From 63f43e8352a8098f480e447a1083d0edbc5d0074 Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Tue, 16 Sep 2014 13:21:22 -0700 Subject: [PATCH] Move findPrecedingToken to ServicesSyntaxUtilities --- src/services/formatting/smartIndenter.ts | 111 +---------------------- src/services/services.ts | 3 +- src/services/servicesSyntaxUtilities.ts | 105 +++++++++++++++++++++ src/services/signatureInfoHelpers.ts | 65 ------------- 4 files changed, 109 insertions(+), 175 deletions(-) create mode 100644 src/services/servicesSyntaxUtilities.ts diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index ad07f884cc..1e8c175937 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -2,13 +2,12 @@ module ts.formatting { export module SmartIndenter { - export function getIndentation(position: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number { if (position > sourceFile.text.length) { return 0; // past EOF } - var precedingToken = findPrecedingToken(position, sourceFile); + var precedingToken = ServicesSyntaxUtilities.findPrecedingToken(position, sourceFile); if (!precedingToken) { return 0; } @@ -137,7 +136,7 @@ module ts.formatting { } function nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken: Node, current: Node, lineAtPosition: number, sourceFile: SourceFile): boolean { - var nextToken = findNextToken(precedingToken, current); + var nextToken = ServicesSyntaxUtilities.findNextToken(precedingToken, current); if (!nextToken) { return false; } @@ -288,112 +287,6 @@ module ts.formatting { return column; } - function findNextToken(previousToken: Node, parent: Node): Node { - return find(parent); - - function find(n: Node): Node { - if (isToken(n) && n.pos === previousToken.end) { - // this is token that starts at the end of previous token - return it - return n; - } - - var children = n.getChildren(); - for (var i = 0, len = children.length; i < len; ++i) { - var child = children[i]; - var shouldDiveInChildNode = - // previous token is enclosed somewhere in the child - (child.pos <= previousToken.pos && child.end > previousToken.end) || - // previous token ends exactly at the beginning of child - (child.pos === previousToken.end); - - if (shouldDiveInChildNode && nodeHasTokens(child)) { - return find(child); - } - } - - return undefined; - } - } - - function findPrecedingToken(position: number, sourceFile: SourceFile): Node { - return find(sourceFile); - - function findRightmostToken(n: Node): Node { - if (isToken(n)) { - return n; - } - - var children = n.getChildren(); - var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); - return candidate && findRightmostToken(candidate); - - } - - function find(n: Node): Node { - if (isToken(n)) { - return n; - } - - var children = n.getChildren(); - for (var i = 0, len = children.length; i < len; ++i) { - var child = children[i]; - if (nodeHasTokens(child)) { - if (position < child.end) { - if (child.getStart(sourceFile) >= position) { - // actual start of the node is past the position - previous token should be at the end of previous child - var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i); - return candidate && findRightmostToken(candidate) - } - else { - // candidate should be in this node - return find(child); - } - } - } - } - - Debug.assert(n.kind === SyntaxKind.SourceFile); - - // Here we know that none of child token nodes embrace the position, - // the only known case is when position is at the end of the file. - // Try to find the rightmost token in the file without filtering. - // Namely we are skipping the check: 'position < node.end' - if (children.length) { - var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); - return candidate && findRightmostToken(candidate); - } - } - - /// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition' - function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number): Node { - for (var i = exclusiveStartPosition - 1; i >= 0; --i) { - if (nodeHasTokens(children[i])) { - return children[i]; - } - } - } - } - - /* - * Checks if node is something that can contain tokens (except EOF) - filters out EOF tokens, Missing\Omitted expressions, empty SyntaxLists and expression statements that wrap any of listed nodes. - */ - function nodeHasTokens(n: Node): boolean { - if (n.kind === SyntaxKind.ExpressionStatement) { - return nodeHasTokens((n).expression); - } - - if (n.kind === SyntaxKind.EndOfFileToken || n.kind === SyntaxKind.OmittedExpression || n.kind === SyntaxKind.Missing) { - return false; - } - - // SyntaxList is already realized so getChildCount should be fast and non-expensive - return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0; - } - - function isToken(n: Node): boolean { - return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken; - } - function nodeContentIsIndented(parent: Node, child: Node): boolean { switch (parent.kind) { case SyntaxKind.ClassDeclaration: diff --git a/src/services/services.ts b/src/services/services.ts index 6b9dbacda7..537144f9a9 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -11,6 +11,7 @@ /// /// /// +/// /// /// @@ -3533,7 +3534,7 @@ module ts { if (!isToken || position <= node.getStart() || position >= node.getEnd()) { // This is a temporary hack until we figure out our token story. // The correct solution is to get the previous token - node = SignatureInfoHelpers.findPrecedingToken(position, sourceFile); + node = ServicesSyntaxUtilities.findPrecedingToken(position, sourceFile); if (!node) { return undefined; diff --git a/src/services/servicesSyntaxUtilities.ts b/src/services/servicesSyntaxUtilities.ts new file mode 100644 index 0000000000..e6d7456826 --- /dev/null +++ b/src/services/servicesSyntaxUtilities.ts @@ -0,0 +1,105 @@ +// These utilities are common to multiple language service features. +module ts.ServicesSyntaxUtilities { + export function findNextToken(previousToken: Node, parent: Node): Node { + return find(parent); + + function find(n: Node): Node { + if (isToken(n) && n.pos === previousToken.end) { + // this is token that starts at the end of previous token - return it + return n; + } + + var children = n.getChildren(); + for (var i = 0, len = children.length; i < len; ++i) { + var child = children[i]; + var shouldDiveInChildNode = + // previous token is enclosed somewhere in the child + (child.pos <= previousToken.pos && child.end > previousToken.end) || + // previous token ends exactly at the beginning of child + (child.pos === previousToken.end); + + if (shouldDiveInChildNode && nodeHasTokens(child)) { + return find(child); + } + } + + return undefined; + } + } + + export function findPrecedingToken(position: number, sourceFile: SourceFile): Node { + return find(sourceFile); + + function findRightmostToken(n: Node): Node { + if (isToken(n)) { + return n; + } + + var children = n.getChildren(); + var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); + return candidate && findRightmostToken(candidate); + + } + + function find(n: Node): Node { + if (isToken(n)) { + return n; + } + + var children = n.getChildren(); + for (var i = 0, len = children.length; i < len; ++i) { + var child = children[i]; + if (nodeHasTokens(child)) { + if (position < child.end) { + if (child.getStart(sourceFile) >= position) { + // actual start of the node is past the position - previous token should be at the end of previous child + var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i); + return candidate && findRightmostToken(candidate) + } + else { + // candidate should be in this node + return find(child); + } + } + } + } + + Debug.assert(n.kind === SyntaxKind.SourceFile); + + // Here we know that none of child token nodes embrace the position, + // the only known case is when position is at the end of the file. + // Try to find the rightmost token in the file without filtering. + // Namely we are skipping the check: 'position < node.end' + if (children.length) { + var candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length); + return candidate && findRightmostToken(candidate); + } + } + + /// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition' + function findRightmostChildNodeWithTokens(children: Node[], exclusiveStartPosition: number): Node { + for (var i = exclusiveStartPosition - 1; i >= 0; --i) { + if (nodeHasTokens(children[i])) { + return children[i]; + } + } + } + } + + function nodeHasTokens(n: Node): boolean { + if (n.kind === SyntaxKind.ExpressionStatement) { + return nodeHasTokens((n).expression); + } + + if (n.kind === SyntaxKind.EndOfFileToken || n.kind === SyntaxKind.OmittedExpression || n.kind === SyntaxKind.Missing) { + return false; + } + + // SyntaxList is already realized so getChildCount should be fast and non-expensive + return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0; + } + + function isToken(n: Node): boolean { + return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken; + } +} \ No newline at end of file diff --git a/src/services/signatureInfoHelpers.ts b/src/services/signatureInfoHelpers.ts index 148e7af4f4..352cdb0295 100644 --- a/src/services/signatureInfoHelpers.ts +++ b/src/services/signatureInfoHelpers.ts @@ -345,70 +345,5 @@ module ts { // return null; //} - export function findPrecedingToken(position: number, sourceFile: SourceFile): Node { - return find(sourceFile, /*diveIntoLastChild*/ false); - - function find(n: Node, diveIntoLastChild: boolean): Node { - if (isToken(n)) { - return n; - } - - var children = n.getChildren(); - if (diveIntoLastChild) { - var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ children.length); - return candidate && find(candidate, /*diveIntoLastChild*/ true); - } - - for (var i = 0, len = children.length; i < len; ++i) { - var child = children[i]; - if (nodeHasTokens(child)) { - if (position < child.end) { - if (child.getStart() >= position) { - // actual start of the node is past the position - previous token should be at the end of previous child - var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ i); - return candidate && find(candidate, /*diveIntoLastChild*/ true) - } - else { - // candidate should be in this node - return find(child, diveIntoLastChild); - } - } - } - } - - // here we know that none of child token nodes embrace the position - // try to find the closest token on the left - if (children.length) { - var candidate = findLastChildNodeCandidate(children, /*exclusiveStartPosition*/ children.length); - return candidate && find(candidate, /*diveIntoLastChild*/ true); - } - } - - /// finds last node that is considered as candidate for search (isCandidate(node) === true) starting from 'exclusiveStartPosition' - function findLastChildNodeCandidate(children: Node[], exclusiveStartPosition: number): Node { - for (var i = exclusiveStartPosition - 1; i >= 0; --i) { - if (nodeHasTokens(children[i])) { - return children[i]; - } - } - } - - function isToken(n: Node): boolean { - return n.kind < SyntaxKind.Missing; - } - - function nodeHasTokens(n: Node): boolean { - if (n.kind === SyntaxKind.ExpressionStatement) { - return nodeHasTokens((n).expression); - } - - if (n.kind === SyntaxKind.EndOfFileToken || n.kind === SyntaxKind.OmittedExpression || n.kind === SyntaxKind.Missing) { - return false; - } - - // SyntaxList is already realized so getChildCount should be fast and non-expensive - return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0; - } - } } } \ No newline at end of file