You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							205 lines
						
					
					
						
							7.8 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							205 lines
						
					
					
						
							7.8 KiB
						
					
					
				
								/*---------------------------------------------------------------------------------------------
							 | 
						|
								 *  Copyright (c) Microsoft Corporation. All rights reserved.
							 | 
						|
								 *  Licensed under the MIT License. See License.txt in the project root for license information.
							 | 
						|
								 *--------------------------------------------------------------------------------------------*/
							 | 
						|
								'use strict';
							 | 
						|
								import { createScanner } from './scanner';
							 | 
						|
								export function format(documentText, range, options) {
							 | 
						|
								    var initialIndentLevel;
							 | 
						|
								    var formatText;
							 | 
						|
								    var formatTextStart;
							 | 
						|
								    var rangeStart;
							 | 
						|
								    var rangeEnd;
							 | 
						|
								    if (range) {
							 | 
						|
								        rangeStart = range.offset;
							 | 
						|
								        rangeEnd = rangeStart + range.length;
							 | 
						|
								        formatTextStart = rangeStart;
							 | 
						|
								        while (formatTextStart > 0 && !isEOL(documentText, formatTextStart - 1)) {
							 | 
						|
								            formatTextStart--;
							 | 
						|
								        }
							 | 
						|
								        var endOffset = rangeEnd;
							 | 
						|
								        while (endOffset < documentText.length && !isEOL(documentText, endOffset)) {
							 | 
						|
								            endOffset++;
							 | 
						|
								        }
							 | 
						|
								        formatText = documentText.substring(formatTextStart, endOffset);
							 | 
						|
								        initialIndentLevel = computeIndentLevel(formatText, options);
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								        formatText = documentText;
							 | 
						|
								        initialIndentLevel = 0;
							 | 
						|
								        formatTextStart = 0;
							 | 
						|
								        rangeStart = 0;
							 | 
						|
								        rangeEnd = documentText.length;
							 | 
						|
								    }
							 | 
						|
								    var eol = getEOL(options, documentText);
							 | 
						|
								    var lineBreak = false;
							 | 
						|
								    var indentLevel = 0;
							 | 
						|
								    var indentValue;
							 | 
						|
								    if (options.insertSpaces) {
							 | 
						|
								        indentValue = repeat(' ', options.tabSize || 4);
							 | 
						|
								    }
							 | 
						|
								    else {
							 | 
						|
								        indentValue = '\t';
							 | 
						|
								    }
							 | 
						|
								    var scanner = createScanner(formatText, false);
							 | 
						|
								    var hasError = false;
							 | 
						|
								    function newLineAndIndent() {
							 | 
						|
								        return eol + repeat(indentValue, initialIndentLevel + indentLevel);
							 | 
						|
								    }
							 | 
						|
								    function scanNext() {
							 | 
						|
								        var token = scanner.scan();
							 | 
						|
								        lineBreak = false;
							 | 
						|
								        while (token === 15 /* Trivia */ || token === 14 /* LineBreakTrivia */) {
							 | 
						|
								            lineBreak = lineBreak || (token === 14 /* LineBreakTrivia */);
							 | 
						|
								            token = scanner.scan();
							 | 
						|
								        }
							 | 
						|
								        hasError = token === 16 /* Unknown */ || scanner.getTokenError() !== 0 /* None */;
							 | 
						|
								        return token;
							 | 
						|
								    }
							 | 
						|
								    var editOperations = [];
							 | 
						|
								    function addEdit(text, startOffset, endOffset) {
							 | 
						|
								        if (!hasError && (!range || (startOffset < rangeEnd && endOffset > rangeStart)) && documentText.substring(startOffset, endOffset) !== text) {
							 | 
						|
								            editOperations.push({ offset: startOffset, length: endOffset - startOffset, content: text });
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								    var firstToken = scanNext();
							 | 
						|
								    if (firstToken !== 17 /* EOF */) {
							 | 
						|
								        var firstTokenStart = scanner.getTokenOffset() + formatTextStart;
							 | 
						|
								        var initialIndent = repeat(indentValue, initialIndentLevel);
							 | 
						|
								        addEdit(initialIndent, formatTextStart, firstTokenStart);
							 | 
						|
								    }
							 | 
						|
								    while (firstToken !== 17 /* EOF */) {
							 | 
						|
								        var firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
							 | 
						|
								        var secondToken = scanNext();
							 | 
						|
								        var replaceContent = '';
							 | 
						|
								        var needsLineBreak = false;
							 | 
						|
								        while (!lineBreak && (secondToken === 12 /* LineCommentTrivia */ || secondToken === 13 /* BlockCommentTrivia */)) {
							 | 
						|
								            // comments on the same line: keep them on the same line, but ignore them otherwise
							 | 
						|
								            var commentTokenStart = scanner.getTokenOffset() + formatTextStart;
							 | 
						|
								            addEdit(' ', firstTokenEnd, commentTokenStart);
							 | 
						|
								            firstTokenEnd = scanner.getTokenOffset() + scanner.getTokenLength() + formatTextStart;
							 | 
						|
								            needsLineBreak = secondToken === 12 /* LineCommentTrivia */;
							 | 
						|
								            replaceContent = needsLineBreak ? newLineAndIndent() : '';
							 | 
						|
								            secondToken = scanNext();
							 | 
						|
								        }
							 | 
						|
								        if (secondToken === 2 /* CloseBraceToken */) {
							 | 
						|
								            if (firstToken !== 1 /* OpenBraceToken */) {
							 | 
						|
								                indentLevel--;
							 | 
						|
								                replaceContent = newLineAndIndent();
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        else if (secondToken === 4 /* CloseBracketToken */) {
							 | 
						|
								            if (firstToken !== 3 /* OpenBracketToken */) {
							 | 
						|
								                indentLevel--;
							 | 
						|
								                replaceContent = newLineAndIndent();
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        else {
							 | 
						|
								            switch (firstToken) {
							 | 
						|
								                case 3 /* OpenBracketToken */:
							 | 
						|
								                case 1 /* OpenBraceToken */:
							 | 
						|
								                    indentLevel++;
							 | 
						|
								                    replaceContent = newLineAndIndent();
							 | 
						|
								                    break;
							 | 
						|
								                case 5 /* CommaToken */:
							 | 
						|
								                case 12 /* LineCommentTrivia */:
							 | 
						|
								                    replaceContent = newLineAndIndent();
							 | 
						|
								                    break;
							 | 
						|
								                case 13 /* BlockCommentTrivia */:
							 | 
						|
								                    if (lineBreak) {
							 | 
						|
								                        replaceContent = newLineAndIndent();
							 | 
						|
								                    }
							 | 
						|
								                    else if (!needsLineBreak) {
							 | 
						|
								                        // symbol following comment on the same line: keep on same line, separate with ' '
							 | 
						|
								                        replaceContent = ' ';
							 | 
						|
								                    }
							 | 
						|
								                    break;
							 | 
						|
								                case 6 /* ColonToken */:
							 | 
						|
								                    if (!needsLineBreak) {
							 | 
						|
								                        replaceContent = ' ';
							 | 
						|
								                    }
							 | 
						|
								                    break;
							 | 
						|
								                case 10 /* StringLiteral */:
							 | 
						|
								                    if (secondToken === 6 /* ColonToken */) {
							 | 
						|
								                        if (!needsLineBreak) {
							 | 
						|
								                            replaceContent = '';
							 | 
						|
								                        }
							 | 
						|
								                        break;
							 | 
						|
								                    }
							 | 
						|
								                // fall through
							 | 
						|
								                case 7 /* NullKeyword */:
							 | 
						|
								                case 8 /* TrueKeyword */:
							 | 
						|
								                case 9 /* FalseKeyword */:
							 | 
						|
								                case 11 /* NumericLiteral */:
							 | 
						|
								                case 2 /* CloseBraceToken */:
							 | 
						|
								                case 4 /* CloseBracketToken */:
							 | 
						|
								                    if (secondToken === 12 /* LineCommentTrivia */ || secondToken === 13 /* BlockCommentTrivia */) {
							 | 
						|
								                        if (!needsLineBreak) {
							 | 
						|
								                            replaceContent = ' ';
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								                    else if (secondToken !== 5 /* CommaToken */ && secondToken !== 17 /* EOF */) {
							 | 
						|
								                        hasError = true;
							 | 
						|
								                    }
							 | 
						|
								                    break;
							 | 
						|
								                case 16 /* Unknown */:
							 | 
						|
								                    hasError = true;
							 | 
						|
								                    break;
							 | 
						|
								            }
							 | 
						|
								            if (lineBreak && (secondToken === 12 /* LineCommentTrivia */ || secondToken === 13 /* BlockCommentTrivia */)) {
							 | 
						|
								                replaceContent = newLineAndIndent();
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        if (secondToken === 17 /* EOF */) {
							 | 
						|
								            replaceContent = options.insertFinalNewline ? eol : '';
							 | 
						|
								        }
							 | 
						|
								        var secondTokenStart = scanner.getTokenOffset() + formatTextStart;
							 | 
						|
								        addEdit(replaceContent, firstTokenEnd, secondTokenStart);
							 | 
						|
								        firstToken = secondToken;
							 | 
						|
								    }
							 | 
						|
								    return editOperations;
							 | 
						|
								}
							 | 
						|
								function repeat(s, count) {
							 | 
						|
								    var result = '';
							 | 
						|
								    for (var i = 0; i < count; i++) {
							 | 
						|
								        result += s;
							 | 
						|
								    }
							 | 
						|
								    return result;
							 | 
						|
								}
							 | 
						|
								function computeIndentLevel(content, 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(options, text) {
							 | 
						|
								    for (var i = 0; i < text.length; i++) {
							 | 
						|
								        var 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';
							 | 
						|
								}
							 | 
						|
								export function isEOL(text, offset) {
							 | 
						|
								    return '\r\n'.indexOf(text.charAt(offset)) !== -1;
							 | 
						|
								}
							 |