Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/test/simulation/language/simulationLanguageFeatureService.ts
13394 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
import type * as vscode from 'vscode';
6
import { ILanguageFeaturesService, NoopLanguageFeaturesService } from '../../../src/platform/languages/common/languageFeaturesService';
7
import { SimulationWorkspace } from '../../../src/platform/test/node/simulationWorkspace';
8
import { getLanguageForResource } from '../../../src/util/common/languages';
9
import { URI } from '../../../src/util/vs/base/common/uri';
10
import { Range, Uri } from '../../../src/vscodeTypes';
11
import { computeSHA256 } from '../../base/hash';
12
import { TestingCacheSalts } from '../../base/salts';
13
import { CacheScope, ICachingResourceFetcher } from '../../base/simulationContext';
14
import { TSServerClient } from './tsServerClient';
15
16
17
export class SimulationLanguageFeaturesService implements ILanguageFeaturesService {
18
_serviceBrand: undefined;
19
private readonly _tsService: TSServerLanguageFeaturesService;
20
private readonly _noOpService: NoopLanguageFeaturesService;
21
22
constructor(
23
readonly _workspace: SimulationWorkspace,
24
@ICachingResourceFetcher _cachingResourceFetcher: ICachingResourceFetcher
25
) {
26
this._tsService = new TSServerLanguageFeaturesService(_workspace, _cachingResourceFetcher);
27
this._noOpService = new NoopLanguageFeaturesService();
28
}
29
30
31
private getLanguageFeatures(uri: vscode.Uri) {
32
const language = getLanguageForResource(uri);
33
switch (language?.languageId) {
34
case 'javascript':
35
case 'javascriptreact':
36
case 'typescript':
37
case 'typescriptreact':
38
return this._tsService;
39
default:
40
return this._noOpService;
41
}
42
}
43
44
getDocumentSymbols(uri: vscode.Uri): Promise<vscode.DocumentSymbol[]> {
45
return this.getLanguageFeatures(uri).getDocumentSymbols(uri);
46
}
47
getDefinitions(uri: vscode.Uri, position: vscode.Position): Promise<(vscode.LocationLink | vscode.Location)[]> {
48
return this.getLanguageFeatures(uri).getDefinitions(uri, position);
49
}
50
getImplementations(uri: vscode.Uri, position: vscode.Position): Promise<(vscode.LocationLink | vscode.Location)[]> {
51
return this.getLanguageFeatures(uri).getImplementations(uri, position);
52
}
53
getReferences(uri: vscode.Uri, position: vscode.Position): Promise<vscode.Location[]> {
54
return this.getLanguageFeatures(uri).getReferences(uri, position);
55
}
56
getDiagnostics(uri: vscode.Uri): vscode.Diagnostic[] {
57
return this.getLanguageFeatures(uri).getDiagnostics(uri);
58
}
59
getWorkspaceSymbols(query: string): Promise<vscode.SymbolInformation[]> {
60
return Promise.resolve([]);
61
}
62
dispose(): void {
63
this._tsService.teardown().catch(err => {
64
console.error(err);
65
});
66
}
67
teardown(): Promise<void> {
68
return this._tsService.teardown();
69
}
70
}
71
72
class TSServerLanguageFeaturesService implements ILanguageFeaturesService {
73
_serviceBrand: undefined;
74
75
private _tsServerClient: TSServerClient | undefined;
76
77
constructor(
78
private _workspace: SimulationWorkspace,
79
@ICachingResourceFetcher private readonly _cachingResourceFetcher: ICachingResourceFetcher
80
) {
81
}
82
83
public async teardown() {
84
try {
85
await this._tsServerClient?.teardown();
86
} catch {
87
// ignored
88
}
89
}
90
91
public async getDefinitions(uri: vscode.Uri, position: vscode.Position): Promise<vscode.LocationLink[]> {
92
return (await this.cachedGetFromTSServer(uri, position, 'def', async (tsserver, currentFile, position) => {
93
const definitions = await tsserver.findDefinitions(currentFile, position);
94
return definitions.map(def => {
95
return {
96
targetUri: this._workspace.getUriFromFilePath(def.fileName),
97
targetRange: def.range
98
};
99
});
100
})).map((def: any) => {
101
return {
102
...def,
103
targetUri: URI.isUri(def.targetUri) ? def.targetUri : Uri.file(def.targetUri.path),
104
targetRange: def.targetRange instanceof Range ? def.targetRange : new Range(def.targetRange[0].line, def.targetRange[0].character, def.targetRange[1].line, def.targetRange[1].character),
105
};
106
});
107
}
108
109
public async getReferences(uri: vscode.Uri, position: vscode.Position): Promise<vscode.Location[]> {
110
return (await this.cachedGetFromTSServer(uri, position, 'ref', async (tsserver, currentFile, position) => {
111
const references = await tsserver.findReferences(currentFile, position);
112
return references.map(ref => {
113
return {
114
uri: this._workspace.getUriFromFilePath(ref.fileName),
115
range: ref.range
116
};
117
});
118
})).map((ref: any) => {
119
return {
120
...ref,
121
uri: URI.isUri(ref.uri) ? ref.uri : Uri.file(ref.uri.path),
122
range: ref.range instanceof Range ? ref.range : new Range(ref.range[0].line, ref.range[0].character, ref.range[1].line, ref.range[1].character),
123
};
124
});
125
}
126
127
private async cachedGetFromTSServer<T extends vscode.LocationLink | vscode.Location>(
128
uri: vscode.Uri,
129
position: vscode.Position,
130
target: 'ref' | 'def',
131
f: (tsserver: TSServerClient, currentFile: string, pos: vscode.Position) => Promise<T[]>): Promise<T[]> {
132
const currentFile = this._workspace.getFilePath(uri);
133
const files = this._workspace.documents.map(d => ({ fileName: this._workspace.getFilePath(d.document.uri), fileContents: d.getText() }));
134
const serializablePosition = { line: position.line, character: position.character };
135
136
const cacheKey = computeSHA256(`${TSServerClient.id}-v${TSServerClient.cacheVersion}-${target}-${JSON.stringify({ files, currentFile, serializablePosition })}`);
137
138
const getFromTSServer = async () => {
139
try {
140
if (this._tsServerClient === undefined) {
141
this._tsServerClient = new TSServerClient(files);
142
}
143
return f(this._tsServerClient, currentFile, position);
144
} catch (error) {
145
console.error(error);
146
return [];
147
}
148
};
149
return this._cachingResourceFetcher.invokeWithCache(CacheScope.TSC, undefined, TestingCacheSalts.tscCacheSalt, cacheKey, getFromTSServer);
150
}
151
152
getImplementations(uri: vscode.Uri, position: vscode.Position): Promise<(vscode.Location | vscode.LocationLink)[]> {
153
return Promise.resolve([]);
154
}
155
getWorkspaceSymbols(query: string): Promise<vscode.SymbolInformation[]> {
156
return Promise.resolve([]);
157
}
158
getDocumentSymbols(uri: vscode.Uri): Promise<vscode.DocumentSymbol[]> {
159
return Promise.resolve([]);
160
}
161
getDiagnostics(uri: vscode.Uri): vscode.Diagnostic[] {
162
return [];
163
}
164
}
165
166