From cd19a8910d9848fc48abc2b89938fe6c372ef7a3 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 30 May 2017 03:11:07 +0900 Subject: [PATCH] add getListByPosition --- src/services/formatting/smartIndenter.ts | 113 ++++++++++++++--------- 1 file changed, 69 insertions(+), 44 deletions(-) diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index ca94e143a62..8cd95e04de8 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -315,60 +315,85 @@ namespace ts.formatting { return false; } + function getListIfVisualStartEndIsInListRange(list: NodeArray | undefined, start: number, end: number, node: Node) { + return list && rangeContainsVisualStartEnd(list) ? list : undefined; + + // Assumes a list is wrapped by list tokens + function rangeContainsVisualStartEnd(textRange: TextRange): boolean { + const children = node.getChildren(); + for (let i = 1; i < children.length - 1; i++) { + if (children[i].pos === textRange.pos && children[i].end === textRange.end) { + return rangeContainsStartEnd({ pos: children[i - 1].end, end: children[i + 1].end - children[i + 1].getWidth() }, start, end); + } + } + return rangeContainsStartEnd(textRange, start, end); + } + } + function getListIfStartEndIsInListRange(list: NodeArray | undefined, start: number, end: number) { return list && rangeContainsStartEnd(list, start, end) ? list : undefined; } export function getContainingList(node: Node, sourceFile: SourceFile): NodeArray | undefined { if (node.parent) { - const { end } = node; - switch (node.parent.kind) { - case SyntaxKind.TypeReference: - return getListIfStartEndIsInListRange((node.parent).typeArguments, node.getStart(sourceFile), end); - case SyntaxKind.ObjectLiteralExpression: - return (node.parent).properties; - case SyntaxKind.ArrayLiteralExpression: - return (node.parent).elements; - case SyntaxKind.FunctionDeclaration: - case SyntaxKind.FunctionExpression: - case SyntaxKind.ArrowFunction: - case SyntaxKind.MethodDeclaration: - case SyntaxKind.MethodSignature: - case SyntaxKind.CallSignature: - case SyntaxKind.Constructor: - case SyntaxKind.ConstructorType: - case SyntaxKind.ConstructSignature: { - const start = node.getStart(sourceFile); - return getListIfStartEndIsInListRange((node.parent).typeParameters, start, end) || - getListIfStartEndIsInListRange((node.parent).parameters, start, end); - } - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: - case SyntaxKind.InterfaceDeclaration: - case SyntaxKind.TypeAliasDeclaration: - case SyntaxKind.JSDocTemplateTag: { - const { typeParameters } = node.parent; - return getListIfStartEndIsInListRange(typeParameters, node.getStart(sourceFile), end); - } - case SyntaxKind.NewExpression: - case SyntaxKind.CallExpression: { - const start = node.getStart(sourceFile); - return getListIfStartEndIsInListRange((node.parent).typeArguments, start, end) || - getListIfStartEndIsInListRange((node.parent).arguments, start, end); - } - case SyntaxKind.VariableDeclarationList: - return getListIfStartEndIsInListRange((node.parent).declarations, node.getStart(sourceFile), end); - case SyntaxKind.NamedImports: - case SyntaxKind.NamedExports: - return getListIfStartEndIsInListRange((node.parent).elements, node.getStart(sourceFile), end); - case SyntaxKind.ObjectBindingPattern: - case SyntaxKind.ArrayBindingPattern: - return getListIfStartEndIsInListRange((node.parent).elements, node.getStart(sourceFile), end); - } + return getListByRange(node.getStart(sourceFile), node.getEnd(), node.parent); } return undefined; } + function getListByPosition(pos: number, node: Node): NodeArray | undefined { + if (!node) { + return; + } + return getListByRange(pos, pos, node); + } + + function getListByRange(start: number, end: number, node: Node): NodeArray | undefined { + switch (node.kind) { + case SyntaxKind.TypeReference: + return getListIfVisualStartEndIsInListRange((node).typeArguments, start, end, node); + case SyntaxKind.ObjectLiteralExpression: + return getListIfVisualStartEndIsInListRange((node).properties, start, end, node); + case SyntaxKind.ArrayLiteralExpression: + return getListIfVisualStartEndIsInListRange((node).elements, start, end, node); + case SyntaxKind.TypeLiteral: + return getListIfVisualStartEndIsInListRange((node).members, start, end, node); + case SyntaxKind.FunctionDeclaration: + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + case SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodSignature: + case SyntaxKind.CallSignature: + case SyntaxKind.Constructor: + case SyntaxKind.ConstructorType: + case SyntaxKind.ConstructSignature: { + return getListIfVisualStartEndIsInListRange((node).typeParameters, start, end, node) || + getListIfVisualStartEndIsInListRange((node).parameters, start, end, node); + } + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.TypeAliasDeclaration: + case SyntaxKind.JSDocTemplateTag: { + const { typeParameters } = node; + return getListIfStartEndIsInListRange(typeParameters, start, end); + } + case SyntaxKind.NewExpression: + case SyntaxKind.CallExpression: { + return getListIfVisualStartEndIsInListRange((node).typeArguments, start, end, node) || + getListIfVisualStartEndIsInListRange((node).arguments, start, end, node); + } + case SyntaxKind.VariableDeclarationList: + return getListIfStartEndIsInListRange((node).declarations, start, end); + case SyntaxKind.NamedImports: + case SyntaxKind.NamedExports: + return getListIfVisualStartEndIsInListRange((node).elements, start, end, node); + case SyntaxKind.ObjectBindingPattern: + case SyntaxKind.ArrayBindingPattern: + return getListIfVisualStartEndIsInListRange((node).elements, start, end, node); + } + } + function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorSettings): number { const containingList = getContainingList(node, sourceFile); if (containingList) {