Move findPrecedingToken to ServicesSyntaxUtilities
This commit is contained in:
parent
49ae281059
commit
63f43e8352
4 changed files with 109 additions and 175 deletions
|
@ -2,13 +2,12 @@
|
||||||
|
|
||||||
module ts.formatting {
|
module ts.formatting {
|
||||||
export module SmartIndenter {
|
export module SmartIndenter {
|
||||||
|
|
||||||
export function getIndentation(position: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
export function getIndentation(position: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||||
if (position > sourceFile.text.length) {
|
if (position > sourceFile.text.length) {
|
||||||
return 0; // past EOF
|
return 0; // past EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
var precedingToken = findPrecedingToken(position, sourceFile);
|
var precedingToken = ServicesSyntaxUtilities.findPrecedingToken(position, sourceFile);
|
||||||
if (!precedingToken) {
|
if (!precedingToken) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +136,7 @@ module ts.formatting {
|
||||||
}
|
}
|
||||||
|
|
||||||
function nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken: Node, current: Node, lineAtPosition: number, sourceFile: SourceFile): boolean {
|
function nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken: Node, current: Node, lineAtPosition: number, sourceFile: SourceFile): boolean {
|
||||||
var nextToken = findNextToken(precedingToken, current);
|
var nextToken = ServicesSyntaxUtilities.findNextToken(precedingToken, current);
|
||||||
if (!nextToken) {
|
if (!nextToken) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -288,112 +287,6 @@ module ts.formatting {
|
||||||
return column;
|
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 {
|
function nodeContentIsIndented(parent: Node, child: Node): boolean {
|
||||||
switch (parent.kind) {
|
switch (parent.kind) {
|
||||||
case SyntaxKind.ClassDeclaration:
|
case SyntaxKind.ClassDeclaration:
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
/// <reference path='breakpoints.ts' />
|
/// <reference path='breakpoints.ts' />
|
||||||
/// <reference path='indentation.ts' />
|
/// <reference path='indentation.ts' />
|
||||||
/// <reference path='signatureInfoHelpers.ts' />
|
/// <reference path='signatureInfoHelpers.ts' />
|
||||||
|
/// <reference path='servicesSyntaxUtilities.ts' />
|
||||||
/// <reference path='formatting\formatting.ts' />
|
/// <reference path='formatting\formatting.ts' />
|
||||||
/// <reference path='formatting\smartIndenter.ts' />
|
/// <reference path='formatting\smartIndenter.ts' />
|
||||||
|
|
||||||
|
@ -3533,7 +3534,7 @@ module ts {
|
||||||
if (!isToken || position <= node.getStart() || position >= node.getEnd()) {
|
if (!isToken || position <= node.getStart() || position >= node.getEnd()) {
|
||||||
// This is a temporary hack until we figure out our token story.
|
// This is a temporary hack until we figure out our token story.
|
||||||
// The correct solution is to get the previous token
|
// The correct solution is to get the previous token
|
||||||
node = SignatureInfoHelpers.findPrecedingToken(position, sourceFile);
|
node = ServicesSyntaxUtilities.findPrecedingToken(position, sourceFile);
|
||||||
|
|
||||||
if (!node) {
|
if (!node) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|
105
src/services/servicesSyntaxUtilities.ts
Normal file
105
src/services/servicesSyntaxUtilities.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -345,70 +345,5 @@ module ts {
|
||||||
// return null;
|
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue