alm
Version:
The best IDE for TypeScript
191 lines (190 loc) • 7.7 kB
JavaScript
/**
* From https://raw.githubusercontent.com/Microsoft/vscode-json-languageservice/master/src/services/jsonFormatter.ts
* - Redirected dependencies
* - Made `getEol` use editorconfig ;)
*/
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
Object.defineProperty(exports, "__esModule", { value: true });
var Json = require("../core/jsonc-parser");
var Position = monaco.Position;
var Range = monaco.Range;
/**
* BAS: Was simple so I wrote it :)
*/
var TextEditReplace;
(function (TextEditReplace) {
function replace(range, text) {
var result = {
range: range,
text: text
};
return result;
}
TextEditReplace.replace = replace;
})(TextEditReplace || (TextEditReplace = {}));
function format(document, range, options) {
var documentText = document.getValue();
var initialIndentLevel;
var value;
var rangeOffset;
if (range) {
var startPosition = new Position(range.startLineNumber, 0);
rangeOffset = document.getOffsetAt(startPosition);
var endOffset = document.getOffsetAt(new Position(range.endLineNumber + 1, 0));
var endLineStart = document.getOffsetAt(new Position(range.endLineNumber, 0));
while (endOffset > endLineStart && isEOL(documentText, endOffset - 1)) {
endOffset--;
}
var endPosition = document.getPositionAt(endOffset);
range = new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);
value = documentText.substring(rangeOffset, endOffset);
initialIndentLevel = computeIndentLevel(value, 0, options);
}
else {
value = documentText;
var endPosition = document.getPositionAt(value.length);
range = new Range(0, 0, endPosition.lineNumber, endPosition.column);
initialIndentLevel = 0;
rangeOffset = 0;
}
var eol = getEOL(document);
var lineBreak = false;
var indentLevel = 0;
var indentValue;
if (options.insertSpaces) {
indentValue = repeat(' ', options.tabSize);
}
else {
indentValue = '\t';
}
var scanner = Json.createScanner(value, false);
function newLineAndIndent() {
return eol + repeat(indentValue, initialIndentLevel + indentLevel);
}
function scanNext() {
var token = scanner.scan();
lineBreak = false;
while (token === Json.SyntaxKind.Trivia || token === Json.SyntaxKind.LineBreakTrivia) {
lineBreak = lineBreak || (token === Json.SyntaxKind.LineBreakTrivia);
token = scanner.scan();
}
return token;
}
var editOperations = [];
function addEdit(text, startOffset, endOffset) {
if (documentText.substring(startOffset, endOffset) !== text) {
var startPos = document.getPositionAt(startOffset);
var endPos = document.getPositionAt(endOffset);
var replaceRange = new Range(startPos.lineNumber, startPos.column, endPos.lineNumber, endPos.column);
editOperations.push(TextEditReplace.replace(replaceRange, text));
}
}
var firstToken = scanNext();
if (firstToken !== Json.SyntaxKind.EOF) {
var firstTokenStart = scanner.getTokenOffset() + rangeOffset;
var initialIndent = repeat(indentValue, initialIndentLevel);
addEdit(initialIndent, rangeOffset, firstTokenStart);
}
while (firstToken !== Json.SyntaxKind.EOF) {
var firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + rangeOffset;
var secondToken = scanNext();
var 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 = scanner.getTokenOffset() + rangeOffset;
addEdit(' ', firstTokenEnd, commentTokenStart);
firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + rangeOffset;
replaceContent = secondToken === Json.SyntaxKind.LineCommentTrivia ? newLineAndIndent() : '';
secondToken = scanNext();
}
if (secondToken === Json.SyntaxKind.CloseBraceToken) {
if (firstToken !== Json.SyntaxKind.OpenBraceToken) {
indentLevel--;
replaceContent = newLineAndIndent();
}
}
else if (secondToken === Json.SyntaxKind.CloseBracketToken) {
if (firstToken !== Json.SyntaxKind.OpenBracketToken) {
indentLevel--;
replaceContent = newLineAndIndent();
}
}
else {
switch (firstToken) {
case Json.SyntaxKind.OpenBracketToken:
case Json.SyntaxKind.OpenBraceToken:
indentLevel++;
replaceContent = newLineAndIndent();
break;
case Json.SyntaxKind.CommaToken:
case Json.SyntaxKind.LineCommentTrivia:
replaceContent = newLineAndIndent();
break;
case Json.SyntaxKind.BlockCommentTrivia:
if (lineBreak) {
replaceContent = newLineAndIndent();
}
else {
// symbol following comment on the same line: keep on same line, separate with ' '
replaceContent = ' ';
}
break;
case Json.SyntaxKind.ColonToken:
replaceContent = ' ';
break;
case Json.SyntaxKind.NullKeyword:
case Json.SyntaxKind.TrueKeyword:
case Json.SyntaxKind.FalseKeyword:
case Json.SyntaxKind.NumericLiteral:
if (secondToken === Json.SyntaxKind.NullKeyword || secondToken === Json.SyntaxKind.FalseKeyword || secondToken === Json.SyntaxKind.NumericLiteral) {
replaceContent = ' ';
}
break;
}
if (lineBreak && (secondToken === Json.SyntaxKind.LineCommentTrivia || secondToken === Json.SyntaxKind.BlockCommentTrivia)) {
replaceContent = newLineAndIndent();
}
}
var secondTokenStart = scanner.getTokenOffset() + rangeOffset;
addEdit(replaceContent, firstTokenEnd, secondTokenStart);
firstToken = secondToken;
}
return editOperations;
}
exports.format = format;
function repeat(s, count) {
var result = '';
for (var i = 0; i < count; i++) {
result += s;
}
return result;
}
function computeIndentLevel(content, offset, options) {
var i = 0;
var nChars = 0;
var tabSize = options.tabSize || 4;
while (i < content.length) {
var ch = content.charAt(i);
if (ch === ' ') {
nChars++;
}
else if (ch === '\t') {
nChars += tabSize;
}
else {
break;
}
i++;
}
return Math.floor(nChars / tabSize);
}
function getEOL(document) {
return document._editorOptions.newLineCharacter;
}
function isEOL(text, offset) {
return '\r\n'.indexOf(text.charAt(offset)) !== -1;
}