From 5270c337226f98a0092b2bc7de66a050771f4803 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Thu, 30 Mar 2017 16:36:26 -0700 Subject: [PATCH 1/4] Add test --- .../formattingOnChainedCallbacks2.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/cases/fourslash/formattingOnChainedCallbacks2.ts diff --git a/tests/cases/fourslash/formattingOnChainedCallbacks2.ts b/tests/cases/fourslash/formattingOnChainedCallbacks2.ts new file mode 100644 index 0000000000000..72c5d308889f3 --- /dev/null +++ b/tests/cases/fourslash/formattingOnChainedCallbacks2.ts @@ -0,0 +1,28 @@ +/// + +////Promise +//// .then( +//// /*then1cb1*/cb, +//// /*then1cb2*/cb2, +//// /*then1*/) +//// .then( +//// /*then2cb1*/cb, +//// /*then2cb2*/cb2, +//// /*then2*/) +//// .then(); + +format.document(); +verify.currentFileContentIs(""); +// goTo.marker('then1cb1'); +// verify.indentationIs(8); +// goTo.marker('then1cb2'); +// verify.indentationIs(8); +// goTo.marker('then1'); +// verify.indentationIs(4); + +// goTo.marker('then2cb1'); +// verify.indentationIs(8); +// goTo.marker('then2cb2'); +// verify.indentationIs(8); +// goTo.marker('then2'); +// verify.indentationIs(4); \ No newline at end of file From 36f2cf42d11609636425e624fb77df81410aaff2 Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Thu, 30 Mar 2017 23:54:19 -0700 Subject: [PATCH 2/4] WIP --- .../formattingOnChainedCallbacks2.ts | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/tests/cases/fourslash/formattingOnChainedCallbacks2.ts b/tests/cases/fourslash/formattingOnChainedCallbacks2.ts index 72c5d308889f3..12cf4d8b1450d 100644 --- a/tests/cases/fourslash/formattingOnChainedCallbacks2.ts +++ b/tests/cases/fourslash/formattingOnChainedCallbacks2.ts @@ -1,28 +1,16 @@ /// +////Promise.then( +/////*then1cb1*/cb, +//// ); ////Promise //// .then( -//// /*then1cb1*/cb, -//// /*then1cb2*/cb2, -//// /*then1*/) -//// .then( -//// /*then2cb1*/cb, -//// /*then2cb2*/cb2, -//// /*then2*/) -//// .then(); +/////*then2cb1*/cb, +//// ); format.document(); -verify.currentFileContentIs(""); -// goTo.marker('then1cb1'); -// verify.indentationIs(8); -// goTo.marker('then1cb2'); -// verify.indentationIs(8); -// goTo.marker('then1'); -// verify.indentationIs(4); +goTo.marker('then1cb1'); +verify.currentLineContentIs(" cb,"); -// goTo.marker('then2cb1'); -// verify.indentationIs(8); -// goTo.marker('then2cb2'); -// verify.indentationIs(8); -// goTo.marker('then2'); -// verify.indentationIs(4); \ No newline at end of file +goTo.marker('then2cb1'); +verify.currentLineContentIs(" cb,"); \ No newline at end of file From adeb9a6d1468a17f793d1c38bc4b47616e59a0d0 Mon Sep 17 00:00:00 2001 From: zhengbli Date: Fri, 31 Mar 2017 14:09:46 -0700 Subject: [PATCH 3/4] Fix it --- src/services/formatting/formatting.ts | 34 +++++++++++++++++-- .../formattingOnChainedCallbacks2.ts | 18 ++++++---- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 4fa3b71a3a200..6b0b3410f9430 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -315,7 +315,7 @@ namespace ts.formatting { } /* @internal */ - export function formatNode(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, rulesProvider: RulesProvider): TextChange[] { + export function formatNode(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, rulesProvider: RulesProvider): TextChange[] { const range = { pos: 0, end: sourceFileLike.text.length }; return formatSpanWorker( range, @@ -691,6 +691,24 @@ namespace ts.formatting { return inheritedIndentation; } + /** + * In some case even when a node list did not start at the same line with its parent, it should be treated specially because + * of the "effective parent line" was indented. E.g. + * + * Promise + * .then( // this is the "lastIndentedLine" + * a, <- here should be indented + * ) + * + * Here the parent of argument list is the call expression itself, however the indentation of the argument list should carry + * over the indentation in line 1 (".then"). + */ + function shouldListInheritIndentationFromLastIndentedLine(listStartLine: number, parent: Node, nodes: NodeArray) { + return lastIndentedLine === listStartLine && + parent.kind === SyntaxKind.CallExpression && + (parent).arguments === nodes; + } + function processChildNodes(nodes: NodeArray, parent: Node, parentStartLine: number, @@ -713,8 +731,13 @@ namespace ts.formatting { else if (tokenInfo.token.kind === listStartToken) { // consume list start token startLine = sourceFile.getLineAndCharacterOfPosition(tokenInfo.token.pos).line; + + if (shouldListInheritIndentationFromLastIndentedLine(startLine, parent, nodes)) { + parentStartLine = lastIndentedLine; + } + const indentation = - computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, parentStartLine); + computeIndentation(tokenInfo.token, startLine, /*inheritedIndentation*/ Constants.Unknown, parent, parentDynamicIndentation, parentStartLine); listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta); consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent); @@ -732,6 +755,13 @@ namespace ts.formatting { inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, startLine, /*isListItem*/ true, /*isFirstListItem*/ i === 0); } + if (nodes.hasTrailingComma && formattingScanner.isOnToken()) { + const tokenInfo = formattingScanner.readTokenInfo(parent); + if (tokenInfo.token.kind === SyntaxKind.CommaToken) { + consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent); + } + } + if (listEndToken !== SyntaxKind.Unknown) { if (formattingScanner.isOnToken()) { const tokenInfo = formattingScanner.readTokenInfo(parent); diff --git a/tests/cases/fourslash/formattingOnChainedCallbacks2.ts b/tests/cases/fourslash/formattingOnChainedCallbacks2.ts index 12cf4d8b1450d..fa861f75d8aef 100644 --- a/tests/cases/fourslash/formattingOnChainedCallbacks2.ts +++ b/tests/cases/fourslash/formattingOnChainedCallbacks2.ts @@ -1,16 +1,22 @@ /// -////Promise.then( -/////*then1cb1*/cb, -//// ); +////Promise +//// .then( +/////*then1cb1*/cb +//// /*then1*/); + ////Promise //// .then( /////*then2cb1*/cb, -//// ); +//// /*then2*/); format.document(); goTo.marker('then1cb1'); -verify.currentLineContentIs(" cb,"); +verify.currentLineContentIs(" cb"); +goTo.marker('then1'); +verify.currentLineContentIs(" );"); goTo.marker('then2cb1'); -verify.currentLineContentIs(" cb,"); \ No newline at end of file +verify.currentLineContentIs(" cb,"); +goTo.marker('then2'); +verify.currentLineContentIs(" );"); \ No newline at end of file From eb6038d2b38a74a76e87f8dbd87d5bb61f91903a Mon Sep 17 00:00:00 2001 From: Zhengbo Li Date: Wed, 5 Apr 2017 12:18:21 -0700 Subject: [PATCH 4/4] Add ElementAccessExpression case --- src/services/formatting/formatting.ts | 15 +++++++++++---- .../fourslash/formattingOnChainedCallbacks2.ts | 12 ++++++++++++ tests/cases/fourslash/formattingOptionsChange.ts | 4 ++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 6b0b3410f9430..6c19ce01391e4 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -536,7 +536,7 @@ namespace ts.formatting { } case SyntaxKind.OpenBracketToken: case SyntaxKind.CloseBracketToken: { - if (container.kind !== SyntaxKind.MappedType) { + if (container.kind !== SyntaxKind.MappedType && container.kind !== SyntaxKind.ElementAccessExpression) { return indentation; } break; @@ -704,9 +704,16 @@ namespace ts.formatting { * over the indentation in line 1 (".then"). */ function shouldListInheritIndentationFromLastIndentedLine(listStartLine: number, parent: Node, nodes: NodeArray) { - return lastIndentedLine === listStartLine && - parent.kind === SyntaxKind.CallExpression && - (parent).arguments === nodes; + if (lastIndentedLine !== listStartLine) { + return false; + } + + switch (parent.kind) { + case SyntaxKind.CallExpression: + return (parent).arguments === nodes; + default: + return false; + } } function processChildNodes(nodes: NodeArray, diff --git a/tests/cases/fourslash/formattingOnChainedCallbacks2.ts b/tests/cases/fourslash/formattingOnChainedCallbacks2.ts index fa861f75d8aef..381b44f84c0b1 100644 --- a/tests/cases/fourslash/formattingOnChainedCallbacks2.ts +++ b/tests/cases/fourslash/formattingOnChainedCallbacks2.ts @@ -10,6 +10,11 @@ /////*then2cb1*/cb, //// /*then2*/); +////Promise +//// ["then"](/*then3_1*/ +/////*then3cb1*/cb, +//// /*then3*/); + format.document(); goTo.marker('then1cb1'); verify.currentLineContentIs(" cb"); @@ -19,4 +24,11 @@ verify.currentLineContentIs(" );"); goTo.marker('then2cb1'); verify.currentLineContentIs(" cb,"); goTo.marker('then2'); +verify.currentLineContentIs(" );"); + +goTo.marker('then3_1'); +verify.currentLineContentIs(` ["then"](`); +goTo.marker('then3cb1'); +verify.currentLineContentIs(" cb,"); +goTo.marker('then3'); verify.currentLineContentIs(" );"); \ No newline at end of file diff --git a/tests/cases/fourslash/formattingOptionsChange.ts b/tests/cases/fourslash/formattingOptionsChange.ts index 0e731412ede3c..69b2253de3ee8 100644 --- a/tests/cases/fourslash/formattingOptionsChange.ts +++ b/tests/cases/fourslash/formattingOptionsChange.ts @@ -5,7 +5,7 @@ /////*insertSpaceBeforeAndAfterBinaryOperators*/1+2- 3 /////*insertSpaceAfterKeywordsInControlFlowStatements*/if (true) { } /////*insertSpaceAfterFunctionKeywordForAnonymousFunctions*/(function () { }) -/////*insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis*/(1 ) +/////*insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis*/(1 ); /////*insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets*/[1 ]; [ ]; []; [,]; /////*insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces*/`${1}`;`${ 1 }` /////*insertSpaceAfterTypeAssertion*/const bar = Thing.getFoo(); @@ -22,7 +22,7 @@ runTest("insertSpaceAfterSemicolonInForStatements", "for (i = 0; i; i++);", "for runTest("insertSpaceBeforeAndAfterBinaryOperators", "1 + 2 - 3", "1+2-3"); runTest("insertSpaceAfterKeywordsInControlFlowStatements", "if (true) { }", "if(true) { }"); runTest("insertSpaceAfterFunctionKeywordForAnonymousFunctions", "(function () { })", "(function() { })"); -runTest("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis", " ( 1 )", " (1)"); +runTest("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis", " ( 1 );", " (1);"); runTest("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets", "[ 1 ];[];[];[ , ];", "[1];[];[];[,];"); runTest("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces", "`${ 1 }`; `${ 1 }`", "`${1}`; `${1}`"); runTest("insertSpaceAfterTypeAssertion", "const bar = Thing.getFoo();", "const bar = Thing.getFoo();");