Skip to content

Commit 88a8345

Browse files
committed
Merge pull request microsoft#4757 from SaschaNaz/indentSuppressor
Expose indentation suppressor from SmartIndenter
2 parents 992bd7a + 34b303a commit 88a8345

File tree

2 files changed

+50
-58
lines changed

2 files changed

+50
-58
lines changed

src/services/formatting/formatting.ts

Lines changed: 34 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ namespace ts.formatting {
3131
* the first token in line so it should be indented
3232
*/
3333
interface DynamicIndentation {
34-
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind): number;
35-
getIndentationForComment(owningToken: SyntaxKind, tokenIndentation: number): number;
34+
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind, container: Node): number;
35+
getIndentationForComment(owningToken: SyntaxKind, tokenIndentation: number, container: Node): number;
3636
/**
3737
* Indentation for open and close tokens of the node if it is block or another node that needs special indentation
3838
* ... {
@@ -54,7 +54,7 @@ namespace ts.formatting {
5454
* so bar inherits indentation from foo and bar.delta will be 4
5555
*
5656
*/
57-
getDelta(): number;
57+
getDelta(child: TextRangeWithKind): number;
5858
/**
5959
* Formatter calls this function when rule adds or deletes new lines from the text
6060
* so indentation scope can adjust values of indentation and delta.
@@ -282,19 +282,19 @@ namespace ts.formatting {
282282
*/
283283
function getOwnOrInheritedDelta(n: Node, options: FormatCodeOptions, sourceFile: SourceFile): number {
284284
let previousLine = Constants.Unknown;
285-
let childKind = SyntaxKind.Unknown;
285+
let child: Node;
286286
while (n) {
287287
let line = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile)).line;
288288
if (previousLine !== Constants.Unknown && line !== previousLine) {
289289
break;
290290
}
291291

292-
if (SmartIndenter.shouldIndentChildNode(n.kind, childKind)) {
292+
if (SmartIndenter.shouldIndentChildNode(n, child)) {
293293
return options.IndentSize;
294294
}
295295

296296
previousLine = line;
297-
childKind = n.kind;
297+
child = n;
298298
n = n.parent;
299299
}
300300
return 0;
@@ -386,34 +386,7 @@ namespace ts.formatting {
386386
effectiveParentStartLine: number): Indentation {
387387

388388
let indentation = inheritedIndentation;
389-
if (indentation === Constants.Unknown) {
390-
if (isSomeBlock(node.kind)) {
391-
// blocks should be indented in
392-
// - other blocks
393-
// - source file
394-
// - switch\default clauses
395-
if (isSomeBlock(parent.kind) ||
396-
parent.kind === SyntaxKind.SourceFile ||
397-
parent.kind === SyntaxKind.CaseClause ||
398-
parent.kind === SyntaxKind.DefaultClause) {
399-
400-
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
401-
}
402-
else {
403-
indentation = parentDynamicIndentation.getIndentation();
404-
}
405-
}
406-
else {
407-
if (SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile)) {
408-
indentation = parentDynamicIndentation.getIndentation();
409-
}
410-
else {
411-
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
412-
}
413-
}
414-
}
415-
416-
var delta = SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
389+
var delta = SmartIndenter.shouldIndentChildNode(node) ? options.IndentSize : 0;
417390

418391
if (effectiveParentStartLine === startLine) {
419392
// if node is located on the same line with the parent
@@ -422,8 +395,17 @@ namespace ts.formatting {
422395
indentation = startLine === lastIndentedLine
423396
? indentationOnLastIndentedLine
424397
: parentDynamicIndentation.getIndentation();
425-
delta = Math.min(options.IndentSize, parentDynamicIndentation.getDelta() + delta);
398+
delta = Math.min(options.IndentSize, parentDynamicIndentation.getDelta(node) + delta);
426399
}
400+
else if (indentation === Constants.Unknown) {
401+
if (SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile)) {
402+
indentation = parentDynamicIndentation.getIndentation();
403+
}
404+
else {
405+
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta(node);
406+
}
407+
}
408+
427409
return {
428410
indentation,
429411
delta
@@ -455,7 +437,7 @@ namespace ts.formatting {
455437

456438
function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, delta: number): DynamicIndentation {
457439
return {
458-
getIndentationForComment: (kind, tokenIndentation) => {
440+
getIndentationForComment: (kind, tokenIndentation, container) => {
459441
switch (kind) {
460442
// preceding comment to the token that closes the indentation scope inherits the indentation from the scope
461443
// .. {
@@ -464,11 +446,11 @@ namespace ts.formatting {
464446
case SyntaxKind.CloseBraceToken:
465447
case SyntaxKind.CloseBracketToken:
466448
case SyntaxKind.CloseParenToken:
467-
return indentation + delta;
449+
return indentation + getEffectiveDelta(delta, container);
468450
}
469451
return tokenIndentation !== Constants.Unknown ? tokenIndentation : indentation;
470452
},
471-
getIndentationForToken: (line, kind) => {
453+
getIndentationForToken: (line, kind, container) => {
472454
if (nodeStartLine !== line && node.decorators) {
473455
if (kind === getFirstNonDecoratorTokenOfNode(node)) {
474456
// if this token is the first token following the list of decorators, we do not need to indent
@@ -489,28 +471,33 @@ namespace ts.formatting {
489471
return indentation;
490472
default:
491473
// if token line equals to the line of containing node (this is a first token in the node) - use node indentation
492-
return nodeStartLine !== line ? indentation + delta : indentation;
474+
return nodeStartLine !== line ? indentation + getEffectiveDelta(delta, container) : indentation;
493475
}
494476
},
495477
getIndentation: () => indentation,
496-
getDelta: () => delta,
478+
getDelta: child => getEffectiveDelta(delta, child),
497479
recomputeIndentation: lineAdded => {
498-
if (node.parent && SmartIndenter.shouldIndentChildNode(node.parent.kind, node.kind)) {
480+
if (node.parent && SmartIndenter.shouldIndentChildNode(node.parent, node)) {
499481
if (lineAdded) {
500482
indentation += options.IndentSize;
501483
}
502484
else {
503485
indentation -= options.IndentSize;
504486
}
505487

506-
if (SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown)) {
488+
if (SmartIndenter.shouldIndentChildNode(node)) {
507489
delta = options.IndentSize;
508490
}
509491
else {
510492
delta = 0;
511493
}
512494
}
513-
},
495+
}
496+
}
497+
498+
function getEffectiveDelta(delta: number, child: TextRangeWithKind) {
499+
// Delta value should be zero when the node explicitly prevents indentation of the child node
500+
return SmartIndenter.nodeWillIndentChild(node, child, true) ? delta : 0;
514501
}
515502
}
516503

@@ -610,7 +597,7 @@ namespace ts.formatting {
610597
// if child node is a token, it does not impact indentation, proceed it using parent indentation scope rules
611598
let tokenInfo = formattingScanner.readTokenInfo(child);
612599
Debug.assert(tokenInfo.token.end === child.end);
613-
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
600+
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation, child);
614601
return inheritedIndentation;
615602
}
616603

@@ -679,7 +666,7 @@ namespace ts.formatting {
679666
}
680667
}
681668

682-
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation): void {
669+
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container?: Node): void {
683670
Debug.assert(rangeContainsRange(parent, currentTokenInfo.token));
684671

685672
let lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
@@ -720,11 +707,11 @@ namespace ts.formatting {
720707

721708
if (indentToken) {
722709
let tokenIndentation = (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) ?
723-
dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind) :
710+
dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind, container) :
724711
Constants.Unknown;
725712

726713
if (currentTokenInfo.leadingTrivia) {
727-
let commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind, tokenIndentation);
714+
let commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind, tokenIndentation, container);
728715
let indentNextTokenOrTrivia = true;
729716

730717
for (let triviaItem of currentTokenInfo.leadingTrivia) {

src/services/formatting/smartIndenter.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ namespace ts.formatting {
6868
let indentationDelta: number;
6969

7070
while (current) {
71-
if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(current.kind, previous ? previous.kind : SyntaxKind.Unknown)) {
71+
if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(current, previous)) {
7272
currentStart = getStartLineAndCharacterForNode(current, sourceFile);
7373

7474
if (nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile)) {
@@ -153,7 +153,7 @@ namespace ts.formatting {
153153
}
154154

155155
// increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line
156-
if (shouldIndentChildNode(parent.kind, current.kind) && !parentAndChildShareLine) {
156+
if (shouldIndentChildNode(parent, current) && !parentAndChildShareLine) {
157157
indentationDelta += options.IndentSize;
158158
}
159159

@@ -466,12 +466,10 @@ namespace ts.formatting {
466466
}
467467
return false;
468468
}
469-
470-
export function shouldIndentChildNode(parent: SyntaxKind, child: SyntaxKind): boolean {
471-
if (nodeContentIsAlwaysIndented(parent)) {
472-
return true;
473-
}
474-
switch (parent) {
469+
470+
export function nodeWillIndentChild(parent: TextRangeWithKind, child: TextRangeWithKind, indentByDefault: boolean) {
471+
let childKind = child ? child.kind : SyntaxKind.Unknown;
472+
switch (parent.kind) {
475473
case SyntaxKind.DoStatement:
476474
case SyntaxKind.WhileStatement:
477475
case SyntaxKind.ForInStatement:
@@ -485,10 +483,17 @@ namespace ts.formatting {
485483
case SyntaxKind.Constructor:
486484
case SyntaxKind.GetAccessor:
487485
case SyntaxKind.SetAccessor:
488-
return child !== SyntaxKind.Block;
489-
default:
490-
return false;
486+
return childKind !== SyntaxKind.Block;
491487
}
488+
// No explicit rule for given nodes so the result will follow the default value argument
489+
return indentByDefault;
490+
}
491+
492+
/*
493+
Function returns true when the parent node should indent the given child by an explicit rule
494+
*/
495+
export function shouldIndentChildNode(parent: TextRangeWithKind, child?: TextRangeWithKind): boolean {
496+
return nodeContentIsAlwaysIndented(parent.kind) || nodeWillIndentChild(parent, child, false);
492497
}
493498
}
494499
}

0 commit comments

Comments
 (0)