/
vue-codelens-references.ts
122 lines (92 loc) · 3.34 KB
/
vue-codelens-references.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
111
112
113
114
115
116
117
118
119
120
121
122
import * as vscode from 'vscode-languageserver-protocol';
import { LanguageServicePlugin, LanguageServicePluginContext, SourceFileDocument } from '@volar/language-service';
import { VueSourceFile } from '@volar/vue-language-core';
const showReferencesCommand = 'volar.show-references';
export const commands = [showReferencesCommand];
type CommandArgs = [string, vscode.Position, vscode.Location[]];
export interface ReferencesCodeLensData {
uri: string,
position: vscode.Position,
}
export default function (options: {
getVueDocument(uri: string): SourceFileDocument | undefined,
findReference(uri: string, position: vscode.Position): Promise<vscode.Location[] | undefined>,
}): LanguageServicePlugin {
let context: LanguageServicePluginContext;
return {
setup(_context) {
context = _context;
},
codeLens: {
on(document) {
return worker(document.uri, async (vueDocument) => {
const isEnabled = await context.env.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.referencesCodeLens)
continue;
result.push({
range: {
start: document.positionAt(mapping.sourceRange[0]),
end: document.positionAt(mapping.sourceRange[1]),
},
data: {
uri: document.uri,
position: document.positionAt(mapping.sourceRange[0]),
} satisfies ReferencesCodeLensData,
});
}
}
return result;
});
},
async resolve(codeLens) {
const data: ReferencesCodeLensData = codeLens.data;
const vueDocument = options.getVueDocument(data.uri);
if (!vueDocument)
return codeLens;
const document = vueDocument.getDocument();
const offset = document.offsetAt(data.position);
const file = vueDocument.file as VueSourceFile;
const blocks = [
file.sfc.script,
file.sfc.scriptSetup,
file.sfc.template,
...file.sfc.styles,
...file.sfc.customBlocks,
];
const allRefs = await options.findReference(data.uri, data.position) ?? [];
const sourceBlock = blocks.find(block => block && offset >= block.startTagEnd && offset <= block.endTagStart);
const diffDocRefs = allRefs.filter(reference =>
reference.uri !== data.uri // different file
|| sourceBlock !== blocks.find(block => block && document.offsetAt(reference.range.start) >= block.startTagEnd && document.offsetAt(reference.range.end) <= block.endTagStart) // different block
);
codeLens.command = {
title: diffDocRefs.length === 1 ? '1 reference' : `${diffDocRefs.length} references`,
command: showReferencesCommand,
arguments: <CommandArgs>[data.uri, codeLens.range.start, diffDocRefs],
};
return codeLens;
},
},
doExecuteCommand(command, args, context) {
if (command === showReferencesCommand) {
const [uri, position, references] = args as CommandArgs;
context.showReferences({
textDocument: { uri },
position,
references,
});
}
},
};
function worker<T>(uri: string, callback: (vueDocument: SourceFileDocument) => T) {
const vueDocument = options.getVueDocument(uri);
if (!vueDocument)
return;
return callback(vueDocument);
}
}