Skip to content

Commit b05c012

Browse files
authored
feat(language-core): cache virtual code by scriptId (#5811)
1 parent f09f173 commit b05c012

File tree

3 files changed

+87
-35
lines changed

3 files changed

+87
-35
lines changed

packages/language-core/lib/languagePlugin.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export function createVueLanguagePlugin<T>(
6060
createVirtualCode(scriptId, languageId, snapshot) {
6161
const fileName = asFileName(scriptId);
6262
if (plugins.some(plugin => plugin.isValidFile?.(fileName, languageId))) {
63-
const code = fileRegistry.get(fileName);
63+
const code = fileRegistry.get(String(scriptId));
6464
if (code) {
6565
code.update(snapshot);
6666
return code;
@@ -74,7 +74,7 @@ export function createVueLanguagePlugin<T>(
7474
plugins,
7575
ts,
7676
);
77-
fileRegistry.set(fileName, code);
77+
fileRegistry.set(String(scriptId), code);
7878
return code;
7979
}
8080
}
@@ -84,8 +84,7 @@ export function createVueLanguagePlugin<T>(
8484
return code;
8585
},
8686
disposeVirtualCode(scriptId) {
87-
const fileName = asFileName(scriptId);
88-
fileRegistry.delete(fileName);
87+
fileRegistry.delete(String(scriptId));
8988
},
9089
typescript: {
9190
extraFileExtensions: getAllExtensions(vueCompilerOptions)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import type { TextDocument } from '@volar/language-server';
2+
import { afterEach, expect, test } from 'vitest';
3+
import { URI } from 'vscode-uri';
4+
import { getLanguageServer, testWorkspacePath } from './server.js';
5+
6+
const openedDocuments: TextDocument[] = [];
7+
8+
afterEach(async () => {
9+
const server = await getLanguageServer();
10+
for (const document of openedDocuments) {
11+
await server.close(document.uri);
12+
}
13+
openedDocuments.length = 0;
14+
});
15+
16+
test('#5572 semantic tokens stay in sync when a git view is opened', async () => {
17+
const server = await getLanguageServer();
18+
const fileContent = `
19+
<script setup lang="ts">
20+
defineProps({
21+
foo: { type: String },
22+
});
23+
</script>
24+
`;
25+
const fileUri = URI.file(`${testWorkspacePath}/semanticTokens.vue`);
26+
27+
const document = await prepareDocument(fileUri, 'vue', fileContent);
28+
const tokensBefore = (await server.vueserver.sendSemanticTokensRequest(document.uri))!.data;
29+
30+
// simlulate open git diff view
31+
const gitUri = URI.from({ scheme: 'git', path: fileUri.path });
32+
await prepareDocument(gitUri, 'vue', fileContent.replace('foo', 'fooooooo'));
33+
34+
const tokensAfter = (await server.vueserver.sendSemanticTokensRequest(document.uri))!.data;
35+
36+
expect(tokensAfter).toEqual(tokensBefore);
37+
});
38+
39+
async function prepareDocument(uriOrFileName: string | URI, languageId: string, content: string) {
40+
const server = await getLanguageServer();
41+
const uri = typeof uriOrFileName === 'string'
42+
? URI.file(`${testWorkspacePath}/${uriOrFileName}`)
43+
: uriOrFileName;
44+
const document = await server.open(uri.toString(), languageId, content);
45+
if (openedDocuments.every(d => d.uri !== document.uri)) {
46+
openedDocuments.push(document);
47+
}
48+
return document;
49+
}

packages/language-server/tests/server.ts

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -69,40 +69,44 @@ export async function getLanguageServer(): Promise<{
6969
vueserver: serverHandle,
7070
tsserver: tsserver,
7171
nextSeq: () => seq++,
72-
open: async (uri: string, languageId: string, content: string) => {
73-
const res = await tsserver.message({
74-
seq: seq++,
75-
type: 'request',
76-
command: 'updateOpen',
77-
arguments: {
78-
changedFiles: [],
79-
closedFiles: [],
80-
openFiles: [
81-
{
82-
file: URI.parse(uri).fsPath,
83-
fileContent: content,
84-
},
85-
],
86-
},
87-
});
88-
if (!res.success) {
89-
throw new Error(res.body);
72+
open: async (uri, languageId, content) => {
73+
if (uri.startsWith('file://')) {
74+
const res = await tsserver.message({
75+
seq: seq++,
76+
type: 'request',
77+
command: 'updateOpen',
78+
arguments: {
79+
changedFiles: [],
80+
closedFiles: [],
81+
openFiles: [
82+
{
83+
file: URI.parse(uri).fsPath,
84+
fileContent: content,
85+
},
86+
],
87+
},
88+
});
89+
if (!res.success) {
90+
throw new Error(res.body);
91+
}
9092
}
9193
return await serverHandle!.openInMemoryDocument(uri, languageId, content);
9294
},
93-
close: async (uri: string) => {
94-
const res = await tsserver.message({
95-
seq: seq++,
96-
type: 'request',
97-
command: 'updateOpen',
98-
arguments: {
99-
changedFiles: [],
100-
closedFiles: [URI.parse(uri).fsPath],
101-
openFiles: [],
102-
},
103-
});
104-
if (!res.success) {
105-
throw new Error(res.body);
95+
close: async uri => {
96+
if (uri.startsWith('file://')) {
97+
const res = await tsserver.message({
98+
seq: seq++,
99+
type: 'request',
100+
command: 'updateOpen',
101+
arguments: {
102+
changedFiles: [],
103+
closedFiles: [URI.parse(uri).fsPath],
104+
openFiles: [],
105+
},
106+
});
107+
if (!res.success) {
108+
throw new Error(res.body);
109+
}
106110
}
107111
await serverHandle!.closeTextDocument(uri);
108112
},

0 commit comments

Comments
 (0)