mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 12:51:30 -05:00
Merge pull request #752 from Microsoft/getTokenAtPosition
make rename\gotoDef work at the end of token
This commit is contained in:
@@ -2121,7 +2121,7 @@ module ts {
|
||||
}
|
||||
|
||||
// TODO: this is a hack for now, we need a proper walking mechanism to verify that we have the correct node
|
||||
var mappedNode = getNodeAtPosition(sourceFile, TypeScript.end(node) - 1);
|
||||
var mappedNode = getTouchingToken(sourceFile, TypeScript.end(node) - 1);
|
||||
if (isPunctuation(mappedNode.kind)) {
|
||||
mappedNode = mappedNode.parent;
|
||||
}
|
||||
@@ -2358,7 +2358,7 @@ module ts {
|
||||
|
||||
fileName = TypeScript.switchToForwardSlashes(fileName);
|
||||
var sourceFile = getSourceFile(fileName);
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingPropertyName(sourceFile, position);
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -2466,7 +2466,7 @@ module ts {
|
||||
|
||||
fileName = TypeScript.switchToForwardSlashes(fileName);
|
||||
var sourceFile = getSourceFile(fileName);
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingWord(sourceFile, position);
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -2549,7 +2549,7 @@ module ts {
|
||||
filename = TypeScript.switchToForwardSlashes(filename);
|
||||
var sourceFile = getSourceFile(filename);
|
||||
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingPropertyName(sourceFile, position);
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -2613,7 +2613,7 @@ module ts {
|
||||
filename = TypeScript.switchToForwardSlashes(filename);
|
||||
var sourceFile = getSourceFile(filename);
|
||||
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingWord(sourceFile, position);
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -3058,7 +3058,7 @@ module ts {
|
||||
filename = TypeScript.switchToForwardSlashes(filename);
|
||||
var sourceFile = getSourceFile(filename);
|
||||
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingPropertyName(sourceFile, position);
|
||||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -3241,7 +3241,7 @@ module ts {
|
||||
forEach(possiblePositions, position => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingWord(sourceFile, position);
|
||||
if (!node || node.getWidth() !== labelName.length) {
|
||||
return;
|
||||
}
|
||||
@@ -3297,7 +3297,7 @@ module ts {
|
||||
forEach(possiblePositions, position => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
var referenceLocation = getNodeAtPosition(sourceFile, position);
|
||||
var referenceLocation = getTouchingPropertyName(sourceFile, position);
|
||||
if (!isValidReferencePosition(referenceLocation, searchText)) {
|
||||
return;
|
||||
}
|
||||
@@ -3349,7 +3349,7 @@ module ts {
|
||||
forEach(possiblePositions, position => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingWord(sourceFile, position);
|
||||
|
||||
if (!node || node.kind !== SyntaxKind.SuperKeyword) {
|
||||
return;
|
||||
@@ -3415,7 +3415,7 @@ module ts {
|
||||
forEach(possiblePositions, position => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingWord(sourceFile, position);
|
||||
if (!node || node.kind !== SyntaxKind.ThisKeyword) {
|
||||
return;
|
||||
}
|
||||
@@ -4229,7 +4229,7 @@ module ts {
|
||||
var sourceFile = getCurrentSourceFile(filename);
|
||||
var result: TypeScript.TextSpan[] = [];
|
||||
|
||||
var token = getTokenAtPosition(sourceFile, position);
|
||||
var token = getTouchingToken(sourceFile, position);
|
||||
|
||||
if (token.getStart(sourceFile) === position) {
|
||||
var matchKind = getMatchingTokenKind(token);
|
||||
@@ -4513,7 +4513,7 @@ module ts {
|
||||
fileName = TypeScript.switchToForwardSlashes(fileName);
|
||||
var sourceFile = getSourceFile(fileName);
|
||||
|
||||
var node = getNodeAtPosition(sourceFile, position);
|
||||
var node = getTouchingWord(sourceFile, position);
|
||||
|
||||
// Can only rename an identifier.
|
||||
if (node && node.kind === SyntaxKind.Identifier) {
|
||||
|
||||
@@ -50,34 +50,54 @@ module ts {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** Get a token that contains the position. This is guaranteed to return a token, the position can be in the
|
||||
* leading trivia or within the token text.
|
||||
*/
|
||||
export function getTokenAtPosition(sourceFile: SourceFile, position: number) {
|
||||
var current: Node = sourceFile;
|
||||
outer: while (true) {
|
||||
// find the child that has this
|
||||
for (var i = 0, n = current.getChildCount(); i < n; i++) {
|
||||
var child = current.getChildAt(i);
|
||||
if (child.getFullStart() <= position && position < child.getEnd()) {
|
||||
current = child;
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
return current;
|
||||
}
|
||||
/* Gets the token whose text has range [start, end) and
|
||||
* position >= start and (position < end or (position === end && token is keyword or identifier))
|
||||
*/
|
||||
export function getTouchingWord(sourceFile: SourceFile, position: number): Node {
|
||||
return getTouchingToken(sourceFile, position, isWord);
|
||||
}
|
||||
|
||||
/** Get the token whose text contains the position, or the containing node. */
|
||||
export function getNodeAtPosition(sourceFile: SourceFile, position: number) {
|
||||
/* Gets the token whose text has range [start, end) and position >= start
|
||||
* and (position < end or (position === end && token is keyword or identifier or numeric\string litera))
|
||||
*/
|
||||
export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node {
|
||||
return getTouchingToken(sourceFile, position, isPropertyName);
|
||||
}
|
||||
|
||||
/** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */
|
||||
export function getTouchingToken(sourceFile: SourceFile, position: number, includeItemAtEndPosition?: (n: Node) => boolean): Node {
|
||||
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition);
|
||||
}
|
||||
|
||||
/** Returns a token if position is in [start-of-leading-trivia, end) */
|
||||
export function getTokenAtPosition(sourceFile: SourceFile, position: number): Node {
|
||||
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined);
|
||||
}
|
||||
|
||||
/** Get the token whose text contains the position */
|
||||
function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean): Node {
|
||||
var current: Node = sourceFile;
|
||||
outer: while (true) {
|
||||
// find the child that has this
|
||||
for (var i = 0, n = current.getChildCount(); i < n; i++) {
|
||||
if (isToken(current)) {
|
||||
// exit early
|
||||
return current;
|
||||
}
|
||||
|
||||
// find the child that contains 'position'
|
||||
for (var i = 0, n = current.getChildCount(sourceFile); i < n; i++) {
|
||||
var child = current.getChildAt(i);
|
||||
if (child.getStart() <= position && position < child.getEnd()) {
|
||||
current = child;
|
||||
continue outer;
|
||||
var start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile);
|
||||
if (start <= position) {
|
||||
if (position < child.getEnd()) {
|
||||
current = child;
|
||||
continue outer;
|
||||
}
|
||||
else if (includeItemAtEndPosition && child.getEnd() === position) {
|
||||
var previousToken = findPrecedingToken(position, sourceFile, child);
|
||||
if (previousToken && includeItemAtEndPosition(previousToken)) {
|
||||
return previousToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return current;
|
||||
@@ -130,8 +150,8 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function findPrecedingToken(position: number, sourceFile: SourceFile): Node {
|
||||
return find(sourceFile);
|
||||
export function findPrecedingToken(position: number, sourceFile: SourceFile, startNode?: Node): Node {
|
||||
return find(startNode || sourceFile);
|
||||
|
||||
function findRightmostToken(n: Node): Node {
|
||||
if (isToken(n)) {
|
||||
@@ -167,7 +187,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
Debug.assert(n.kind === SyntaxKind.SourceFile);
|
||||
Debug.assert(startNode || 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.
|
||||
@@ -205,4 +225,16 @@ module ts {
|
||||
function isToken(n: Node): boolean {
|
||||
return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
|
||||
}
|
||||
|
||||
function isKeyword(n: Node): boolean {
|
||||
return n.kind >= SyntaxKind.FirstKeyword && n.kind <= SyntaxKind.LastKeyword;
|
||||
}
|
||||
|
||||
function isWord(n: Node): boolean {
|
||||
return n.kind === SyntaxKind.Identifier || isKeyword(n);
|
||||
}
|
||||
|
||||
function isPropertyName(n: Node): boolean {
|
||||
return n.kind === SyntaxKind.StringLiteral || n.kind === SyntaxKind.NumericLiteral || isWord(n);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user