diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6e01a7b2e36..fdb49d8dfdd 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -549,7 +549,7 @@ module ts { export interface SourceFile extends Block { filename: string; text: string; - getLineAndCharacterFromPosition(position: number): { line: number; character: number }; + getLineAndCharacterFromPosition(position: number): LineAndCharacter; getPositionFromLineAndCharacter(line: number, character: number): number; getLineStarts(): number[]; amdDependencies: string[]; diff --git a/src/services/formatting/format.ts b/src/services/formatting/format.ts index ef5315703f6..9831921e874 100644 --- a/src/services/formatting/format.ts +++ b/src/services/formatting/format.ts @@ -121,7 +121,12 @@ module ts.formatting { sourceFile: SourceFile, options: FormatCodeOptions, rulesProvider: RulesProvider, - requestKind: FormattingRequestKind): TextChange[] { + requestKind: FormattingRequestKind): TextChange[]{ + + var syntacticErrors = sourceFile.syntacticErrors.length !== 0 && sourceFile.syntacticErrors.slice(0); + if (syntacticErrors) { + syntacticErrors.sort((d1, d2) => d1.start - d2.start); + } // formatting context to be used by rules provider to get rules var formattingContext = new FormattingContext(sourceFile, requestKind); @@ -131,6 +136,7 @@ module ts.formatting { var formattingScanner = getFormattingScanner(sourceFile, enclosingNode, originalRange); + var previousRangeHasError: boolean; var previousRange: TextRangeWithKind; var previousParent: Node; var previousRangeStartLine: number; @@ -144,6 +150,9 @@ module ts.formatting { var startLine = sourceFile.getLineAndCharacterFromPosition(enclosingNode.getStart(sourceFile)).line; processNode(enclosingNode, enclosingNode, startLine, initialIndentation); } + + formattingScanner.close(); + return edits; function getIndentationDelta(node: Node, lineAdded: boolean): number { @@ -238,7 +247,6 @@ module ts.formatting { // determine child indentation // TODO: share this code with SmartIndenter - // NOTE: SI uses non-adjusted lines var increaseIndentation = childStartLine !== nodeStartLine && !SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(node, child, childStartLine, sourceFile) && @@ -254,6 +262,14 @@ module ts.formatting { } } + function rangeContainsError(range: TextRange): boolean { + if (!syntacticErrors.length) { + return false; + } + + binarySearch + } + function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, contextNode: Node, indentation: DynamicIndentation): void { Debug.assert(rangeContainsRange(parent, currentTokenInfo.token)); @@ -266,13 +282,14 @@ module ts.formatting { var lineAdded: boolean; var isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token); var indentToken: boolean = true; + if (isTokenInRange) { var prevStartLine = previousRangeStartLine; var tokenStart = sourceFile.getLineAndCharacterFromPosition(currentTokenInfo.token.pos); lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, contextNode, indentation); if (lineAdded !== undefined) { indentToken = lineAdded; - } + } else { indentToken = tokenStart.line !== prevStartLine; } @@ -329,20 +346,23 @@ module ts.formatting { } function processRange(range: TextRangeWithKind, rangeStart: LineAndCharacter, parent: Node, contextNode: Node, indentation: DynamicIndentation): boolean { - + var rangeHasError = rangeContainsError(range); var lineAdded: boolean; - if (!previousRange) { - // trim whitespaces starting from the beginning of the span up to the current line - var originalStart = sourceFile.getLineAndCharacterFromPosition(originalRange.pos); - trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line); - } - else { - lineAdded = processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, indentation) + if (!rangeHasError && !previousRangeHasError) { + if (!previousRange) { + // trim whitespaces starting from the beginning of the span up to the current line + var originalStart = sourceFile.getLineAndCharacterFromPosition(originalRange.pos); + trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line); + } + else { + lineAdded = processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, indentation) + } } previousRange = range; previousParent = parent; previousRangeStartLine = rangeStart.line; + previousRangeHasError = rangeHasError; return lineAdded; } diff --git a/src/services/formatting/formattingScanner.ts b/src/services/formatting/formattingScanner.ts index a4b574bdb8a..3728ebeb417 100644 --- a/src/services/formatting/formattingScanner.ts +++ b/src/services/formatting/formattingScanner.ts @@ -6,6 +6,7 @@ module ts.formatting { isOnToken(): boolean; readTokenInfo(n: Node): TokenInfo; lastTrailingTriviaWasNewLine(): boolean; + close(): void; } export function getFormattingScanner(sourceFile: SourceFile, enclosingNode: Node, range: TextRange): FormattingScanner { @@ -23,7 +24,8 @@ module ts.formatting { advance: advance, readTokenInfo: readTokenInfo, isOnToken: isOnToken, - lastTrailingTriviaWasNewLine: lastTrailingTriviaWasNewLine + lastTrailingTriviaWasNewLine: lastTrailingTriviaWasNewLine, + close: () => scanner.setText(undefined) }