diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 7662a625bde..914b66c00f6 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -34,7 +34,7 @@ namespace ts.formatting { * the first token in line so it should be indented */ interface DynamicIndentation { - getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind, container: Node, suppressDelta?: boolean): 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 @@ -735,7 +735,6 @@ 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) @@ -751,6 +750,7 @@ namespace ts.formatting { consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation, parent); + let indentationOnListStartToken: number; 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 @@ -835,7 +835,7 @@ namespace ts.formatting { if (indentToken) { const tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) ? - dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container, isListEndToken) : + dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container, !!isListEndToken) : Constants.Unknown; let indentNextTokenOrTrivia = true; diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index d5180c87874..eee8240aa62 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -66,7 +66,7 @@ namespace ts.formatting { } } - const containerList = getListByPosition(position, precedingToken.parent); + const containerList = getListByPosition(position, precedingToken.parent, sourceFile); // use list position if the preceding token is before any list items if (containerList && !rangeContainsRange(containerList, precedingToken)) { return getActualIndentationForListStartLine(containerList, sourceFile, options) + options.indentSize!; // TODO: GH#18217 @@ -322,7 +322,7 @@ namespace ts.formatting { return false; } - function getListIfVisualStartEndIsInListRange(list: NodeArray | undefined, start: number, end: number, node: Node) { + function getListIfVisualStartEndIsInListRange(list: NodeArray | undefined, start: number, end: number, node: Node, sourceFile: SourceFile) { return list && rangeContainsVisualStartEnd(list) ? list : undefined; // Assumes a list is wrapped by list tokens @@ -330,7 +330,7 @@ namespace ts.formatting { const children = node.getChildren(); for (let i = 1; 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 - children[i + 1].getWidth() }, start, end); + return rangeContainsStartEnd({ pos: children[i - 1].end, end: children[i + 1].getStart(sourceFile) }, start, end); } } return rangeContainsStartEnd(textRange, start, end); @@ -343,28 +343,28 @@ namespace ts.formatting { export function getContainingList(node: Node, sourceFile: SourceFile): NodeArray | undefined { if (node.parent) { - return getListByRange(node.getStart(sourceFile), node.getEnd(), node.parent); + return getListByRange(node.getStart(sourceFile), node.getEnd(), node.parent, sourceFile); } return undefined; } - function getListByPosition(pos: number, node: Node): NodeArray | undefined { + function getListByPosition(pos: number, node: Node, sourceFile: SourceFile): NodeArray | undefined { if (!node) { return; } - return getListByRange(pos, pos, node); + return getListByRange(pos, pos, node, sourceFile); } - function getListByRange(start: number, end: number, node: Node): NodeArray | undefined { + function getListByRange(start: number, end: number, node: Node, sourceFile: SourceFile): NodeArray | undefined { switch (node.kind) { case SyntaxKind.TypeReference: - return getListIfVisualStartEndIsInListRange((node).typeArguments, start, end, node); + return getListIfVisualStartEndIsInListRange((node).typeArguments, start, end, node, sourceFile); case SyntaxKind.ObjectLiteralExpression: - return getListIfVisualStartEndIsInListRange((node).properties, start, end, node); + return getListIfVisualStartEndIsInListRange((node).properties, start, end, node, sourceFile); case SyntaxKind.ArrayLiteralExpression: - return getListIfVisualStartEndIsInListRange((node).elements, start, end, node); + return getListIfVisualStartEndIsInListRange((node).elements, start, end, node, sourceFile); case SyntaxKind.TypeLiteral: - return getListIfVisualStartEndIsInListRange((node).members, start, end, node); + return getListIfVisualStartEndIsInListRange((node).members, start, end, node, sourceFile); case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: @@ -374,8 +374,8 @@ namespace ts.formatting { case SyntaxKind.Constructor: case SyntaxKind.ConstructorType: case SyntaxKind.ConstructSignature: { - return getListIfVisualStartEndIsInListRange((node).typeParameters, start, end, node) || - getListIfVisualStartEndIsInListRange((node).parameters, start, end, node); + return getListIfVisualStartEndIsInListRange((node).typeParameters, start, end, node, sourceFile) || + getListIfVisualStartEndIsInListRange((node).parameters, start, end, node, sourceFile); } case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: @@ -383,21 +383,21 @@ namespace ts.formatting { case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.JSDocTemplateTag: { const { typeParameters } = node; - return getListIfStartEndIsInListRange(typeParameters, start, end); + return getListIfVisualStartEndIsInListRange(typeParameters, start, end, node, sourceFile); } case SyntaxKind.NewExpression: case SyntaxKind.CallExpression: { - return getListIfVisualStartEndIsInListRange((node).typeArguments, start, end, node) || - getListIfVisualStartEndIsInListRange((node).arguments, start, end, node); + return getListIfVisualStartEndIsInListRange((node).typeArguments, start, end, node, sourceFile) || + getListIfVisualStartEndIsInListRange((node).arguments, start, end, node, sourceFile); } case SyntaxKind.VariableDeclarationList: return getListIfStartEndIsInListRange((node).declarations, start, end); case SyntaxKind.NamedImports: case SyntaxKind.NamedExports: - return getListIfVisualStartEndIsInListRange((node).elements, start, end, node); + return getListIfVisualStartEndIsInListRange((node).elements, start, end, node, sourceFile); case SyntaxKind.ObjectBindingPattern: case SyntaxKind.ArrayBindingPattern: - return getListIfVisualStartEndIsInListRange((node).elements, start, end, node); + return getListIfVisualStartEndIsInListRange((node).elements, start, end, node, sourceFile); } } diff --git a/tests/cases/fourslash/formattingOnChainedCallbacks.ts b/tests/cases/fourslash/formattingOnChainedCallbacks.ts index 5c1eafbbd24..1dc2d5bc84a 100644 --- a/tests/cases/fourslash/formattingOnChainedCallbacks.ts +++ b/tests/cases/fourslash/formattingOnChainedCallbacks.ts @@ -1,26 +1,26 @@ -/// - -////Promise -//// .resolve() -//// .then(() => {/*1*/""/*2*/ -////}).then(() => {/*3*//*4*/ -////})/*semi1*//*semi2*/ - -////function foo() { -//// return Promise.resolve() -//// .then(function () { -//// ""/*a*/ -//// })/*b*/ -////} - -////Promise -//// .then( -//// /*n1*/ -//// ) -//// /*n2*/ -//// .then(); - -// @Filename: listSmart.ts +/// + +////Promise +//// .resolve() +//// .then(() => {/*1*/""/*2*/ +////}).then(() => {/*3*//*4*/ +////})/*semi1*//*semi2*/ + +////function foo() { +//// return Promise.resolve() +//// .then(function () { +//// ""/*a*/ +//// })/*b*/ +////} + +////Promise +//// .then( +//// /*n1*/ +//// ) +//// /*n2*/ +//// .then(); + +// @Filename: listSmart.ts ////Promise //// .resolve().then( //// /*listSmart1*/ @@ -31,9 +31,9 @@ //// /*listSmart3*/ //// ] //// /*listSmart4*/ -//// ); - -// @Filename: listZeroIndent.ts +//// ); + +// @Filename: listZeroIndent.ts ////Promise.resolve([ ////]).then( //// /*listZeroIndent1*/ @@ -41,9 +41,9 @@ //// /*listZeroIndent2*/ //// 3 //// ] -//// ); - -// @Filename: listTypeParameter1.ts +//// ); + +// @Filename: listTypeParameter1.ts ////foo.then //// < //// /*listTypeParameter1*/ @@ -54,49 +54,49 @@ //// }, //// function (): void { //// } -//// ); - -// @Filename: listComment.ts +//// ); + +// @Filename: listComment.ts ////Promise //// .then( //// // euphonium //// "k" //// // oboe -//// ); - - -goTo.marker('1'); -edit.insertLine(''); -goTo.marker('2'); -verify.currentLineContentIs(' ""'); -edit.insertLine(''); -verify.indentationIs(8); -goTo.marker('4'); -edit.insertLine(''); -goTo.marker('3'); -verify.currentLineContentIs(' }).then(() => {'); - -goTo.marker("semi1"); -edit.insert(';'); -verify.currentLineContentIs(' });'); -goTo.marker("semi2"); -edit.insert(';'); -verify.currentLineContentIs(' });;'); - -goTo.marker('a'); -edit.insert(';'); -verify.currentLineContentIs(' "";'); -goTo.marker('b'); -edit.insert(';'); -verify.currentLineContentIs(' });'); - -goTo.marker('n1'); -verify.indentationIs(8); -goTo.marker('n2'); -verify.indentationIs(4); - -goTo.file(1); -format.document(); +//// ); + + +goTo.marker('1'); +edit.insertLine(''); +goTo.marker('2'); +verify.currentLineContentIs(' ""'); +edit.insertLine(''); +verify.indentationIs(8); +goTo.marker('4'); +edit.insertLine(''); +goTo.marker('3'); +verify.currentLineContentIs(' }).then(() => {'); + +goTo.marker("semi1"); +edit.insert(';'); +verify.currentLineContentIs(' });'); +goTo.marker("semi2"); +edit.insert(';'); +verify.currentLineContentIs(' });;'); + +goTo.marker('a'); +edit.insert(';'); +verify.currentLineContentIs(' "";'); +goTo.marker('b'); +edit.insert(';'); +verify.currentLineContentIs(' });'); + +goTo.marker('n1'); +verify.indentationIs(8); +goTo.marker('n2'); +verify.indentationIs(4); + +goTo.file("listSmart.ts"); +format.document(); verify.currentFileContentIs(`Promise .resolve().then( @@ -117,7 +117,7 @@ verify.indentationIs(12); goTo.marker("listSmart4"); verify.indentationIs(8); -goTo.file(2); +goTo.file("listZeroIndent.ts"); format.document(); verify.currentFileContentIs(`Promise.resolve([ ]).then( @@ -132,7 +132,7 @@ verify.indentationIs(4); goTo.marker("listZeroIndent2"); verify.indentationIs(8); -goTo.file(3); +goTo.file("listTypeParameter1.ts"); format.document(); verify.currentFileContentIs(`foo.then < @@ -150,7 +150,7 @@ verify.indentationIs(8); goTo.marker("listTypeParameter2"); verify.indentationIs(8); -goTo.file(4); +goTo.file("listComment.ts"); format.document(); verify.currentFileContentIs(`Promise .then(