Services utilities: Combine isInsideComment
with isInComment
This commit is contained in:
parent
278fb803b1
commit
0defde7185
3 changed files with 30 additions and 60 deletions
|
@ -359,7 +359,7 @@ namespace ts.Completions {
|
||||||
|
|
||||||
start = timestamp();
|
start = timestamp();
|
||||||
// Completion not allowed inside comments, bail out if this is the case
|
// Completion not allowed inside comments, bail out if this is the case
|
||||||
const insideComment = isInsideComment(sourceFile, currentToken, position);
|
const insideComment = isInComment(sourceFile, position, currentToken);
|
||||||
log("getCompletionData: Is inside comment: " + (timestamp() - start));
|
log("getCompletionData: Is inside comment: " + (timestamp() - start));
|
||||||
|
|
||||||
if (insideComment) {
|
if (insideComment) {
|
||||||
|
|
|
@ -1853,8 +1853,8 @@ namespace ts {
|
||||||
|
|
||||||
// OK, we have found a match in the file. This is only an acceptable match if
|
// OK, we have found a match in the file. This is only an acceptable match if
|
||||||
// it is contained within a comment.
|
// it is contained within a comment.
|
||||||
const token = getTokenAtPosition(sourceFile, matchPosition);
|
|
||||||
if (!isInsideComment(sourceFile, token, matchPosition)) {
|
if (!isInComment(sourceFile, matchPosition)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -256,37 +256,6 @@ namespace ts {
|
||||||
getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node;
|
getExternalModuleImportEqualsDeclarationExpression(node.parent.parent) === node;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns true if the position is within a comment */
|
|
||||||
export function isInsideComment(sourceFile: SourceFile, token: Node, position: number): boolean {
|
|
||||||
// The position has to be: 1. in the leading trivia (before token.getStart()), and 2. within a comment
|
|
||||||
return position <= token.getStart(sourceFile) &&
|
|
||||||
(isInsideCommentRange(getTrailingCommentRanges(sourceFile.text, token.getFullStart())) ||
|
|
||||||
isInsideCommentRange(getLeadingCommentRanges(sourceFile.text, token.getFullStart())));
|
|
||||||
|
|
||||||
function isInsideCommentRange(comments: CommentRange[]): boolean {
|
|
||||||
return forEach(comments, comment => {
|
|
||||||
// either we are 1. completely inside the comment, or 2. at the end of the comment
|
|
||||||
if (comment.pos < position && position < comment.end) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (position === comment.end) {
|
|
||||||
const text = sourceFile.text;
|
|
||||||
const width = comment.end - comment.pos;
|
|
||||||
// is single line comment or just /*
|
|
||||||
if (width <= 2 || text.charCodeAt(comment.pos + 1) === CharacterCodes.slash) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// is unterminated multi-line comment
|
|
||||||
return !(text.charCodeAt(comment.end - 1) === CharacterCodes.slash &&
|
|
||||||
text.charCodeAt(comment.end - 2) === CharacterCodes.asterisk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getContainerNode(node: Node): Declaration {
|
export function getContainerNode(node: Node): Declaration {
|
||||||
while (true) {
|
while (true) {
|
||||||
node = node.parent;
|
node = node.parent;
|
||||||
|
@ -834,10 +803,6 @@ namespace ts {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInComment(sourceFile: SourceFile, position: number) {
|
|
||||||
return isInCommentHelper(sourceFile, position, /*predicate*/ undefined);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns true if the position is in between the open and close elements of an JSX expression.
|
* returns true if the position is in between the open and close elements of an JSX expression.
|
||||||
*/
|
*/
|
||||||
|
@ -883,15 +848,26 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the cursor at position in sourceFile is within a comment that additionally
|
* Returns true if the cursor at position in sourceFile is within a comment.
|
||||||
* satisfies predicate, and false otherwise.
|
*
|
||||||
|
* @param tokenAtPosition Must equal `getTokenAtPosition(sourceFile, position)
|
||||||
|
* @param predicate Additional predicate to test on the comment range.
|
||||||
*/
|
*/
|
||||||
export function isInCommentHelper(sourceFile: SourceFile, position: number, predicate?: (c: CommentRange) => boolean): boolean {
|
export function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition = getTokenAtPosition(sourceFile, position), predicate?: (c: CommentRange) => boolean): boolean {
|
||||||
const token = getTokenAtPosition(sourceFile, position);
|
return position <= tokenAtPosition.getStart(sourceFile) &&
|
||||||
|
(isInCommentRange(getLeadingCommentRanges(sourceFile.text, tokenAtPosition.pos)) ||
|
||||||
|
isInCommentRange(getTrailingCommentRanges(sourceFile.text, tokenAtPosition.pos)));
|
||||||
|
|
||||||
if (token && position <= token.getStart(sourceFile)) {
|
function isInCommentRange(commentRanges: CommentRange[]): boolean {
|
||||||
const commentRanges = getLeadingCommentRanges(sourceFile.text, token.pos);
|
return forEach(commentRanges, c => isPositionInCommentRange(c, position, sourceFile.text) && (!predicate || predicate(c)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPositionInCommentRange({ pos, end, kind }: ts.CommentRange, position: number, text: string): boolean {
|
||||||
|
if (pos < position && position < end) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (position === end) {
|
||||||
// The end marker of a single-line comment does not include the newline character.
|
// The end marker of a single-line comment does not include the newline character.
|
||||||
// In the following case, we are inside a comment (^ denotes the cursor position):
|
// In the following case, we are inside a comment (^ denotes the cursor position):
|
||||||
//
|
//
|
||||||
|
@ -902,15 +878,13 @@ namespace ts {
|
||||||
// /* asdf */^
|
// /* asdf */^
|
||||||
//
|
//
|
||||||
// Internally, we represent the end of the comment at the newline and closing '/', respectively.
|
// Internally, we represent the end of the comment at the newline and closing '/', respectively.
|
||||||
return predicate ?
|
return kind === SyntaxKind.SingleLineCommentTrivia ||
|
||||||
forEach(commentRanges, c => c.pos < position &&
|
// true for unterminated multi-line comment
|
||||||
(c.kind === SyntaxKind.SingleLineCommentTrivia ? position <= c.end : position < c.end) &&
|
!(text.charCodeAt(end - 1) === CharacterCodes.slash && text.charCodeAt(end - 2) === CharacterCodes.asterisk);
|
||||||
predicate(c)) :
|
}
|
||||||
forEach(commentRanges, c => c.pos < position &&
|
else {
|
||||||
(c.kind === SyntaxKind.SingleLineCommentTrivia ? position <= c.end : position < c.end));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasDocComment(sourceFile: SourceFile, position: number) {
|
export function hasDocComment(sourceFile: SourceFile, position: number) {
|
||||||
|
@ -1093,21 +1067,17 @@ namespace ts {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInReferenceComment(sourceFile: SourceFile, position: number): boolean {
|
export function isInReferenceComment(sourceFile: SourceFile, position: number): boolean {
|
||||||
return isInCommentHelper(sourceFile, position, isReferenceComment);
|
return isInComment(sourceFile, position, /*tokenAtPosition*/ undefined, c => {
|
||||||
|
|
||||||
function isReferenceComment(c: CommentRange): boolean {
|
|
||||||
const commentText = sourceFile.text.substring(c.pos, c.end);
|
const commentText = sourceFile.text.substring(c.pos, c.end);
|
||||||
return tripleSlashDirectivePrefixRegex.test(commentText);
|
return tripleSlashDirectivePrefixRegex.test(commentText);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isInNonReferenceComment(sourceFile: SourceFile, position: number): boolean {
|
export function isInNonReferenceComment(sourceFile: SourceFile, position: number): boolean {
|
||||||
return isInCommentHelper(sourceFile, position, isNonReferenceComment);
|
return isInComment(sourceFile, position, /*tokenAtPosition*/ undefined, c => {
|
||||||
|
|
||||||
function isNonReferenceComment(c: CommentRange): boolean {
|
|
||||||
const commentText = sourceFile.text.substring(c.pos, c.end);
|
const commentText = sourceFile.text.substring(c.pos, c.end);
|
||||||
return !tripleSlashDirectivePrefixRegex.test(commentText);
|
return !tripleSlashDirectivePrefixRegex.test(commentText);
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile): TextSpan {
|
export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile): TextSpan {
|
||||||
|
|
Loading…
Reference in a new issue