提交 73b78b70 编写于 作者: M Martin Aeschlimann

Move jsonFormatter to base

上级 399a12f3
......@@ -4,43 +4,71 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import strings = require('vs/base/common/strings');
import Json = require('vs/base/common/json');
import EditorCommon = require('vs/editor/common/editorCommon');
import Modes = require('vs/editor/common/modes');
export function format(model: EditorCommon.IMirrorModel, range: EditorCommon.IRange, options: Modes.IFormattingOptions): EditorCommon.ISingleEditOperation[] {
var initialIndentLevel: number;
var value: string;
var rangeOffset: number;
import Json = require('./json');
export interface FormattingOptions {
/**
* If indentation is based on spaces (`insertSpaces` = true), then what is the number of spaces that make an indent?
*/
tabSize: number;
/**
* Is indentation based on spaces?
*/
insertSpaces: boolean;
/**
* The default end of line line character
*/
eol: string;
}
export interface Edit {
offset: number;
length: number;
content: string;
}
export function format(documentText: string, range: { offset: number, length: number}, options: FormattingOptions): Edit[] {
let initialIndentLevel: number;
let value: string;
let rangeStart: number;
let rangeEnd: number;
if (range) {
range = { startLineNumber: range.startLineNumber, startColumn: 1, endLineNumber: range.endLineNumber, endColumn: model.getLineMaxColumn(range.endLineNumber) }; // extend to full range
initialIndentLevel = computeIndentLevel(model.getLineContent(range.startLineNumber), options);
value = model.getValueInRange(range);
rangeOffset = model.getOffsetFromPosition({ lineNumber: range.startLineNumber, column: range.startColumn });
rangeStart = range.offset;
rangeEnd = rangeStart + range.length;
while (rangeStart > 0 && !isEOL(documentText, rangeStart - 1)) {
rangeStart--;
}
let scanner = Json.createScanner(documentText, true);
scanner.setPosition(rangeEnd);
scanner.scan();
rangeEnd = scanner.getPosition();
value = documentText.substring(rangeStart, rangeEnd);
initialIndentLevel = computeIndentLevel(value, 0, options);
} else {
range = model.getFullModelRange();
value = documentText;
rangeStart = 0;
rangeEnd = documentText.length;
initialIndentLevel = 0;
value = model.getValue();
rangeOffset = 0;
}
let eol = getEOL(options, documentText);
var lineBreak = false;
var indentLevel = 0;
var indentValue: string;
let lineBreak = false;
let indentLevel = 0;
let indentValue: string;
if (options.insertSpaces) {
indentValue = strings.repeat(' ', options.tabSize);
indentValue = repeat(' ', options.tabSize);
} else {
indentValue = '\t';
}
var scanner = Json.createScanner(value, false);
let scanner = Json.createScanner(value, false);
function newLineAndIndent(): string {
return model.getEOL() + strings.repeat(indentValue, initialIndentLevel + indentLevel);
return eol + repeat(indentValue, initialIndentLevel + indentLevel);
}
function scanNext(): Json.SyntaxKind {
var token = scanner.scan();
let token = scanner.scan();
lineBreak = false;
while (token === Json.SyntaxKind.Trivia || token === Json.SyntaxKind.LineBreakTrivia) {
lineBreak = lineBreak || (token === Json.SyntaxKind.LineBreakTrivia);
......@@ -48,33 +76,34 @@ export function format(model: EditorCommon.IMirrorModel, range: EditorCommon.IRa
}
return token;
}
var editOperations: EditorCommon.ISingleEditOperation[] = [];
function addEdit(text: string, range: EditorCommon.IRange) {
if (model.getValueInRange(range) !== text) {
editOperations.push({ range: range, text: text });
let editOperations: Edit[] = [];
function addEdit(text: string, startOffset: number, endOffset: number) {
if (documentText.substring(startOffset, endOffset) !== text) {
editOperations.push({ offset: startOffset, length: endOffset - startOffset, content: text });
}
}
var firstToken = scanNext();
let firstToken = scanNext();
if (firstToken !== Json.SyntaxKind.EOF) {
var firstTokenStart = model.getPositionFromOffset(scanner.getTokenOffset() + rangeOffset);
var initialIndent = strings.repeat(indentValue, initialIndentLevel);
addEdit(initialIndent, { startLineNumber: range.startLineNumber, startColumn: range.startColumn, endLineNumber: firstTokenStart.lineNumber, endColumn: firstTokenStart.column });
let firstTokenStart = scanner.getTokenOffset() + rangeStart;
let initialIndent = repeat(indentValue, initialIndentLevel);
addEdit(initialIndent, rangeStart, firstTokenStart);
}
while (firstToken !== Json.SyntaxKind.EOF) {
var firstTokenEnd = model.getPositionFromOffset(scanner.getTokenOffset() + scanner.getTokenLength() + rangeOffset);
var secondToken = scanNext();
let firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + rangeStart;
let secondToken = scanNext();
let replaceContent = '';
while (!lineBreak && (secondToken === Json.SyntaxKind.LineCommentTrivia || secondToken === Json.SyntaxKind.BlockCommentTrivia)) {
// comments on the same line: keep them on the same line, but ignore them otherwise
var commentTokenStart = model.getPositionFromOffset(scanner.getTokenOffset() + rangeOffset);
addEdit(' ', { startLineNumber: firstTokenEnd.lineNumber, startColumn: firstTokenEnd.column, endLineNumber: commentTokenStart.lineNumber, endColumn: commentTokenStart.column });
firstTokenEnd = model.getPositionFromOffset(scanner.getTokenOffset() + scanner.getTokenLength() + rangeOffset);
let commentTokenStart = scanner.getTokenOffset() + rangeStart;
addEdit(' ', firstTokenEnd, commentTokenStart);
firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + rangeStart;
replaceContent = secondToken === Json.SyntaxKind.LineCommentTrivia ? newLineAndIndent() : '';
secondToken = scanNext();
}
if (secondToken === Json.SyntaxKind.CloseBraceToken) {
if (firstToken !== Json.SyntaxKind.OpenBraceToken) {
indentLevel--;
......@@ -85,7 +114,7 @@ export function format(model: EditorCommon.IMirrorModel, range: EditorCommon.IRa
indentLevel--;
replaceContent = newLineAndIndent();
}
} else {
} else if (secondToken !== Json.SyntaxKind.EOF) {
switch (firstToken) {
case Json.SyntaxKind.OpenBracketToken:
case Json.SyntaxKind.OpenBraceToken:
......@@ -121,19 +150,27 @@ export function format(model: EditorCommon.IMirrorModel, range: EditorCommon.IRa
}
}
var secondTokenStart = model.getPositionFromOffset(scanner.getTokenOffset() + rangeOffset);
addEdit(replaceContent, { startLineNumber: firstTokenEnd.lineNumber, startColumn: firstTokenEnd.column, endLineNumber: secondTokenStart.lineNumber, endColumn: secondTokenStart.column });
let secondTokenStart = scanner.getTokenOffset() + rangeStart;
addEdit(replaceContent, firstTokenEnd, secondTokenStart);
firstToken = secondToken;
}
return editOperations;
}
function computeIndentLevel(line: string, options: Modes.IFormattingOptions): number {
var i = 0;
var nChars = 0;
var tabSize = options.tabSize || 4;
while (i < line.length) {
var ch = line.charAt(i);
function repeat(s: string, count: number): string {
let result = '';
for (let i = 0; i < count; i++) {
result += s;
}
return result;
}
function computeIndentLevel(content: string, offset: number, options: FormattingOptions): number {
let i = 0;
let nChars = 0;
let tabSize = options.tabSize || 4;
while (i < content.length) {
let ch = content.charAt(i);
if (ch === ' ') {
nChars++;
} else if (ch === '\t') {
......@@ -144,4 +181,23 @@ function computeIndentLevel(line: string, options: Modes.IFormattingOptions): nu
i++;
}
return Math.floor(nChars / tabSize);
}
function getEOL(options: FormattingOptions, text: string): string {
for (let i = 0; i < text.length; i++) {
let ch = text.charAt(i);
if (ch === '\r') {
if (i + 1 < text.length && text.charAt(i+1) === '\n') {
return '\r\n';
}
return '\r';
} else if (ch === '\n') {
return '\n';
}
}
return (options && options.eol) || '\n';
}
function isEOL(text: string, offset: number) {
return '\r\n'.indexOf(text.charAt(offset)) !== -1;
}
\ No newline at end of file
......@@ -4,46 +4,33 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import EditorCommon = require('vs/editor/common/editorCommon');
import {Range} from 'vs/editor/common/core/range';
import {Model} from 'vs/editor/common/model/model';
import ModesTestUtils = require('vs/editor/test/common/modesTestUtils');
import Formatter = require('vs/languages/json/common/features/jsonFormatter');
import MirrorModel = require('vs/editor/common/model/mirrorModel');
import Formatter = require('vs/base/common/jsonFormatter');
import assert = require('assert');
suite('JSON - formatter', () => {
function format(unformatted: string, expected: string, insertSpaces = true) {
var range : EditorCommon.IRange = null;
var mirrorModel = MirrorModel.createTestMirrorModelFromString(unformatted);
var rangeStart = unformatted.indexOf('|');
var rangeEnd = unformatted.lastIndexOf('|');
function format(content: string, expected: string, insertSpaces = true) {
let range = void 0;
var rangeStart = content.indexOf('|');
var rangeEnd = content.lastIndexOf('|');
if (rangeStart !== -1 && rangeEnd !== -1) {
unformatted = unformatted.substring(0, rangeStart) + unformatted.substring(rangeStart + 1, rangeEnd) + unformatted.substring(rangeEnd + 1);
content = content.substring(0, rangeStart) + content.substring(rangeStart + 1, rangeEnd) + content.substring(rangeEnd + 1);
range = { offset: rangeStart, length: rangeEnd - rangeStart };
}
var edits = Formatter.format(content, range, { tabSize: 2, insertSpaces: insertSpaces, eol: '\n' });
var startPos = mirrorModel.getPositionFromOffset(rangeStart);
var endPos = mirrorModel.getPositionFromOffset(rangeEnd);
range = { startLineNumber: startPos.lineNumber, startColumn: startPos.column, endLineNumber: endPos.lineNumber, endColumn: endPos.column };
mirrorModel = MirrorModel.createTestMirrorModelFromString(unformatted);
let lastEditOffset = content.length;
for (let i = edits.length - 1; i >= 0; i--) {
let edit = edits[i];
assert(edit.offset >= 0 && edit.length >= 0 && edit.offset + edit.length <= content.length)
assert(typeof edit.content === 'string');
assert(lastEditOffset >= edit.offset + edit.length); // make sure all edits are ordered
lastEditOffset = edit.offset;
content = content.substring(0, edit.offset) + edit.content + content.substring(edit.offset + edit.length);
}
var operations = Formatter.format(mirrorModel, range, { tabSize: 2, insertSpaces: insertSpaces });
var model = new Model(unformatted, Model.DEFAULT_CREATION_OPTIONS, null);
model.pushEditOperations([], operations.map(o => {
return {
range: Range.lift(o.range),
text: o.text,
identifier: null,
forceMoveMarkers: false
};
}), () => []);
var newContent = model.getValue(EditorCommon.EndOfLinePreference.LF);
assert.equal(newContent, expected);
model.dispose();
assert.equal(content, expected);
}
test('object - single property', () => {
......
......@@ -10,7 +10,7 @@ import EditorCommon = require('vs/editor/common/editorCommon');
import Modes = require('vs/editor/common/modes');
import HtmlContent = require('vs/base/common/htmlContent');
import Parser = require('./parser/jsonParser');
import JSONFormatter = require('vs/languages/json/common/features/jsonFormatter');
import JSONFormatter = require('vs/base/common/jsonFormatter');
import SchemaService = require('./jsonSchemaService');
import JSONSchema = require('vs/base/common/jsonSchema');
import JSONIntellisense = require('./jsonIntellisense');
......@@ -412,8 +412,11 @@ export class JSONWorker {
}
public format(resource: URI, range: EditorCommon.IRange, options: Modes.IFormattingOptions): WinJS.TPromise<EditorCommon.ISingleEditOperation[]> {
var model = this.resourceService.get(resource);
return WinJS.TPromise.as(JSONFormatter.format(model, range, options));
let model = this.resourceService.get(resource);
let formatRange = range ? model.getOffsetAndLengthFromRange(range) : void 0;
let edits = JSONFormatter.format(model.getValue(), formatRange, { insertSpaces: options.insertSpaces, tabSize: options.tabSize, eol: model.getEOL() });
let operations = edits.map(e => ({ range: model.getRangeFromOffsetAndLength(e.offset, e.length), text: e.content }));
return WinJS.TPromise.as(operations);
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册