From 2c395e6819efdbca9c76c3d7182c8d4f91908be4 Mon Sep 17 00:00:00 2001 From: SaschaNaz Date: Thu, 8 Oct 2015 02:48:10 +0900 Subject: [PATCH] trimWhitespacesInEmptyLineTrivia --- src/services/formatting/formatting.ts | 51 +++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 4a7033c6f3e..08a84c83483 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -121,7 +121,7 @@ namespace ts.formatting { function findOutermostParent(position: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node { let precedingToken = findPrecedingToken(position, sourceFile); - + // when it is claimed that trigger character was typed at given position // we verify that there is a token with a matching kind whose end is equal to position (because the character was just typed). // If this condition is not hold - then trigger character was typed in some other context, @@ -151,7 +151,7 @@ namespace ts.formatting { return current; } - + // Returns true if node is a element in some list in parent // i.e. parent is class declaration with the list of members and node is one of members. function isListElement(parent: Node, node: Node): boolean { @@ -198,7 +198,7 @@ namespace ts.formatting { if (!errors.length) { return rangeHasNoErrors; } - + // pick only errors that fall in range let sorted = errors .filter(d => rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length)) @@ -340,6 +340,12 @@ namespace ts.formatting { let delta = getOwnOrInheritedDelta(enclosingNode, options, sourceFile); processNode(enclosingNode, enclosingNode, startLine, undecoratedStartLine, initialIndentation, delta); } + else { + let leadingTrivia = formattingScanner.readTokenInfo(undefined).leadingTrivia; + if (leadingTrivia) { + trimWhitespacesInEmptyLineTrivia(leadingTrivia, true); + } + } formattingScanner.close(); @@ -445,7 +451,7 @@ namespace ts.formatting { if ((node).asteriskToken) { return SyntaxKind.AsteriskToken; } - // fall-through + // fall-through case SyntaxKind.PropertyDeclaration: case SyntaxKind.Parameter: @@ -555,6 +561,13 @@ namespace ts.formatting { consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation); } + if (!formattingScanner.isOnToken()) { + let leadingTrivia = formattingScanner.readTokenInfo(node).leadingTrivia; + if (leadingTrivia) { + trimWhitespacesInEmptyLineTrivia(leadingTrivia, true); + } + } + function processChildNode( child: Node, inheritedIndentation: number, @@ -686,6 +699,7 @@ namespace ts.formatting { let indentToken = false; if (currentTokenInfo.leadingTrivia) { + trimWhitespacesInEmptyLineTrivia(currentTokenInfo.leadingTrivia, formattingScanner.lastTrailingTriviaWasNewLine()); processTrivia(currentTokenInfo.leadingTrivia, parent, childContextNode, dynamicIndentation); } @@ -838,8 +852,8 @@ namespace ts.formatting { // We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line trimTrailingWhitespaces = - (rule.Operation.Action & (RuleAction.NewLine | RuleAction.Space)) && - rule.Flag !== RuleFlags.CanDeleteNewLines; + (rule.Operation.Action & (RuleAction.NewLine | RuleAction.Space)) && + rule.Flag !== RuleFlags.CanDeleteNewLines; } else { trimTrailingWhitespaces = true; @@ -949,6 +963,31 @@ namespace ts.formatting { } } + function trimWhitespacesInEmptyLineTrivia(trivia: TextRangeWithKind[], lastTraviaWasNewLine: boolean) { + let targetCandidate: TextRangeWithKind; + + for (let triviaItem of trivia) { + switch (triviaItem.kind) { + case SyntaxKind.WhitespaceTrivia: + targetCandidate = lastTraviaWasNewLine ? triviaItem : undefined; + break; + case SyntaxKind.NewLineTrivia: + if (targetCandidate) { + recordDelete(targetCandidate.pos, targetCandidate.end - targetCandidate.pos); + targetCandidate = undefined; + } + break; + default: + targetCandidate = undefined; + break; + } + lastTraviaWasNewLine = triviaItem.kind === SyntaxKind.NewLineTrivia; + } + if (targetCandidate && targetCandidate.end === sourceFile.end) { + recordDelete(targetCandidate.pos, targetCandidate.end - targetCandidate.pos); + } + } + function newTextChange(start: number, len: number, newText: string): TextChange { return { span: createTextSpan(start, len), newText } }