diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 0e37672f66da2..4d03aa640db35 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -1146,10 +1146,9 @@ namespace ts.formatting { export function getRangeOfEnclosingComment( sourceFile: SourceFile, position: number, - onlyMultiLine: boolean, precedingToken?: Node | null, // tslint:disable-line:no-null-keyword tokenAtPosition = getTokenAtPosition(sourceFile, position), - predicate?: (c: CommentRange) => boolean): CommentRange | undefined { + ): CommentRange | undefined { const jsdoc = findAncestor(tokenAtPosition, isJSDoc); if (jsdoc) tokenAtPosition = jsdoc.parent; const tokenStart = tokenAtPosition.getStart(sourceFile); @@ -1157,39 +1156,28 @@ namespace ts.formatting { return undefined; } - if (precedingToken === undefined) { - precedingToken = findPrecedingToken(position, sourceFile); - } + precedingToken = precedingToken === null ? undefined : precedingToken === undefined ? findPrecedingToken(position, sourceFile) : precedingToken; // Between two consecutive tokens, all comments are either trailing on the former // or leading on the latter (and none are in both lists). const trailingRangesOfPreviousToken = precedingToken && getTrailingCommentRanges(sourceFile.text, precedingToken.end); const leadingCommentRangesOfNextToken = getLeadingCommentRangesOfNode(tokenAtPosition, sourceFile); - const commentRanges = trailingRangesOfPreviousToken && leadingCommentRangesOfNextToken ? - trailingRangesOfPreviousToken.concat(leadingCommentRangesOfNextToken) : - trailingRangesOfPreviousToken || leadingCommentRangesOfNextToken; - if (commentRanges) { - for (const range of commentRanges) { - // The end marker of a single-line comment does not include the newline character. - // With caret at `^`, in the following case, we are inside a comment (^ denotes the cursor position): - // - // // asdf ^\n - // - // But for closed multi-line comments, we don't want to be inside the comment in the following case: - // - // /* asdf */^ - // - // However, unterminated multi-line comments *do* contain their end. - // - // Internally, we represent the end of the comment at the newline and closing '/', respectively. - // - if ((range.pos < position && position < range.end || - position === range.end && (range.kind === SyntaxKind.SingleLineCommentTrivia || position === sourceFile.getFullWidth()))) { - return (range.kind === SyntaxKind.MultiLineCommentTrivia || !onlyMultiLine) && (!predicate || predicate(range)) ? range : undefined; - } - } - } - return undefined; + const commentRanges = concatenate(trailingRangesOfPreviousToken, leadingCommentRangesOfNextToken); + return commentRanges && find(commentRanges, range => rangeContainsPositionExclusive(range, position) || + // The end marker of a single-line comment does not include the newline character. + // With caret at `^`, in the following case, we are inside a comment (^ denotes the cursor position): + // + // // asdf ^\n + // + // But for closed multi-line comments, we don't want to be inside the comment in the following case: + // + // /* asdf */^ + // + // However, unterminated multi-line comments *do* contain their end. + // + // Internally, we represent the end of the comment at the newline and closing '/', respectively. + // + position === range.end && (range.kind === SyntaxKind.SingleLineCommentTrivia || position === sourceFile.getFullWidth())); } function getOpenTokenForList(node: Node, list: ReadonlyArray) { diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index a03154df64217..b024d1f94d03a 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -34,8 +34,8 @@ namespace ts.formatting { const precedingToken = findPrecedingToken(position, sourceFile, /*startNode*/ undefined, /*excludeJsdoc*/ true); - const enclosingCommentRange = getRangeOfEnclosingComment(sourceFile, position, /*onlyMultiLine*/ true, precedingToken || null); // tslint:disable-line:no-null-keyword - if (enclosingCommentRange) { + const enclosingCommentRange = getRangeOfEnclosingComment(sourceFile, position, precedingToken || null); // tslint:disable-line:no-null-keyword + if (enclosingCommentRange && enclosingCommentRange.kind === SyntaxKind.MultiLineCommentTrivia) { return getCommentIndent(sourceFile, position, options, enclosingCommentRange); } diff --git a/src/services/services.ts b/src/services/services.ts index ac37317eebf91..67e1b710994d2 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -2049,8 +2049,8 @@ namespace ts { function getSpanOfEnclosingComment(fileName: string, position: number, onlyMultiLine: boolean): TextSpan | undefined { const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); - const range = formatting.getRangeOfEnclosingComment(sourceFile, position, onlyMultiLine); - return range && createTextSpanFromRange(range); + const range = formatting.getRangeOfEnclosingComment(sourceFile, position); + return range && (!onlyMultiLine || range.kind === SyntaxKind.MultiLineCommentTrivia) ? createTextSpanFromRange(range) : undefined; } function getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[] { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 300a1a0a2e024..a7453e070db67 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -1024,12 +1024,8 @@ namespace ts { * @param tokenAtPosition Must equal `getTokenAtPosition(sourceFile, position) * @param predicate Additional predicate to test on the comment range. */ - export function isInComment( - sourceFile: SourceFile, - position: number, - tokenAtPosition?: Node, - predicate?: (c: CommentRange) => boolean): boolean { - return !!formatting.getRangeOfEnclosingComment(sourceFile, position, /*onlyMultiLine*/ false, /*precedingToken*/ undefined, tokenAtPosition, predicate); + export function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition?: Node): CommentRange | undefined { + return formatting.getRangeOfEnclosingComment(sourceFile, position, /*precedingToken*/ undefined, tokenAtPosition); } export function hasDocComment(sourceFile: SourceFile, position: number): boolean { @@ -1140,17 +1136,16 @@ namespace ts { } export function isInReferenceComment(sourceFile: SourceFile, position: number): boolean { - return isInComment(sourceFile, position, /*tokenAtPosition*/ undefined, c => { - const commentText = sourceFile.text.substring(c.pos, c.end); - return tripleSlashDirectivePrefixRegex.test(commentText); - }); + return isInReferenceCommentWorker(sourceFile, position, /*shouldBeReference*/ true); } export function isInNonReferenceComment(sourceFile: SourceFile, position: number): boolean { - return isInComment(sourceFile, position, /*tokenAtPosition*/ undefined, c => { - const commentText = sourceFile.text.substring(c.pos, c.end); - return !tripleSlashDirectivePrefixRegex.test(commentText); - }); + return isInReferenceCommentWorker(sourceFile, position, /*shouldBeReference*/ false); + } + + function isInReferenceCommentWorker(sourceFile: SourceFile, position: number, shouldBeReference: boolean): boolean { + const range = isInComment(sourceFile, position, /*tokenAtPosition*/ undefined); + return !!range && shouldBeReference === tripleSlashDirectivePrefixRegex.test(sourceFile.text.substring(range.pos, range.end)); } export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile): TextSpan { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 1783064f309b3..b298c35e044dc 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -10784,7 +10784,7 @@ declare namespace ts { * @param tokenAtPosition Must equal `getTokenAtPosition(sourceFile, position) * @param predicate Additional predicate to test on the comment range. */ - function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition?: Node, predicate?: (c: CommentRange) => boolean): boolean; + function isInComment(sourceFile: SourceFile, position: number, tokenAtPosition?: Node): CommentRange | undefined; function hasDocComment(sourceFile: SourceFile, position: number): boolean; function getNodeModifiers(node: Node): string; function getTypeArgumentOrTypeParameterList(node: Node): NodeArray | undefined; @@ -11404,8 +11404,8 @@ declare namespace ts.formatting { /** * @param precedingToken pass `null` if preceding token was already computed and result was `undefined`. */ - function getRangeOfEnclosingComment(sourceFile: SourceFile, position: number, onlyMultiLine: boolean, precedingToken?: Node | null, // tslint:disable-line:no-null-keyword - tokenAtPosition?: Node, predicate?: (c: CommentRange) => boolean): CommentRange | undefined; + function getRangeOfEnclosingComment(sourceFile: SourceFile, position: number, precedingToken?: Node | null, // tslint:disable-line:no-null-keyword + tokenAtPosition?: Node): CommentRange | undefined; function getIndentationString(indentation: number, options: EditorSettings): string; } declare namespace ts.formatting {