fix indentations in functions

This commit is contained in:
Vladimir Matveev
2014-11-05 15:23:11 -08:00
parent e270bda57e
commit f28c1a3498
3 changed files with 233 additions and 58 deletions

View File

@@ -17,10 +17,14 @@ module ts.formatting {
}
interface DynamicIndentation {
getIndentation(): number;
getCommentIndentation(): number;
getEffectiveIndentation(line: number, kind: SyntaxKind): number;
getEffectiveCommentIndentation(line: number): number;
getDelta(): number;
getBaseIndentation(): number;
getBaseCommentIndentation(): number;
increaseCommentIndentation(delta: number): void;
recomputeIndentation(lineAddedByFormatting: boolean): void;
setDelta(delta: number): number;
}
export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[]{
@@ -61,6 +65,41 @@ module ts.formatting {
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection);
}
function isSomeBlock(kind: SyntaxKind): boolean {
switch (kind) {
case SyntaxKind.Block:
case SyntaxKind.FunctionBlock:
case SyntaxKind.TryBlock:
case SyntaxKind.CatchBlock:
case SyntaxKind.FinallyBlock:
case SyntaxKind.ModuleBlock:
return true;
default:
return false;
}
}
function indentChildNodes(kind: SyntaxKind): boolean {
if (SmartIndenter.nodeContentIsAlwaysIndented(kind)) {
return true;
}
switch (kind) {
case SyntaxKind.IfStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.Method:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return true;
break;
}
return false;
}
function formatOutermostParent(position: number, expectedLastToken: SyntaxKind, sourceFile: SourceFile, options: FormatCodeOptions, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[]{
var parent = findOutermostParent(position, expectedLastToken, sourceFile);
if (!parent) {
@@ -187,7 +226,8 @@ module ts.formatting {
if (formattingScanner.isOnToken()) {
var startLine = sourceFile.getLineAndCharacterFromPosition(enclosingNode.getStart(sourceFile)).line;
processNode(enclosingNode, enclosingNode, startLine, initialIndentation);
var delta = indentChildNodes(enclosingNode.kind) ? options.IndentSize : 0;
processNode(enclosingNode, enclosingNode, startLine, initialIndentation, delta);
}
formattingScanner.close();
@@ -201,10 +241,35 @@ module ts.formatting {
return 0;
}
function getDynamicIndentation(node: Node, indentation: number, commentIndentation: number, parentIndentation: DynamicIndentation): DynamicIndentation {
function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, commentIndentation: number, delta: number, parentIndentation: DynamicIndentation): DynamicIndentation {
return {
getCommentIndentation: () => commentIndentation,
getIndentation: () => indentation,
getEffectiveCommentIndentation: (line) => {
if (nodeStartLine !== line) {
return commentIndentation + delta;
}
return commentIndentation;
},
getEffectiveIndentation: (line, kind) => {
switch (kind) {
case SyntaxKind.OpenBraceToken:
case SyntaxKind.CloseBraceToken:
case SyntaxKind.OpenBracketToken:
case SyntaxKind.CloseBracketToken:
case SyntaxKind.ElseKeyword:
case SyntaxKind.WhileKeyword:
return indentation;
default:
return nodeStartLine !== line ? indentation + delta : indentation;
}
//if (nodeStartLine !== line && kind !== SyntaxKind.CloseBraceToken) {
// return indentation + delta;
//}
//return indentation;
},
getBaseIndentation: () => indentation,
getBaseCommentIndentation: () => commentIndentation,
getDelta: () => delta,
recomputeIndentation: (lineAdded) => {
if (parentIndentation) {
parentIndentation.recomputeIndentation(lineAdded);
@@ -217,6 +282,11 @@ module ts.formatting {
},
increaseCommentIndentation: (delta) => {
commentIndentation += delta;
},
setDelta(newDelta: number): number {
var old = delta;
delta = newDelta;
return old;
}
}
}
@@ -228,15 +298,16 @@ module ts.formatting {
var nodeStartLine = sourceFile.getLineAndCharacterFromPosition(start).line;
var startLinePosition = getStartPositionOfLine(nodeStartLine, sourceFile);
var shareLine = nodeStartLine === parentStartLine;
var column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, start, sourceFile, options); // ?
var column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, start, sourceFile, options);
return shareLine && start !== column? -1 : column;
}
function processNode(node: Node, contextNode: Node, nodeStartLine: number, indentation: number) {
function processNode(node: Node, contextNode: Node, nodeStartLine: number, indentation: number, delta: number) {
if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) {
return;
}
var nodeIndentation = getDynamicIndentation(node, indentation, indentation, undefined);
var nodeIndentation = getDynamicIndentation(node, nodeStartLine, indentation, indentation, delta, undefined);
var childContextNode = contextNode;
forEachChild(
@@ -283,11 +354,16 @@ module ts.formatting {
// make sure that this token does not belong to the child
var startTokenIndentation = nodeIndentation;
var tokenStartLine = sourceFile.getLineAndCharacterFromPosition(tokenInfo.token.pos).line;
var oldDelta = -1;
if (node.parent.kind !== SyntaxKind.SourceFile && tokenStartLine !== nodeStartLine) {
var indentation = nodeIndentation.getIndentation() + options.IndentSize;
startTokenIndentation = getDynamicIndentation(node, indentation, indentation, nodeIndentation);
oldDelta = nodeIndentation.setDelta(options.IndentSize);
//var indentation = nodeIndentation.getIndentation() + options.IndentSize;
//startTokenIndentation = getDynamicIndentation(node, indentation, indentation, nodeIndentation);
}
doConsumeTokenAndAdvanceScanner(tokenInfo, node, startTokenIndentation);
if (oldDelta !== -1) {
nodeIndentation.setDelta(oldDelta);
}
}
}
}
@@ -301,9 +377,10 @@ module ts.formatting {
if (formattingScanner.isOnToken()) {
var tokenInfo = formattingScanner.readTokenInfo(node);
if (tokenInfo.token.kind === listEndToken && formattingScanner.lastTrailingTriviaWasNewLine()) {
var endTokenIndentation = nodeIndentation.getIndentation() + options.IndentSize;
doConsumeTokenAndAdvanceScanner(tokenInfo, node, getDynamicIndentation(node, endTokenIndentation, endTokenIndentation, nodeIndentation));
var old = nodeIndentation.setDelta(options.IndentSize);
//var endTokenIndentation = nodeIndentation.getIndentation() + options.IndentSize;
doConsumeTokenAndAdvanceScanner(tokenInfo, node, nodeIndentation);
nodeIndentation.setDelta(old);
}
}
}
@@ -318,7 +395,7 @@ module ts.formatting {
break;
}
if (SmartIndenter.nodeContentIsAlwaysIndented(node) && node.end === tokenInfo.token.end) {
if (SmartIndenter.nodeContentIsAlwaysIndented(node.kind) && node.end === tokenInfo.token.end) {
nodeIndentation.increaseCommentIndentation(options.IndentSize);
}
doConsumeTokenAndAdvanceScanner(tokenInfo, node, nodeIndentation);
@@ -347,62 +424,159 @@ module ts.formatting {
var childStart = sourceFile.getLineAndCharacterFromPosition(start);
var actualIndentation = inheritedIndentation;
var childIndentationAmount: number;
var childDelta: number = 0;
var isChildInRange = rangeOverlapsWithStartEnd(originalRange, start, child.getEnd());
var childIndentationValue: number;
if (containingList) {
if (isChildInRange) {
if (isChildInRange) {
if (inheritedIndentation !== undefined) {
// use indentation inherited from preceding list items
childIndentationValue = inheritedIndentation;
}
else {
var increaseIndentation =
node.kind !== SyntaxKind.SourceFile &&
node.pos !== child.pos &&
formattingScanner.lastTrailingTriviaWasNewLine();
var childIndentationValue =
increaseIndentation
? nodeIndentation.getIndentation() + options.IndentSize
: nodeIndentation.getIndentation();
childIndentationAmount = inheritedIndentation;
childDelta = 0;
}
}
else {
// child is a list item that is not in span being formatted
// fetch actual indentation for the child item to push it downstream
// TODO: ensure that indentation is picked correctly
var actualIndentation = getListItemIndentation(containingList, listElementIndex, nodeStartLine, options);
if (actualIndentation !== -1) {
inheritedIndentation = actualIndentation;
inheritedIndentation = childIndentationAmount = actualIndentation;
childDelta = 0;
}
var childIndentationValue = inheritedIndentation || nodeIndentation.getIndentation();
}
}
else {
var shareLine = nodeStartLine === childStart.line;
var increaseIndentation =
!shareLine &&
!SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(node, child, childStart.line, sourceFile) &&
SmartIndenter.shouldIndentChildNode(node, child);
var childIndentationValue =
increaseIndentation
? nodeIndentation.getIndentation() + options.IndentSize
: nodeIndentation.getIndentation();
if (childIndentationAmount === undefined) {
if (isSomeBlock(child.kind)) {
// child is indented
childDelta = options.IndentSize;
if (isSomeBlock(node.kind) || node.kind === SyntaxKind.SourceFile || node.kind === SyntaxKind.CaseClause || node.kind === SyntaxKind.DefaultClause) {
childIndentationAmount = nodeIndentation.getBaseIndentation() + nodeIndentation.getDelta();
}
else {
childIndentationAmount = nodeIndentation.getBaseIndentation();
}
}
else {
var increaseIndentation = SmartIndenter.nodeContentIsAlwaysIndented(child.kind);
if (!increaseIndentation) {
switch (child.kind) {
case SyntaxKind.IfStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.Method:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
increaseIndentation = true;
break;
}
}
//var increaseIndentation =
// !SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(node, child, childStart.line, sourceFile) &&
// SmartIndenter.shouldIndentChildNode(child, undefined);
if (SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(node, child, childStart.line, sourceFile) || node.kind === SyntaxKind.PropertyAccess) {
childIndentationAmount = nodeIndentation.getBaseIndentation();
}
else {
childIndentationAmount = nodeIndentation.getBaseIndentation() + nodeIndentation.getDelta();
}
if (increaseIndentation) {
childDelta = options.IndentSize;
}
}
}
var childIndentation = getDynamicIndentation(node, childIndentationValue, childIndentationValue, nodeIndentation);
////var childIndentationValue: number;
//var childIndentationAmount: number;
//var childDelta: number;
//if (containingList) {
// childDelta = 0;
// if (isChildInRange) {
// if (inheritedIndentation !== undefined) {
// // use indentation inherited from preceding list items
// // childIndentationValue = inheritedIndentation;
// childIndentationAmount = inheritedIndentation;
// }
// else {
// childIndentationAmount = nodeIndentation.getEffectiveIndentation(childStart.line, child.kind);
// //var increaseIndentation =
// // node.kind !== SyntaxKind.SourceFile &&
// // node.pos !== child.pos &&
// // formattingScanner.lastTrailingTriviaWasNewLine();
// //var childIndentationValue =
// // increaseIndentation
// // ? nodeIndentation.getIndentation() + options.IndentSize
// // : nodeIndentation.getIndentation();
// }
// }
// else {
// // child is a list item that is not in span being formatted
// // fetch actual indentation for the child item to push it downstream
// // TODO: ensure that indentation is picked correctly
// var actualIndentation = getListItemIndentation(containingList, listElementIndex, nodeStartLine, options);
// if (actualIndentation !== -1) {
// inheritedIndentation = actualIndentation;
// childIndentationAmount = actualIndentation;
// }
// else {
// childIndentationAmount = nodeIndentation.getEffectiveIndentation(childStart.line, child.kind);
// }
// }
// var increaseIndentation =
// // !shareLine &&
// !SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(node, child, childStart.line, sourceFile) &&
// SmartIndenter.shouldIndentChildNode(node, child);
// childIndentationAmount = nodeIndentation.getEffectiveIndentation(childStart.line, child.kind);
// if (increaseIndentation) {
// childDelta = options.IndentSize;
// }
// else {
// childDelta = 0;
// }
//}
//else {
// //var shareLine = nodeStartLine === childStart.line;
// var increaseIndentation =
// // !shareLine &&
// !SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(node, child, childStart.line, sourceFile) &&
// SmartIndenter.shouldIndentChildNode(node, child);
// childIndentationAmount = nodeIndentation.getEffectiveIndentation(childStart.line, child.kind);
// if (increaseIndentation) {
// childDelta = options.IndentSize;
// }
// else {
// childDelta = 0;
// }
// //var childIndentationValue =
// // increaseIndentation
// // ? nodeIndentation.getIndentation() + options.IndentSize
// // : nodeIndentation.getIndentation();
//}
if (nodeStartLine === childStart.line) {
childIndentationAmount = nodeIndentation.getBaseIndentation();
childDelta = Math.min(options.IndentSize, delta + childDelta);
}
// ensure that current token is inside child node
if (isToken(child)) {
var tokenInfo = formattingScanner.readTokenInfo(node);
Debug.assert(tokenInfo.token.end === child.end);
var childIndentation = getDynamicIndentation(node, nodeStartLine, childIndentationAmount, childIndentationAmount, childDelta, nodeIndentation);
doConsumeTokenAndAdvanceScanner(tokenInfo, node, childIndentation);
}
else {
processNode(child, childContextNode, childStart.line, childIndentationValue);
processNode(child, childContextNode, childStart.line, childIndentationAmount, childDelta);
childContextNode = node;
}
return inheritedIndentation;
@@ -427,9 +601,9 @@ module ts.formatting {
var isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token);
var indentToken: boolean = true;
var tokenStart = sourceFile.getLineAndCharacterFromPosition(currentTokenInfo.token.pos);
if (isTokenInRange) {
var prevStartLine = previousRangeStartLine;
var tokenStart = sourceFile.getLineAndCharacterFromPosition(currentTokenInfo.token.pos);
var prevStartLine = previousRangeStartLine;
lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, contextNode, indentation);
if (lineAdded !== undefined) {
indentToken = lineAdded;
@@ -449,15 +623,16 @@ module ts.formatting {
if (currentTokenInfo.leadingTrivia) {
for (var i = 0, len = currentTokenInfo.leadingTrivia.length; i < len; ++i) {
var triviaItem = currentTokenInfo.leadingTrivia[i];
var triviaStartLine = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos).line;
if (rangeContainsRange(originalRange, triviaItem)) {
switch (triviaItem.kind) {
case SyntaxKind.MultiLineCommentTrivia:
indentMultilineComment(triviaItem, indentation.getCommentIndentation(), /*firstLineIsIndented*/ !indentNextTokenOrTrivia);
indentMultilineComment(triviaItem, indentation.getBaseCommentIndentation(), /*firstLineIsIndented*/ !indentNextTokenOrTrivia);
indentNextTokenOrTrivia = false;
break;
case SyntaxKind.SingleLineCommentTrivia:
if (indentNextTokenOrTrivia) {
insertIndentation(triviaItem.pos, indentation.getCommentIndentation(), /*lineAdded*/ false);
insertIndentation(triviaItem.pos, indentation.getBaseCommentIndentation(), /*lineAdded*/ false);
indentNextTokenOrTrivia = false;
}
break;
@@ -472,7 +647,7 @@ module ts.formatting {
}
}
if (isTokenInRange) {
insertIndentation(currentTokenInfo.token.pos, indentation.getIndentation(), lineAdded);
insertIndentation(currentTokenInfo.token.pos, indentation.getEffectiveIndentation(tokenStart.line, currentTokenInfo.token.kind), lineAdded);
}
}

View File

@@ -296,8 +296,8 @@ module ts.formatting {
return column;
}
export function nodeContentIsAlwaysIndented(n: Node): boolean {
switch (n.kind) {
export function nodeContentIsAlwaysIndented(kind: SyntaxKind): boolean {
switch (kind) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
@@ -327,7 +327,7 @@ module ts.formatting {
}
export function shouldIndentChildNode(parent: Node, child: Node): boolean {
if (nodeContentIsAlwaysIndented(parent)) {
if (nodeContentIsAlwaysIndented(parent.kind)) {
return true;
}
switch (parent.kind) {