Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/common/extHostLanguages.ts
3296 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
6
import { MainContext, MainThreadLanguagesShape, IMainContext, ExtHostLanguagesShape } from './extHost.protocol.js';
7
import type * as vscode from 'vscode';
8
import { ExtHostDocuments } from './extHostDocuments.js';
9
import * as typeConvert from './extHostTypeConverters.js';
10
import { StandardTokenType, Range, Position, LanguageStatusSeverity } from './extHostTypes.js';
11
import Severity from '../../../base/common/severity.js';
12
import { disposableTimeout } from '../../../base/common/async.js';
13
import { DisposableStore, IDisposable } from '../../../base/common/lifecycle.js';
14
import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
15
import { CommandsConverter } from './extHostCommands.js';
16
import { IURITransformer } from '../../../base/common/uriIpc.js';
17
import { checkProposedApiEnabled } from '../../services/extensions/common/extensions.js';
18
19
export class ExtHostLanguages implements ExtHostLanguagesShape {
20
21
private readonly _proxy: MainThreadLanguagesShape;
22
23
private _languageIds: string[] = [];
24
25
constructor(
26
mainContext: IMainContext,
27
private readonly _documents: ExtHostDocuments,
28
private readonly _commands: CommandsConverter,
29
private readonly _uriTransformer: IURITransformer | undefined
30
) {
31
this._proxy = mainContext.getProxy(MainContext.MainThreadLanguages);
32
}
33
34
$acceptLanguageIds(ids: string[]): void {
35
this._languageIds = ids;
36
}
37
38
async getLanguages(): Promise<string[]> {
39
return this._languageIds.slice(0);
40
}
41
42
async changeLanguage(uri: vscode.Uri, languageId: string): Promise<vscode.TextDocument> {
43
await this._proxy.$changeLanguage(uri, languageId);
44
const data = this._documents.getDocumentData(uri);
45
if (!data) {
46
throw new Error(`document '${uri.toString()}' NOT found`);
47
}
48
return data.document;
49
}
50
51
async tokenAtPosition(document: vscode.TextDocument, position: vscode.Position): Promise<vscode.TokenInformation> {
52
const versionNow = document.version;
53
const pos = typeConvert.Position.from(position);
54
const info = await this._proxy.$tokensAtPosition(document.uri, pos);
55
const defaultRange = {
56
type: StandardTokenType.Other,
57
range: document.getWordRangeAtPosition(position) ?? new Range(position.line, position.character, position.line, position.character)
58
};
59
if (!info) {
60
// no result
61
return defaultRange;
62
}
63
const result = {
64
range: typeConvert.Range.to(info.range),
65
type: typeConvert.TokenType.to(info.type)
66
};
67
if (!result.range.contains(<Position>position)) {
68
// bogous result
69
return defaultRange;
70
}
71
if (versionNow !== document.version) {
72
// concurrent change
73
return defaultRange;
74
}
75
return result;
76
}
77
78
private _handlePool: number = 0;
79
private _ids = new Set<string>();
80
81
createLanguageStatusItem(extension: IExtensionDescription, id: string, selector: vscode.DocumentSelector): vscode.LanguageStatusItem {
82
83
const handle = this._handlePool++;
84
const proxy = this._proxy;
85
const ids = this._ids;
86
87
// enforce extension unique identifier
88
const fullyQualifiedId = `${extension.identifier.value}/${id}`;
89
if (ids.has(fullyQualifiedId)) {
90
throw new Error(`LanguageStatusItem with id '${id}' ALREADY exists`);
91
}
92
ids.add(fullyQualifiedId);
93
94
const data: Omit<vscode.LanguageStatusItem, 'dispose' | 'text2'> = {
95
selector,
96
id,
97
name: extension.displayName ?? extension.name,
98
severity: LanguageStatusSeverity.Information,
99
command: undefined,
100
text: '',
101
detail: '',
102
busy: false
103
};
104
105
106
let soonHandle: IDisposable | undefined;
107
const commandDisposables = new DisposableStore();
108
const updateAsync = () => {
109
soonHandle?.dispose();
110
111
if (!ids.has(fullyQualifiedId)) {
112
console.warn(`LanguageStatusItem (${id}) from ${extension.identifier.value} has been disposed and CANNOT be updated anymore`);
113
return; // disposed in the meantime
114
}
115
116
soonHandle = disposableTimeout(() => {
117
commandDisposables.clear();
118
this._proxy.$setLanguageStatus(handle, {
119
id: fullyQualifiedId,
120
name: data.name ?? extension.displayName ?? extension.name,
121
source: extension.displayName ?? extension.name,
122
selector: typeConvert.DocumentSelector.from(data.selector, this._uriTransformer),
123
label: data.text,
124
detail: data.detail ?? '',
125
severity: data.severity === LanguageStatusSeverity.Error ? Severity.Error : data.severity === LanguageStatusSeverity.Warning ? Severity.Warning : Severity.Info,
126
command: data.command && this._commands.toInternal(data.command, commandDisposables),
127
accessibilityInfo: data.accessibilityInformation,
128
busy: data.busy
129
});
130
}, 0);
131
};
132
133
const result: vscode.LanguageStatusItem = {
134
dispose() {
135
commandDisposables.dispose();
136
soonHandle?.dispose();
137
proxy.$removeLanguageStatus(handle);
138
ids.delete(fullyQualifiedId);
139
},
140
get id() {
141
return data.id;
142
},
143
get name() {
144
return data.name;
145
},
146
set name(value) {
147
data.name = value;
148
updateAsync();
149
},
150
get selector() {
151
return data.selector;
152
},
153
set selector(value) {
154
data.selector = value;
155
updateAsync();
156
},
157
get text() {
158
return data.text;
159
},
160
set text(value) {
161
data.text = value;
162
updateAsync();
163
},
164
set text2(value) {
165
checkProposedApiEnabled(extension, 'languageStatusText');
166
data.text = value;
167
updateAsync();
168
},
169
get text2() {
170
checkProposedApiEnabled(extension, 'languageStatusText');
171
return data.text;
172
},
173
get detail() {
174
return data.detail;
175
},
176
set detail(value) {
177
data.detail = value;
178
updateAsync();
179
},
180
get severity() {
181
return data.severity;
182
},
183
set severity(value) {
184
data.severity = value;
185
updateAsync();
186
},
187
get accessibilityInformation() {
188
return data.accessibilityInformation;
189
},
190
set accessibilityInformation(value) {
191
data.accessibilityInformation = value;
192
updateAsync();
193
},
194
get command() {
195
return data.command;
196
},
197
set command(value) {
198
data.command = value;
199
updateAsync();
200
},
201
get busy() {
202
return data.busy;
203
},
204
set busy(value: boolean) {
205
data.busy = value;
206
updateAsync();
207
}
208
};
209
updateAsync();
210
return result;
211
}
212
}
213
214