From cddc72a25e1a1cf524be872e1c26d3f1c8b13ce0 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Wed, 21 Dec 2016 20:58:52 +0900 Subject: [PATCH 1/4] always give container --- src/services/formatting/formatting.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index bcd8cebb017..78ddfa5c6e9 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -566,7 +566,7 @@ namespace ts.formatting { if (tokenInfo.token.end > node.end) { break; } - consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation); + consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation, node); } function processChildNode( @@ -617,7 +617,7 @@ namespace ts.formatting { break; } - consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation); + consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation, node); } if (!formattingScanner.isOnToken()) { @@ -673,11 +673,11 @@ namespace ts.formatting { computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, parentStartLine); listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta); - consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation); + consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent); } else { // consume any tokens that precede the list as child elements of 'node' using its indentation scope - consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation); + consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation, parent); } } } @@ -697,13 +697,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); + consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent); } } } } - function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container?: Node): void { + function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container: Node): void { Debug.assert(rangeContainsRange(parent, currentTokenInfo.token)); const lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine(); From 54fb29b8b89f09f0c2d02e1679e4c84a26aab17a Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Wed, 21 Dec 2016 21:01:03 +0900 Subject: [PATCH 2/4] format generic type alias --- src/services/formatting/rules.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 2095f062bd1..89250820c7c 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -829,6 +829,7 @@ namespace ts.formatting { switch (parent.kind) { case SyntaxKind.TypeReference: case SyntaxKind.TypeAssertionExpression: + case SyntaxKind.TypeAliasDeclaration: case SyntaxKind.ClassDeclaration: case SyntaxKind.ClassExpression: case SyntaxKind.InterfaceDeclaration: From bc59d6242b562a8312f66e1e345076fdf6d18e38 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Wed, 21 Dec 2016 21:01:28 +0900 Subject: [PATCH 3/4] format [P in keyof T] --- src/services/formatting/rules.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 89250820c7c..408b4683fe9 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -358,7 +358,7 @@ namespace ts.formatting { this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); // Add a space around certain TypeScript keywords - this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); + this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword, SyntaxKind.KeyOfKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.FromKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { @@ -575,6 +575,8 @@ namespace ts.formatting { return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken; // "in" keyword in for (let x in []) { } case SyntaxKind.ForInStatement: + // "in" keyword in [P in keyof T]: T[P] + case SyntaxKind.TypeParameter: return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword; // Technically, "of" is not a binary operator, but format it the same way as "in" case SyntaxKind.ForOfStatement: From f4c33aaec4537deecf4f5a0587616b386be5be2f Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Wed, 21 Dec 2016 21:01:47 +0900 Subject: [PATCH 4/4] indent inside mapped type --- src/services/formatting/formatting.ts | 6 ++++-- src/services/formatting/smartIndenter.ts | 1 + tests/cases/fourslash/formattingMappedType.ts | 12 ++++++++++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/formattingMappedType.ts diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 78ddfa5c6e9..8350b2a8dc8 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -488,14 +488,16 @@ 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.OpenBracketToken: - case SyntaxKind.CloseBracketToken: case SyntaxKind.OpenParenToken: case SyntaxKind.CloseParenToken: case SyntaxKind.ElseKeyword: case SyntaxKind.WhileKeyword: case SyntaxKind.AtToken: return indentation; + case SyntaxKind.OpenBracketToken: + case SyntaxKind.CloseBracketToken: + return (container.kind === SyntaxKind.MappedType) ? + indentation + getEffectiveDelta(delta, container) : indentation; default: // 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; diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index 84f83a9c7db..eb9e1ba04c5 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -438,6 +438,7 @@ namespace ts.formatting { case SyntaxKind.ModuleBlock: case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.TypeLiteral: + case SyntaxKind.MappedType: case SyntaxKind.TupleType: case SyntaxKind.CaseBlock: case SyntaxKind.DefaultClause: diff --git a/tests/cases/fourslash/formattingMappedType.ts b/tests/cases/fourslash/formattingMappedType.ts new file mode 100644 index 00000000000..a33d948a9c3 --- /dev/null +++ b/tests/cases/fourslash/formattingMappedType.ts @@ -0,0 +1,12 @@ +/// + +/////*generic*/type t < T > = { +/////*map*/ [ P in keyof T ] : T [ P ] +////}; + + +format.document(); +goTo.marker("generic"); +verify.currentLineContentIs("type t = {"); +goTo.marker("map"); +verify.currentLineContentIs(" [P in keyof T]: T[P]"); \ No newline at end of file