/
referencesCodeLens.ts
110 lines (82 loc) · 3.86 KB
/
referencesCodeLens.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import * as vscode from 'vscode-languageserver-protocol';
import { ConfigurationHost, EmbeddedLanguageServicePlugin } from '@volar/vue-language-service-types';
import * as shared from '@volar/shared';
import { VueDocument } from '../vueDocuments';
const showReferencesCommand = 'volar.show-references';
export const commands = [showReferencesCommand];
type CommandArgs = [string, vscode.Position, vscode.Location[]];
export interface ReferencesCodeLensData {
uri: string,
vueTag: string | undefined,
position: vscode.Position,
}
export default function (host: {
configurationHost: ConfigurationHost | undefined,
getVueDocument(uri: string): VueDocument | undefined,
findReference(uri: string, position: vscode.Position): Promise<vscode.Location[] | undefined>,
}): EmbeddedLanguageServicePlugin {
return {
doCodeLens(document) {
return worker(document.uri, async (vueDocument) => {
const isEnabled = await host.configurationHost?.getConfiguration<boolean>('volar.codeLens.references') ?? true;
if (!isEnabled)
return;
const result: vscode.CodeLens[] = [];
for (const sourceMap of vueDocument.getSourceMaps()) {
for (const mapping of sourceMap.mappings) {
if (!mapping.data.capabilities.referencesCodeLens)
continue;
const data: ReferencesCodeLensData = {
uri: document.uri,
vueTag: mapping.data.vueTag,
position: document.positionAt(mapping.sourceRange.start),
};
result.push({
range: {
start: document.positionAt(mapping.sourceRange.start),
end: document.positionAt(mapping.sourceRange.end),
},
data: data as any,
});
}
}
return result;
});
},
async doCodeLensResolve(codeLens) {
const data: ReferencesCodeLensData = codeLens.data as any;
const vueDocument = host.getVueDocument(data.uri)
if (!vueDocument)
return codeLens;
const sourceMaps = vueDocument.getSourceMaps();
const references = await host.findReference(data.uri, data.position) ?? [];
const referencesInDifferentDocument = references.filter(reference =>
reference.uri !== data.uri // different file
|| !sourceMaps.some(sourceMap => sourceMap.getMappedRange(reference.range.start, reference.range.end, _data => _data.vueTag !== data.vueTag)) // different embedded document
);
const referencesCount = referencesInDifferentDocument.length ?? 0;
codeLens.command = {
title: referencesCount === 1 ? '1 reference' : `${referencesCount} references`,
command: showReferencesCommand,
arguments: <CommandArgs>[data.uri, codeLens.range.start, references],
};
return codeLens;
},
doExecuteCommand(command, args, context) {
if (command === showReferencesCommand) {
const [uri, position, references] = args as CommandArgs;
context.sendNotification(shared.ShowReferencesNotification.type, {
textDocument: { uri },
position,
references,
});
}
},
};
function worker<T>(uri: string, callback: (vueDocument: VueDocument) => T) {
const vueDocument = host.getVueDocument(uri);
if (!vueDocument)
return;
return callback(vueDocument);
}
}