diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 07aacf3c8a7..aa3097debad 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2427,6 +2427,16 @@ namespace FourSlash { } } + public verifyIsInMultiLineComment(negative: boolean) { + const expected = !negative; + const position = this.currentCaretPosition; + const fileName = this.activeFile.fileName; + const actual = this.languageService.getIsInMultiLineComment(fileName, position); + if (expected !== actual) { + this.raiseError(`verifyIsInDocComment failed: at position '${position}' in '${fileName}', expected '${expected}'.`); + } + } + private clarifyNewlines(str: string) { return str.replace(/\r?\n/g, lineEnding => { const representation = lineEnding === "\r\n" ? "CRLF" : "LF"; @@ -3577,6 +3587,10 @@ namespace FourSlashInterface { this.state.verifyCodeFixAvailable(this.negative); } + public isInMultiLineComment() { + this.state.verifyIsInMultiLineComment(this.negative); + } + public applicableRefactorAvailableAtMarker(markerName: string) { this.state.verifyApplicableRefactorAvailableAtMarker(this.negative, markerName); } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 7aefb0f3a1f..c67dde5f67b 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -483,6 +483,9 @@ namespace Harness.LanguageService { getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion { return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position)); } + getIsInMultiLineComment(fileName: string, position: number): boolean { + return unwrapJSONCallResult(this.shim.getIsInMultiLineComment(fileName, position)); + } isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean { return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPosition(fileName, position, openingBrace)); } diff --git a/src/server/client.ts b/src/server/client.ts index aca52422e44..69727a18e60 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -672,6 +672,10 @@ namespace ts.server { return notImplemented(); } + getIsInMultiLineComment(_fileName: string, _position: number): boolean { + return notImplemented(); + } + isValidBraceCompletionAtPosition(_fileName: string, _position: number, _openingBrace: number): boolean { return notImplemented(); } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 4e474edd0c4..1cfe617ca72 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -85,6 +85,7 @@ namespace ts.server.protocol { TodoComments = "todoComments", Indentation = "indentation", DocCommentTemplate = "docCommentTemplate", + IsInMultiLineComment = "isInMultiLineComment", /* @internal */ CompilerOptionsDiagnosticsFull = "compilerOptionsDiagnostics-full", /* @internal */ @@ -238,6 +239,20 @@ namespace ts.server.protocol { body?: TodoComment[]; } + /** + * A request to determine if the caret is inside a multi-line comment. + */ + export interface IsInMultiLineCommentRequest extends FileLocationRequest { + command: CommandTypes.IsInMultiLineComment; + } + + /** + * Response for TodoCommentRequest request. + */ + export interface IsInMultiLineCommentResponse extends Response { + body?: { isInMultiLineComment: boolean }; + } + /** * Request to obtain outlining spans in file. */ diff --git a/src/server/session.ts b/src/server/session.ts index 6ec234952db..abebdb5fae9 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -961,6 +961,13 @@ namespace ts.server { return project.getLanguageService(/*ensureSynchronized*/ false).getDocCommentTemplateAtPosition(file, position); } + private getIsInMultiLineComment(args: protocol.FileLocationRequestArgs) { + const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args); + const scriptInfo = project.getScriptInfoForNormalizedPath(file); + const position = this.getPosition(args, scriptInfo); + return project.getLanguageService(/*ensureSynchronized*/ false).getIsInMultiLineComment(file, position); + } + private getIndentation(args: protocol.IndentationRequestArgs) { const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args); const position = this.getPosition(args, project.getScriptInfoForNormalizedPath(file)); @@ -1694,6 +1701,9 @@ namespace ts.server { [CommandNames.DocCommentTemplate]: (request: protocol.DocCommentTemplateRequest) => { return this.requiredResponse(this.getDocCommentTemplate(request.arguments)); }, + [CommandNames.IsInMultiLineComment]: (request: protocol.IsInMultiLineCommentRequest) => { + return this.requiredResponse(this.getIsInMultiLineComment(request.arguments)); + }, [CommandNames.Format]: (request: protocol.FormatRequest) => { return this.requiredResponse(this.getFormattingEditsForRange(request.arguments)); }, diff --git a/src/services/services.ts b/src/services/services.ts index 21c756a9acc..8da654140e0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1789,6 +1789,16 @@ namespace ts { return JsDoc.getDocCommentTemplateAtPosition(getNewLineOrDefaultFromHost(host), syntaxTreeCache.getCurrentSourceFile(fileName), position); } + function getIsInMultiLineComment(_fileName: string, position: number): boolean { + const sourceFile = syntaxTreeCache.getCurrentSourceFile(_fileName); + const token = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ true); + const _triviaWidth = token.getLeadingTriviaWidth(sourceFile); _triviaWidth; + const _text = token.getText(sourceFile); _text; + const _fullText = token.getFullText(sourceFile); _fullText; + // TODO: distinguish multi-line and single line comments... + return token.getFullStart() <= position && position < token.getStart(sourceFile, /*includeJsDocComment*/ false); + } + function isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean { // '<' is currently not supported, figuring out if we're in a Generic Type vs. a comparison is too // expensive to do during typing scenarios @@ -2039,6 +2049,7 @@ namespace ts { getFormattingEditsForDocument, getFormattingEditsAfterKeystroke, getDocCommentTemplateAtPosition, + getIsInMultiLineComment, isValidBraceCompletionAtPosition, getCodeFixesAtPosition, getEmitOutput, diff --git a/src/services/shims.ts b/src/services/shims.ts index 498c1834a60..3ce553d552e 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -247,6 +247,11 @@ namespace ts { */ getDocCommentTemplateAtPosition(fileName: string, position: number): string; + /** + * Returns JSON-encoded value of the type TextInsertion. + */ + getIsInMultiLineComment(fileName: string, position: number): string; + /** * Returns JSON-encoded boolean to indicate whether we should support brace location * at the current position. @@ -935,6 +940,13 @@ namespace ts { ); } + public getIsInMultiLineComment(fileName: string, position: number): string { + return this.forwardJSONCall( + `getIsInMultiLineComment('${fileName}', ${position})`, + () => this.languageService.getIsInMultiLineComment(fileName, position) + ); + } + /// NAVIGATE TO /** Return a list of symbols that are interesting to navigate to */ diff --git a/src/services/types.ts b/src/services/types.ts index e042276e650..62d2db1b65c 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -257,6 +257,7 @@ namespace ts { getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[]; getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion; + getIsInMultiLineComment(fileName: string, position: number): boolean; isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 3e80b005625..3984a074fd9 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -150,6 +150,7 @@ declare namespace FourSlashInterface { implementationListIsEmpty(): void; isValidBraceCompletionAtPosition(openingBrace?: string): void; codeFixAvailable(): void; + isInMultiLineComment(): void; applicableRefactorAvailableAtMarker(markerName: string): void; codeFixDiagnosticsAvailableAtMarkers(markerNames: string[], diagnosticCode?: number): void; applicableRefactorAvailableForRange(): void; diff --git a/tests/cases/fourslash/isInMultiLineComment.ts b/tests/cases/fourslash/isInMultiLineComment.ts new file mode 100644 index 00000000000..4d6c8d6af1a --- /dev/null +++ b/tests/cases/fourslash/isInMultiLineComment.ts @@ -0,0 +1,6 @@ +/// + +//// /* blach /*m0*/ */ let x = 10; + +goTo.marker("m0"); +verify.isInMultiLineComment(); \ No newline at end of file