Skip to content

Commit

Permalink
fix(server): Respect the client capabilities "textDocument.{declarati…
Browse files Browse the repository at this point in the history
…on,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
  • Loading branch information
andlrc committed Mar 9, 2023
1 parent e9c2438 commit 8751840
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
2 changes: 2 additions & 0 deletions integration/lsp/test_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ export function initializeServer(client: MessageConnection): Promise<lsp.Initial
}
},
moniker: {},
definition: {linkSupport: true},
typeDefinition: {linkSupport: true}
}
},
/**
Expand Down
56 changes: 54 additions & 2 deletions server/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,8 @@ export class Session {
return htmlLS.getFoldingRanges(virtualHtmlDoc);
}

private onDefinition(params: lsp.TextDocumentPositionParams): lsp.LocationLink[]|null {
private onDefinition(params: lsp.TextDocumentPositionParams):
lsp.Location[]|lsp.LocationLink[]|null {
const lsInfo = this.getLSAndScriptInfo(params.textDocument);
if (lsInfo === null) {
return null;
Expand All @@ -867,11 +868,20 @@ export class Session {
if (!definition || !definition.definitions) {
return null;
}

const clientSupportsLocationLinks =
this.clientCapabilities.textDocument?.definition?.linkSupport ?? false;

if (!clientSupportsLocationLinks) {
return this.tsDefinitionsToLspLocations(definition.definitions);
}

const originSelectionRange = tsTextSpanToLspRange(scriptInfo, definition.textSpan);
return this.tsDefinitionsToLspLocationLinks(definition.definitions, originSelectionRange);
}

private onTypeDefinition(params: lsp.TextDocumentPositionParams): lsp.LocationLink[]|null {
private onTypeDefinition(params: lsp.TextDocumentPositionParams):
lsp.Location[]|lsp.LocationLink[]|null {
const lsInfo = this.getLSAndScriptInfo(params.textDocument);
if (lsInfo === null) {
return null;
Expand All @@ -882,6 +892,14 @@ export class Session {
if (!definitions) {
return null;
}

const clientSupportsLocationLinks =
this.clientCapabilities.textDocument?.typeDefinition?.linkSupport ?? false;

if (!clientSupportsLocationLinks) {
return this.tsDefinitionsToLspLocations(definitions);
}

return this.tsDefinitionsToLspLocationLinks(definitions);
}

Expand Down Expand Up @@ -965,6 +983,40 @@ export class Session {
});
}

private tsDefinitionsToLspLocations(definitions: readonly ts.DefinitionInfo[]): lsp.Location[] {
const results: lsp.Location[] = [];
for (const d of definitions) {
const scriptInfo = this.projectService.getScriptInfo(d.fileName);

// Some definitions, like definitions of CSS files, may not be recorded files with a
// `scriptInfo` but are still valid definitions because they are files that exist. In this
// case, check to make sure that the text span of the definition is zero so that the file
// doesn't have to be read; if the span is non-zero, we can't do anything with this
// definition.
if (!scriptInfo && d.textSpan.length > 0) {
continue;
}

let mappedInfo = d;
let range = EMPTY_RANGE;
if (scriptInfo) {
const project = this.getDefaultProjectForScriptInfo(scriptInfo);
mappedInfo = project ? getMappedDefinitionInfo(d, project) : mappedInfo;
// After the DTS file maps to original source file, the `scriptInfo` should be updated.
const originalScriptInfo =
this.projectService.getScriptInfo(mappedInfo.fileName) ?? scriptInfo;
range = tsTextSpanToLspRange(originalScriptInfo, mappedInfo.textSpan);
}

const uri = filePathToUri(mappedInfo.fileName);
results.push({
uri,
range,
});
}
return results;
}

private tsDefinitionsToLspLocationLinks(
definitions: readonly ts.DefinitionInfo[],
originSelectionRange?: lsp.Range): lsp.LocationLink[] {
Expand Down

0 comments on commit 8751840

Please sign in to comment.