From 8d1cfbdf1aadf54313151f1d680cc92b418f9067 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 30 May 2017 02:34:34 +0900 Subject: [PATCH 1/7] use last line indentation on formatter ... and add explicit delta suppressor for list end tokens --- src/services/formatting/formatting.ts | 57 +++++++++++++++++++++------ 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 531b768f6d80f..7635e2601107c 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -31,7 +31,7 @@ namespace ts.formatting { * the first token in line so it should be indented */ interface DynamicIndentation { - getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind, container: Node): number; + getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind, container: Node, suppressDelta: boolean): number; getIndentationForComment(owningToken: SyntaxKind, tokenIndentation: number, container: Node): number; /** * Indentation for open and close tokens of the node if it is block or another node that needs special indentation @@ -369,7 +369,7 @@ namespace ts.formatting { let previousRangeStartLine: number; let lastIndentedLine: number; - let indentationOnLastIndentedLine: number; + let indentationOnLastIndentedLine = Constants.Unknown; const edits: TextChange[] = []; @@ -506,7 +506,7 @@ namespace ts.formatting { } return tokenIndentation !== Constants.Unknown ? tokenIndentation : indentation; }, - getIndentationForToken: (line, kind, container) => { + getIndentationForToken: (line, kind, container, suppressDelta) => { if (nodeStartLine !== line && node.decorators) { if (kind === getFirstNonDecoratorTokenOfNode(node)) { // if this token is the first token following the list of decorators, we do not need to indent @@ -517,7 +517,6 @@ namespace ts.formatting { // open and close brace, 'else' and 'while' (in do statement) tokens has indentation of the parent case SyntaxKind.OpenBraceToken: case SyntaxKind.CloseBraceToken: - case SyntaxKind.OpenParenToken: case SyntaxKind.CloseParenToken: case SyntaxKind.ElseKeyword: case SyntaxKind.WhileKeyword: @@ -541,8 +540,23 @@ namespace ts.formatting { break; } } - // if token line equals to the line of containing node (this is a first token in the node) - use node indentation - return nodeStartLine !== line ? indentation + getEffectiveDelta(delta, container) : indentation; + if (suppressDelta) { + // if list end token is LessThanToken '>' then its delta should be explicitly suppressed + // so that LessThanToken as a binary operator can still be indented. + // foo.then + // < + // number, + // string, + // >(); + // vs + // var a = xValue + // > yValue; + return indentation; + } + else { + // if token line equals to the line of containing node (this is a first token in the node) - use node indentation + return nodeStartLine !== line ? indentation + getEffectiveDelta(delta, container) : indentation; + } }, getIndentation: () => indentation, getDelta: child => getEffectiveDelta(delta, child), @@ -700,6 +714,7 @@ namespace ts.formatting { let listDynamicIndentation = parentDynamicIndentation; let startLine = parentStartLine; + let indentationOnListStartToken = parentDynamicIndentation.getIndentation(); if (listStartToken !== SyntaxKind.Unknown) { // introduce a new indentation scope for lists (including list start and end tokens) @@ -712,11 +727,22 @@ namespace ts.formatting { else if (tokenInfo.token.kind === listStartToken) { // consume list start token startLine = sourceFile.getLineAndCharacterOfPosition(tokenInfo.token.pos).line; - const indentation = - computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, parentStartLine); - listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta); - consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent); + consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation, parent); + + if (indentationOnLastIndentedLine !== Constants.Unknown) { + // scanner just processed list start token so consider last indentation as list indentation + // function foo(): { // last indentation was 0, list item will be indented based on this value + // foo: number; + // }: {}; + indentationOnListStartToken = indentationOnLastIndentedLine; + } + else { + const startLinePosition = getLineStartPositionForPosition(tokenInfo.token.pos, sourceFile); + indentationOnListStartToken = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, tokenInfo.token.pos, sourceFile, options); + } + + listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentationOnListStartToken, options.indentSize); } else { // consume any tokens that precede the list as child elements of 'node' using its indentation scope @@ -740,13 +766,13 @@ namespace ts.formatting { // without this check close paren will be interpreted as list end token for function expression which is wrong if (tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) { // consume list end token - consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent); + consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent, /*isListEndToken*/ true); } } } } - function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container: Node): void { + function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container: Node, isListEndToken?: boolean): void { Debug.assert(rangeContainsRange(parent, currentTokenInfo.token)); const lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine(); @@ -787,7 +813,7 @@ namespace ts.formatting { if (indentToken) { const tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) ? - dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container) : + dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container, isListEndToken) : Constants.Unknown; let indentNextTokenOrTrivia = true; @@ -1145,6 +1171,9 @@ namespace ts.formatting { if ((node).typeArguments === list) { return SyntaxKind.LessThanToken; } + break; + case SyntaxKind.TypeLiteral: + return SyntaxKind.OpenBraceToken; } return SyntaxKind.Unknown; @@ -1156,6 +1185,8 @@ namespace ts.formatting { return SyntaxKind.CloseParenToken; case SyntaxKind.LessThanToken: return SyntaxKind.GreaterThanToken; + case SyntaxKind.OpenBraceToken: + return SyntaxKind.CloseBraceToken; } return SyntaxKind.Unknown; From e92711c08563edd78aea3ddf0bd918448b23028c Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 30 May 2017 03:09:07 +0900 Subject: [PATCH 2/7] remove deprecated function --- src/services/formatting/smartIndenter.ts | 52 ------------------------ 1 file changed, 52 deletions(-) diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 18b0479c85a30..018aee2513e9c 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -99,10 +99,6 @@ namespace ts.formatting { if (actualIndentation !== Value.Unknown) { return actualIndentation; } - actualIndentation = getLineIndentationWhenExpressionIsInMultiLine(current, sourceFile, options); - if (actualIndentation !== Value.Unknown) { - return actualIndentation + options.indentSize; - } previous = current; current = current.parent; @@ -163,10 +159,6 @@ namespace ts.formatting { if (actualIndentation !== Value.Unknown) { return actualIndentation + indentationDelta; } - actualIndentation = getLineIndentationWhenExpressionIsInMultiLine(current, sourceFile, options); - if (actualIndentation !== Value.Unknown) { - return actualIndentation + indentationDelta; - } } // increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line @@ -334,50 +326,6 @@ namespace ts.formatting { } } - function getLineIndentationWhenExpressionIsInMultiLine(node: Node, sourceFile: SourceFile, options: EditorSettings): number { - // actual indentation should not be used when: - // - node is close parenthesis - this is the end of the expression - if (node.kind === SyntaxKind.CloseParenToken) { - return Value.Unknown; - } - - if (node.parent && isCallOrNewExpression(node.parent) && (node.parent).expression !== node) { - - const fullCallOrNewExpression = (node.parent).expression; - const startingExpression = getStartingExpression(fullCallOrNewExpression); - - if (fullCallOrNewExpression === startingExpression) { - return Value.Unknown; - } - - const fullCallOrNewExpressionEnd = sourceFile.getLineAndCharacterOfPosition(fullCallOrNewExpression.end); - const startingExpressionEnd = sourceFile.getLineAndCharacterOfPosition(startingExpression.end); - - if (fullCallOrNewExpressionEnd.line === startingExpressionEnd.line) { - return Value.Unknown; - } - - return findColumnForFirstNonWhitespaceCharacterInLine(fullCallOrNewExpressionEnd, sourceFile, options); - } - - return Value.Unknown; - - function getStartingExpression(node: Expression) { - while (true) { - switch (node.kind) { - case SyntaxKind.CallExpression: - case SyntaxKind.NewExpression: - case SyntaxKind.PropertyAccessExpression: - case SyntaxKind.ElementAccessExpression: - node = (node).expression; - break; - default: - return node; - } - } - } - } - function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: EditorSettings): number { Debug.assert(index >= 0 && index < list.length); const node = list[index]; From bfb1bf518e88e2aaef75ce4e47863dc5c7b19f8f Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 30 May 2017 03:11:07 +0900 Subject: [PATCH 3/7] add getListByPosition --- src/services/formatting/smartIndenter.ts | 94 +++++++++++++++--------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 018aee2513e9c..e4949ea406f62 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -272,50 +272,76 @@ namespace ts.formatting { return false; } + function getListIfVisualStartEndIsInListRange(list: NodeArray, start: number, end: number, node: Node) { + return list && rangeContainsVisualStartEnd(list) ? list : undefined; + + // Assumes a list is wrapped by list tokens + function rangeContainsVisualStartEnd(textRange: TextRange): boolean { + const children = node.getChildren(); + for (let i = 0; i < children.length - 1; i++) { + if (children[i].pos === textRange.pos && children[i].end === textRange.end) { + return rangeContainsStartEnd({ pos: children[i - 1].end, end: children[i + 1].end - 1 }, start, end); + } + } + return rangeContainsStartEnd(textRange, start, end); + } + } + function getListIfStartEndIsInListRange(list: NodeArray, start: number, end: number) { return list && rangeContainsStartEnd(list, start, end) ? list : undefined; } export function getContainingList(node: Node, sourceFile: SourceFile): NodeArray { if (node.parent) { - switch (node.parent.kind) { - case SyntaxKind.TypeReference: - return getListIfStartEndIsInListRange((node.parent).typeArguments, node.getStart(sourceFile), node.getEnd()); - case SyntaxKind.ObjectLiteralExpression: - return (node.parent).properties; - case SyntaxKind.ArrayLiteralExpression: - return (node.parent).elements; - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.CallSignature: - case SyntaxKind.Constructor: - case SyntaxKind.ConstructorType: - case SyntaxKind.ConstructSignature: { - const start = node.getStart(sourceFile); - return getListIfStartEndIsInListRange((node.parent).typeParameters, start, node.getEnd()) || - getListIfStartEndIsInListRange((node.parent).parameters, start, node.getEnd()); - } - case SyntaxKind.ClassDeclaration: - return getListIfStartEndIsInListRange((node.parent).typeParameters, node.getStart(sourceFile), node.getEnd()); - case SyntaxKind.NewExpression: - case SyntaxKind.CallExpression: { - const start = node.getStart(sourceFile); - return getListIfStartEndIsInListRange((node.parent).typeArguments, start, node.getEnd()) || - getListIfStartEndIsInListRange((node.parent).arguments, start, node.getEnd()); - } - case SyntaxKind.VariableDeclarationList: - return getListIfStartEndIsInListRange((node.parent).declarations, node.getStart(sourceFile), node.getEnd()); - case SyntaxKind.NamedImports: - case SyntaxKind.NamedExports: - return getListIfStartEndIsInListRange((node.parent).elements, node.getStart(sourceFile), node.getEnd()); - } + return getListByRange(node.getStart(sourceFile), node.getEnd(), node.parent); } return undefined; } + function getListByPosition(pos: number, node: Node): NodeArray { + if (!node) { + return; + } + return getListByRange(pos, pos, node); + } + + function getListByRange(start: number, end: number, node: Node): NodeArray { + switch (node.kind) { + case SyntaxKind.TypeReference: + return getListIfVisualStartEndIsInListRange((node).typeArguments, start, end, node); + case SyntaxKind.ObjectLiteralExpression: + return getListIfVisualStartEndIsInListRange((node).properties, start, end, node); + case SyntaxKind.ArrayLiteralExpression: + return getListIfVisualStartEndIsInListRange((node).elements, start, end, node); + case SyntaxKind.TypeLiteral: + return getListIfVisualStartEndIsInListRange((node).members, start, end, node); + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.Constructor: + case SyntaxKind.ConstructorType: + case SyntaxKind.ConstructSignature: { + return getListIfVisualStartEndIsInListRange((node).typeParameters, start, end, node) || + getListIfVisualStartEndIsInListRange((node).parameters, start, end, node); + } + case SyntaxKind.ClassDeclaration: + return getListIfVisualStartEndIsInListRange((node).typeParameters, start, end, node); + case SyntaxKind.NewExpression: + case SyntaxKind.CallExpression: { + return getListIfVisualStartEndIsInListRange((node).typeArguments, start, end, node) || + getListIfVisualStartEndIsInListRange((node).arguments, start, end, node); + } + case SyntaxKind.VariableDeclarationList: + return getListIfStartEndIsInListRange((node).declarations, start, end); + case SyntaxKind.NamedImports: + case SyntaxKind.NamedExports: + return getListIfVisualStartEndIsInListRange((node).elements, start, end, node); + } + } + function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings): number { const containingList = getContainingList(node, sourceFile); return containingList ? getActualIndentationFromList(containingList) : Value.Unknown; From 0464ee17c16073be60acdfa44fda8a1ab14f6890 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 30 May 2017 03:16:10 +0900 Subject: [PATCH 4/7] indent using list start position before first list item --- src/services/formatting/smartIndenter.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index e4949ea406f62..6889136e77b8d 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -72,6 +72,12 @@ namespace ts.formatting { } } + const containerList = getListByPosition(position, precedingToken.parent); + // use list position if the preceding token is before any list items + if (containerList && !rangeContainsRange(containerList, precedingToken)) { + return getActualIndentationForListStartLine(containerList, sourceFile, options) + options.indentSize; + } + // try to find node that can contribute to indentation and includes 'position' starting from 'precedingToken' // if such node is found - compute initial indentation for 'position' inside this node let previous: Node; @@ -342,6 +348,13 @@ namespace ts.formatting { } } + function getActualIndentationForListStartLine(list: NodeArray, sourceFile: SourceFile, options: EditorSettings): number { + if (!list) { + return Value.Unknown; + } + return findColumnForFirstNonWhitespaceCharacterInLine(sourceFile.getLineAndCharacterOfPosition(list.pos), sourceFile, options); + } + function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings): number { const containingList = getContainingList(node, sourceFile); return containingList ? getActualIndentationFromList(containingList) : Value.Unknown; From 1541096ef81b785e01792ca4fa7d10d67d8695ce Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 30 May 2017 03:21:13 +0900 Subject: [PATCH 5/7] indent using list start position --- src/services/formatting/smartIndenter.ts | 34 ++++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 6889136e77b8d..a4a6f1fe22ed7 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -101,7 +101,10 @@ namespace ts.formatting { } // check if current node is a list item - if yes, take indentation from it - let actualIndentation = getActualIndentationForListItem(current, sourceFile, options); + // do not consider parent-child line sharing yet: + // function foo(a + // | preceding node 'a' does share line with its parent but indentation is expected + const actualIndentation = getActualIndentationForListItem(current, sourceFile, options, /*listIndentsChild*/ true); if (actualIndentation !== Value.Unknown) { return actualIndentation; } @@ -147,21 +150,20 @@ namespace ts.formatting { useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end; } - if (useActualIndentation) { - // check if current node is a list item - if yes, take indentation from it - const actualIndentation = getActualIndentationForListItem(current, sourceFile, options); - if (actualIndentation !== Value.Unknown) { - return actualIndentation + indentationDelta; - } - } parentStart = getParentStart(parent, current, sourceFile); const parentAndChildShareLine = parentStart.line === currentStart.line || childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); if (useActualIndentation) { + // check if current node is a list item - if yes, take indentation from it + let actualIndentation = getActualIndentationForListItem(current, sourceFile, options, !parentAndChildShareLine); + if (actualIndentation !== Value.Unknown) { + return actualIndentation + indentationDelta; + } + // try to fetch actual indentation for current node from source text - let actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options); + actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options); if (actualIndentation !== Value.Unknown) { return actualIndentation + indentationDelta; } @@ -355,9 +357,19 @@ namespace ts.formatting { return findColumnForFirstNonWhitespaceCharacterInLine(sourceFile.getLineAndCharacterOfPosition(list.pos), sourceFile, options); } - function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings): number { + function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings, listIndentsChild: boolean): number { + if (node.parent && node.parent.kind === SyntaxKind.VariableDeclarationList) { + // VariableDeclarationList has no wrapping tokens + return Value.Unknown; + } const containingList = getContainingList(node, sourceFile); - return containingList ? getActualIndentationFromList(containingList) : Value.Unknown; + const result = containingList ? getActualIndentationFromList(containingList) : Value.Unknown; + if (containingList && result === Value.Unknown) { + return getActualIndentationForListStartLine(containingList, sourceFile, options) + (listIndentsChild ? options.indentSize : 0); + } + else { + return result; + } function getActualIndentationFromList(list: Node[]): number { const index = indexOf(list, node); From 92d6566f4fcd1d82ed33c65f95bc357a5d62a458 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 30 May 2017 03:21:26 +0900 Subject: [PATCH 6/7] tests --- .../fourslash/formattingOnChainedCallbacks.ts | 110 +++++++++++++++++- .../fourslash/formattingOnTypeLiteral.ts | 37 ++++++ tests/cases/fourslash/smartIndentOnListEnd.ts | 12 ++ ...rtIndentOnUnclosedFunctionDeclaration04.ts | 17 +-- 4 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 tests/cases/fourslash/formattingOnTypeLiteral.ts create mode 100644 tests/cases/fourslash/smartIndentOnListEnd.ts diff --git a/tests/cases/fourslash/formattingOnChainedCallbacks.ts b/tests/cases/fourslash/formattingOnChainedCallbacks.ts index b8dbc55d8b6cb..5c1eafbbd2450 100644 --- a/tests/cases/fourslash/formattingOnChainedCallbacks.ts +++ b/tests/cases/fourslash/formattingOnChainedCallbacks.ts @@ -20,6 +20,50 @@ //// /*n2*/ //// .then(); +// @Filename: listSmart.ts +////Promise +//// .resolve().then( +//// /*listSmart1*/ +//// 3, +//// /*listSmart2*/ +//// [ +//// 3 +//// /*listSmart3*/ +//// ] +//// /*listSmart4*/ +//// ); + +// @Filename: listZeroIndent.ts +////Promise.resolve([ +////]).then( +//// /*listZeroIndent1*/ +//// [ +//// /*listZeroIndent2*/ +//// 3 +//// ] +//// ); + +// @Filename: listTypeParameter1.ts +////foo.then +//// < +//// /*listTypeParameter1*/ +//// void +//// /*listTypeParameter2*/ +//// >( +//// function (): void { +//// }, +//// function (): void { +//// } +//// ); + +// @Filename: listComment.ts +////Promise +//// .then( +//// // euphonium +//// "k" +//// // oboe +//// ); + goTo.marker('1'); edit.insertLine(''); @@ -49,4 +93,68 @@ verify.currentLineContentIs(' });'); goTo.marker('n1'); verify.indentationIs(8); goTo.marker('n2'); -verify.indentationIs(4); \ No newline at end of file +verify.indentationIs(4); + +goTo.file(1); +format.document(); +verify.currentFileContentIs(`Promise + .resolve().then( + + 3, + + [ + 3 + + ] + + );`); +goTo.marker("listSmart1"); +verify.indentationIs(8); +goTo.marker("listSmart2"); +verify.indentationIs(8); +goTo.marker("listSmart3"); +verify.indentationIs(12); +goTo.marker("listSmart4"); +verify.indentationIs(8); + +goTo.file(2); +format.document(); +verify.currentFileContentIs(`Promise.resolve([ +]).then( + + [ + + 3 + ] +);`); +goTo.marker("listZeroIndent1"); +verify.indentationIs(4); +goTo.marker("listZeroIndent2"); +verify.indentationIs(8); + +goTo.file(3); +format.document(); +verify.currentFileContentIs(`foo.then + < + + void + + >( + function(): void { + }, + function(): void { + } + );`); +goTo.marker("listTypeParameter1"); +verify.indentationIs(8); +goTo.marker("listTypeParameter2"); +verify.indentationIs(8); + +goTo.file(4); +format.document(); +verify.currentFileContentIs(`Promise + .then( + // euphonium + "k" + // oboe + );`) diff --git a/tests/cases/fourslash/formattingOnTypeLiteral.ts b/tests/cases/fourslash/formattingOnTypeLiteral.ts new file mode 100644 index 0000000000000..9b7929a5f5eee --- /dev/null +++ b/tests/cases/fourslash/formattingOnTypeLiteral.ts @@ -0,0 +1,37 @@ +/// + +////function _uniteVertices

( +//// minority: Pinned>, +//// majorityCounter: number, +//// majority: Pinned> +////): { +//// /*start*/ +//// majorityCounter: number; +//// vertecis: Pinned; +//// }>; +//// /*end*/ +//// } { +////} + +format.document(); +verify.currentFileContentIs(`function _uniteVertices

( + minority: Pinned>, + majorityCounter: number, + majority: Pinned> +): { + + majorityCounter: number; + vertecis: Pinned; + }>; + +} { +}`); + +goTo.marker("start"); +verify.indentationIs(4); +goTo.marker("end"); +verify.indentationIs(4); \ No newline at end of file diff --git a/tests/cases/fourslash/smartIndentOnListEnd.ts b/tests/cases/fourslash/smartIndentOnListEnd.ts new file mode 100644 index 0000000000000..21c6653fa95f1 --- /dev/null +++ b/tests/cases/fourslash/smartIndentOnListEnd.ts @@ -0,0 +1,12 @@ +/// + +////var a = [] +/////*1*/ +////| {} +/////*2*/ +////| ""; + +goTo.marker("1"); +verify.indentationIs(4) +goTo.marker("2"); +verify.indentationIs(4) \ No newline at end of file diff --git a/tests/cases/fourslash/smartIndentOnUnclosedFunctionDeclaration04.ts b/tests/cases/fourslash/smartIndentOnUnclosedFunctionDeclaration04.ts index 2cfd27f2e3bce..5a103fc576d31 100644 --- a/tests/cases/fourslash/smartIndentOnUnclosedFunctionDeclaration04.ts +++ b/tests/cases/fourslash/smartIndentOnUnclosedFunctionDeclaration04.ts @@ -3,15 +3,18 @@ ////function f/*1*/(/*2*/a: A, /*3*/b:/*4*/B, c/*5*/, d: C/*6*/ -function verifyIndentationAfterNewLine(marker: string, indentation: number): void { +function verifyIndentationAfterNewLine(marker: string, indentation: number, positionWorkaround: number, expectedText: string): void { goTo.marker(marker); edit.insert("\r\n"); + // The next two lines are to workaround #13433 + goTo.position(positionWorkaround); + verify.textAtCaretIs(expectedText); verify.indentationIs(indentation); } -verifyIndentationAfterNewLine("1", 4); -verifyIndentationAfterNewLine("2", 4); -verifyIndentationAfterNewLine("3", 4); -verifyIndentationAfterNewLine("4", 8); -verifyIndentationAfterNewLine("5", 4); -verifyIndentationAfterNewLine("6", 4); \ No newline at end of file +verifyIndentationAfterNewLine("1", 4, 25, '('); +verifyIndentationAfterNewLine("2", 8, 36, 'a'); +verifyIndentationAfterNewLine("3", 8, 51, 'b'); +verifyIndentationAfterNewLine("4", 12, 67, 'B'); +verifyIndentationAfterNewLine("5", 8, 81, ','); +verifyIndentationAfterNewLine("6", 8, 89, ''); \ No newline at end of file From cd2acf5c11e2f8982bdf38836f7801bec1b5e900 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 30 May 2017 03:21:56 +0900 Subject: [PATCH 7/7] workaround for codefix test failure See https://github.com/Microsoft/TypeScript/pull/13574#issuecomment-304691381 --- src/services/formatting/formatting.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 7635e2601107c..85543eef0bf08 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -716,7 +716,7 @@ namespace ts.formatting { let startLine = parentStartLine; let indentationOnListStartToken = parentDynamicIndentation.getIndentation(); - if (listStartToken !== SyntaxKind.Unknown) { + if (listStartToken !== SyntaxKind.Unknown && nodes.end !== undefined /* TODO: nodes.end must not be `undefined` */) { // introduce a new indentation scope for lists (including list start and end tokens) while (formattingScanner.isOnToken()) { const tokenInfo = formattingScanner.readTokenInfo(parent);