diff --git a/src/services/smartIndenter.ts b/src/services/smartIndenter.ts index 8e3208c21e5..7a56ea07be3 100644 --- a/src/services/smartIndenter.ts +++ b/src/services/smartIndenter.ts @@ -13,8 +13,8 @@ module ts.formatting { } // no indentation in string \regex literals - if ((precedingToken.kind === SyntaxKind.StringLiteral || precedingToken.kind === SyntaxKind.RegularExpressionLiteral) && - precedingToken.getStart(sourceFile) <= position && + if ((precedingToken.kind === SyntaxKind.StringLiteral || precedingToken.kind === SyntaxKind.RegularExpressionLiteral) && + precedingToken.getStart(sourceFile) <= position && precedingToken.end > position) { return 0; } @@ -59,7 +59,7 @@ module ts.formatting { previous = current; current = current.parent; } - + if (!current) { // no parent was found - return 0 to be indented on the level of SourceFile return 0; @@ -100,9 +100,9 @@ module ts.formatting { return actualIndentation + indentationDelta; } } - parentStart = sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile)); - var parentAndChildShareLine = - parentStart.line === currentStart.line || + parentStart = getParentStart(parent, current, sourceFile); + var parentAndChildShareLine = + parentStart.line === currentStart.line || childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile); if (useActualIndentation) { @@ -127,9 +127,18 @@ module ts.formatting { } + function getParentStart(parent: Node, child: Node, sourceFile: SourceFile): LineAndCharacter { + var containingList = getContainingList(child, sourceFile); + if (containingList) { + return sourceFile.getLineAndCharacterFromPosition(containingList.pos); + } + + return sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile)); + } + /* * Function returns -1 if indentation cannot be determined - */ + */ function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorOptions): number { // previous token is comma that separates items in list - find the previous item and try to derive indentation from it var commaItemInfo = findListItemInfo(commaToken); @@ -141,20 +150,20 @@ module ts.formatting { /* * Function returns -1 if actual indentation for node should not be used (i.e because node is nested expression) */ - function getActualIndentationForNode(current: Node, - parent: Node, - currentLineAndChar: LineAndCharacter, - parentAndChildShareLine: boolean, - sourceFile: SourceFile, - options: EditorOptions): number { + function getActualIndentationForNode(current: Node, + parent: Node, + currentLineAndChar: LineAndCharacter, + parentAndChildShareLine: boolean, + sourceFile: SourceFile, + options: EditorOptions): number { // actual indentation is used for statements\declarations if one of cases below is true: // - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually // - parent and child are not on the same line - var useActualIndentation = + var useActualIndentation = (isDeclaration(current) || isStatement(current)) && (parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine); - + if (!useActualIndentation) { return -1; } @@ -167,7 +176,7 @@ module ts.formatting { if (!nextToken) { return false; } - + if (nextToken.kind === SyntaxKind.OpenBraceToken) { // open braces are always indented at the parent level return true; @@ -202,27 +211,25 @@ module ts.formatting { var elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile); Debug.assert(elseKeyword !== undefined); - var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line; + var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line; return elseKeywordStartLine === childStartLine; } return false; } - function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorOptions): number { + function getContainingList(node: Node, sourceFile: SourceFile): NodeArray { if (node.parent) { switch (node.parent.kind) { case SyntaxKind.TypeReference: if ((node.parent).typeArguments) { - return getActualIndentationFromList((node.parent).typeArguments); + return (node.parent).typeArguments; } break; case SyntaxKind.ObjectLiteral: - return getActualIndentationFromList((node.parent).properties); - //case SyntaxKind.TypeLiteral: - // return getActualIndentationFromList((node.parent).members); + return (node.parent).properties; case SyntaxKind.ArrayLiteral: - return getActualIndentationFromList((node.parent).elements); + return (node.parent).elements; case SyntaxKind.FunctionDeclaration: case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: @@ -230,21 +237,26 @@ module ts.formatting { case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: if ((node.parent).typeParameters && node.end < (node.parent).typeParameters.end) { - return getActualIndentationFromList((node.parent).typeParameters); + return (node.parent).typeParameters; } - - return getActualIndentationFromList((node.parent).parameters); + + return (node.parent).parameters; case SyntaxKind.NewExpression: case SyntaxKind.CallExpression: if ((node.parent).typeArguments && node.end < (node.parent).typeArguments.end) { - return getActualIndentationFromList((node.parent).typeArguments); + return (node.parent).typeArguments; } - - return getActualIndentationFromList((node.parent).arguments); + + return (node.parent).arguments; } } - return -1; + return undefined; + } + + function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorOptions): number { + var containingList = getContainingList(node, sourceFile); + return containingList ? getActualIndentationFromList(containingList) : -1; function getActualIndentationFromList(list: Node[]): number { var index = indexOf(list, node); @@ -259,7 +271,7 @@ module ts.formatting { // walk toward the start of the list starting from current node and check if the line is the same for all items. // if end line for item [i - 1] differs from the start line for item [i] - find column of the first non-whitespace character on the line of item [i] - var lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile); + var lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile); for (var i = index - 1; i >= 0; --i) { if (list[i].kind === SyntaxKind.CommaToken) { continue; @@ -401,7 +413,7 @@ module ts.formatting { if ((n).elseStatement) { return isCompletedNode((n).elseStatement, sourceFile); } - return isCompletedNode((n).thenStatement, sourceFile); + return isCompletedNode((n).thenStatement, sourceFile); case SyntaxKind.ExpressionStatement: return isCompletedNode((n).expression, sourceFile); case SyntaxKind.ArrayLiteral: @@ -417,10 +429,10 @@ module ts.formatting { case SyntaxKind.DoStatement: // rough approximation: if DoStatement has While keyword - then if node is completed is checking the presence of ')'; var hasWhileKeyword = findChildOfKind(n, SyntaxKind.WhileKeyword, sourceFile); - if(hasWhileKeyword) { + if (hasWhileKeyword) { return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile); } - return isCompletedNode((n).statement, sourceFile); + return isCompletedNode((n).statement, sourceFile); default: return true; } diff --git a/tests/cases/fourslash/smartIndentStartLineInLists.ts b/tests/cases/fourslash/smartIndentStartLineInLists.ts new file mode 100644 index 00000000000..0150881ff34 --- /dev/null +++ b/tests/cases/fourslash/smartIndentStartLineInLists.ts @@ -0,0 +1,8 @@ +/// +////foo(function () { +////}).then(function () {/*1*/ +////}) + +goTo.marker("1"); +edit.insert("\r\n"); +verify.indentationIs(4); \ No newline at end of file