Skip to content

Commit

Permalink
Merge pull request #28340 from saschanaz/listindent-revive
Browse files Browse the repository at this point in the history
List position based formatting
  • Loading branch information
DanielRosenwasser authored Nov 9, 2018
2 parents 50a0174 + 7995f91 commit 02ca5be
Show file tree
Hide file tree
Showing 10 changed files with 370 additions and 190 deletions.
50 changes: 38 additions & 12 deletions src/services/formatting/formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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): 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
Expand Down Expand Up @@ -398,7 +398,7 @@ namespace ts.formatting {
let previousRangeStartLine: number;

let lastIndentedLine: number;
let indentationOnLastIndentedLine: number;
let indentationOnLastIndentedLine = Constants.Unknown;

const edits: TextChange[] = [];

Expand Down Expand Up @@ -539,8 +539,18 @@ namespace ts.formatting {
}
return tokenIndentation !== Constants.Unknown ? tokenIndentation : indentation;
},
getIndentationForToken: (line, kind, container) =>
shouldAddDelta(line, kind, container) ? indentation + getDelta(container) : indentation,
// 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;
getIndentationForToken: (line, kind, container, suppressDelta) =>
!suppressDelta && shouldAddDelta(line, kind, container) ? indentation + getDelta(container) : indentation,
getIndentation: () => indentation,
getDelta,
recomputeIndentation: lineAdded => {
Expand All @@ -556,7 +566,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:
Expand Down Expand Up @@ -737,11 +746,23 @@ 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);

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
// 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!); // TODO: GH#18217
}
else {
// consume any tokens that precede the list as child elements of 'node' using its indentation scope
Expand Down Expand Up @@ -770,12 +791,12 @@ namespace ts.formatting {
// without this check close paren will be interpreted as list end token for function expression which is wrong
if (tokenInfo && 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();
Expand Down Expand Up @@ -813,7 +834,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;
Expand Down Expand Up @@ -1227,6 +1248,9 @@ namespace ts.formatting {
if ((<TypeReferenceNode>node).typeArguments === list) {
return SyntaxKind.LessThanToken;
}
break;
case SyntaxKind.TypeLiteral:
return SyntaxKind.OpenBraceToken;
}

return SyntaxKind.Unknown;
Expand All @@ -1238,6 +1262,8 @@ namespace ts.formatting {
return SyntaxKind.CloseParenToken;
case SyntaxKind.LessThanToken:
return SyntaxKind.GreaterThanToken;
case SyntaxKind.OpenBraceToken:
return SyntaxKind.CloseBraceToken;
}

return SyntaxKind.Unknown;
Expand Down
Loading

0 comments on commit 02ca5be

Please sign in to comment.