Skip to content

Commit 8751840

Browse files
authored
fix(server): Respect the client capabilities "textDocument.{declaration,typeDefinition}.linkSupport." (#1875)
If the client doesn't explicitly tells the server that they have this capability then a `Location` should be send instead of `LocationLink` as a reply to a "Goto Declaration Request". See the relevant documentation: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_declaration
1 parent e9c2438 commit 8751840

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

integration/lsp/test_utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ export function initializeServer(client: MessageConnection): Promise<lsp.Initial
7373
}
7474
},
7575
moniker: {},
76+
definition: {linkSupport: true},
77+
typeDefinition: {linkSupport: true}
7678
}
7779
},
7880
/**

server/src/session.ts

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -856,7 +856,8 @@ export class Session {
856856
return htmlLS.getFoldingRanges(virtualHtmlDoc);
857857
}
858858

859-
private onDefinition(params: lsp.TextDocumentPositionParams): lsp.LocationLink[]|null {
859+
private onDefinition(params: lsp.TextDocumentPositionParams):
860+
lsp.Location[]|lsp.LocationLink[]|null {
860861
const lsInfo = this.getLSAndScriptInfo(params.textDocument);
861862
if (lsInfo === null) {
862863
return null;
@@ -867,11 +868,20 @@ export class Session {
867868
if (!definition || !definition.definitions) {
868869
return null;
869870
}
871+
872+
const clientSupportsLocationLinks =
873+
this.clientCapabilities.textDocument?.definition?.linkSupport ?? false;
874+
875+
if (!clientSupportsLocationLinks) {
876+
return this.tsDefinitionsToLspLocations(definition.definitions);
877+
}
878+
870879
const originSelectionRange = tsTextSpanToLspRange(scriptInfo, definition.textSpan);
871880
return this.tsDefinitionsToLspLocationLinks(definition.definitions, originSelectionRange);
872881
}
873882

874-
private onTypeDefinition(params: lsp.TextDocumentPositionParams): lsp.LocationLink[]|null {
883+
private onTypeDefinition(params: lsp.TextDocumentPositionParams):
884+
lsp.Location[]|lsp.LocationLink[]|null {
875885
const lsInfo = this.getLSAndScriptInfo(params.textDocument);
876886
if (lsInfo === null) {
877887
return null;
@@ -882,6 +892,14 @@ export class Session {
882892
if (!definitions) {
883893
return null;
884894
}
895+
896+
const clientSupportsLocationLinks =
897+
this.clientCapabilities.textDocument?.typeDefinition?.linkSupport ?? false;
898+
899+
if (!clientSupportsLocationLinks) {
900+
return this.tsDefinitionsToLspLocations(definitions);
901+
}
902+
885903
return this.tsDefinitionsToLspLocationLinks(definitions);
886904
}
887905

@@ -965,6 +983,40 @@ export class Session {
965983
});
966984
}
967985

986+
private tsDefinitionsToLspLocations(definitions: readonly ts.DefinitionInfo[]): lsp.Location[] {
987+
const results: lsp.Location[] = [];
988+
for (const d of definitions) {
989+
const scriptInfo = this.projectService.getScriptInfo(d.fileName);
990+
991+
// Some definitions, like definitions of CSS files, may not be recorded files with a
992+
// `scriptInfo` but are still valid definitions because they are files that exist. In this
993+
// case, check to make sure that the text span of the definition is zero so that the file
994+
// doesn't have to be read; if the span is non-zero, we can't do anything with this
995+
// definition.
996+
if (!scriptInfo && d.textSpan.length > 0) {
997+
continue;
998+
}
999+
1000+
let mappedInfo = d;
1001+
let range = EMPTY_RANGE;
1002+
if (scriptInfo) {
1003+
const project = this.getDefaultProjectForScriptInfo(scriptInfo);
1004+
mappedInfo = project ? getMappedDefinitionInfo(d, project) : mappedInfo;
1005+
// After the DTS file maps to original source file, the `scriptInfo` should be updated.
1006+
const originalScriptInfo =
1007+
this.projectService.getScriptInfo(mappedInfo.fileName) ?? scriptInfo;
1008+
range = tsTextSpanToLspRange(originalScriptInfo, mappedInfo.textSpan);
1009+
}
1010+
1011+
const uri = filePathToUri(mappedInfo.fileName);
1012+
results.push({
1013+
uri,
1014+
range,
1015+
});
1016+
}
1017+
return results;
1018+
}
1019+
9681020
private tsDefinitionsToLspLocationLinks(
9691021
definitions: readonly ts.DefinitionInfo[],
9701022
originSelectionRange?: lsp.Range): lsp.LocationLink[] {

0 commit comments

Comments
 (0)