Move findPrecedingToken to ServicesSyntaxUtilities

This commit is contained in:
Jason Freeman 2014-09-16 13:21:22 -07:00
parent 49ae281059
commit 63f43e8352
4 changed files with 109 additions and 175 deletions

View file

@ -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((<ExpressionStatement>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:

View file

@ -11,6 +11,7 @@
/// <reference path='breakpoints.ts' />
/// <reference path='indentation.ts' />
/// <reference path='signatureInfoHelpers.ts' />
/// <reference path='servicesSyntaxUtilities.ts' />
/// <reference path='formatting\formatting.ts' />
/// <reference path='formatting\smartIndenter.ts' />
@ -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;

View file

@ -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((<ExpressionStatement>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;
}
}

View file

@ -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((<ExpressionStatement>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;
}
}
}
}