Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/common/extHostLanguageFeatures.ts
5221 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 type * as vscode from 'vscode';
7
import { asArray, coalesce, isFalsyOrEmpty, isNonEmptyArray } from '../../../base/common/arrays.js';
8
import { raceCancellationError } from '../../../base/common/async.js';
9
import { VSBuffer } from '../../../base/common/buffer.js';
10
import { CancellationToken } from '../../../base/common/cancellation.js';
11
import { NotImplementedError, isCancellationError } from '../../../base/common/errors.js';
12
import { IdGenerator } from '../../../base/common/idGenerator.js';
13
import { DisposableStore, Disposable as CoreDisposable } from '../../../base/common/lifecycle.js';
14
import { equals, mixin } from '../../../base/common/objects.js';
15
import { StopWatch } from '../../../base/common/stopwatch.js';
16
import { regExpLeadsToEndlessLoop } from '../../../base/common/strings.js';
17
import { assertType, isObject } from '../../../base/common/types.js';
18
import { URI, UriComponents } from '../../../base/common/uri.js';
19
import { IURITransformer } from '../../../base/common/uriIpc.js';
20
import { generateUuid } from '../../../base/common/uuid.js';
21
import { IPosition } from '../../../editor/common/core/position.js';
22
import { Range as EditorRange, IRange } from '../../../editor/common/core/range.js';
23
import { ISelection, Selection } from '../../../editor/common/core/selection.js';
24
import * as languages from '../../../editor/common/languages.js';
25
import { IAutoClosingPairConditional } from '../../../editor/common/languages/languageConfiguration.js';
26
import { encodeSemanticTokensDto } from '../../../editor/common/services/semanticTokensDto.js';
27
import { localize } from '../../../nls.js';
28
import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
29
import { ILogService } from '../../../platform/log/common/log.js';
30
import { isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
31
import { Cache } from './cache.js';
32
import * as extHostProtocol from './extHost.protocol.js';
33
import { IExtHostApiDeprecationService } from './extHostApiDeprecationService.js';
34
import { CommandsConverter, ExtHostCommands } from './extHostCommands.js';
35
import { ExtHostDiagnostics } from './extHostDiagnostics.js';
36
import { ExtHostDocuments } from './extHostDocuments.js';
37
import { ExtHostTelemetry, IExtHostTelemetry } from './extHostTelemetry.js';
38
import * as typeConvert from './extHostTypeConverters.js';
39
import { CodeAction, CodeActionKind, CompletionList, DataTransfer, Disposable, DocumentDropOrPasteEditKind, DocumentSymbol, InlineCompletionsDisposeReasonKind, InlineCompletionTriggerKind, InternalDataTransferItem, Location, NewSymbolNameTriggerKind, Range, SemanticTokens, SemanticTokensEdit, SemanticTokensEdits, SnippetString, SymbolInformation, SyntaxTokenType } from './extHostTypes.js';
40
import { Emitter } from '../../../base/common/event.js';
41
import { IInlineCompletionsUnificationState } from '../../services/inlineCompletions/common/inlineCompletionsUnification.js';
42
43
// --- adapter
44
45
class DocumentSymbolAdapter {
46
47
constructor(
48
private readonly _documents: ExtHostDocuments,
49
private readonly _provider: vscode.DocumentSymbolProvider
50
) { }
51
52
async provideDocumentSymbols(resource: URI, token: CancellationToken): Promise<languages.DocumentSymbol[] | undefined> {
53
const doc = this._documents.getDocument(resource);
54
const value = await this._provider.provideDocumentSymbols(doc, token);
55
if (isFalsyOrEmpty(value)) {
56
return undefined;
57
} else if (value![0] instanceof DocumentSymbol) {
58
return (<DocumentSymbol[]>value).map(typeConvert.DocumentSymbol.from);
59
} else {
60
return DocumentSymbolAdapter._asDocumentSymbolTree(<SymbolInformation[]>value);
61
}
62
}
63
64
private static _asDocumentSymbolTree(infos: SymbolInformation[]): languages.DocumentSymbol[] {
65
// first sort by start (and end) and then loop over all elements
66
// and build a tree based on containment.
67
infos = infos.slice(0).sort((a, b) => {
68
let res = a.location.range.start.compareTo(b.location.range.start);
69
if (res === 0) {
70
res = b.location.range.end.compareTo(a.location.range.end);
71
}
72
return res;
73
});
74
const res: languages.DocumentSymbol[] = [];
75
const parentStack: languages.DocumentSymbol[] = [];
76
for (const info of infos) {
77
const element: languages.DocumentSymbol = {
78
name: info.name || '!!MISSING: name!!',
79
kind: typeConvert.SymbolKind.from(info.kind),
80
tags: info.tags?.map(typeConvert.SymbolTag.from) || [],
81
detail: '',
82
containerName: info.containerName,
83
range: typeConvert.Range.from(info.location.range),
84
selectionRange: typeConvert.Range.from(info.location.range),
85
children: []
86
};
87
88
while (true) {
89
if (parentStack.length === 0) {
90
parentStack.push(element);
91
res.push(element);
92
break;
93
}
94
const parent = parentStack[parentStack.length - 1];
95
if (EditorRange.containsRange(parent.range, element.range) && !EditorRange.equalsRange(parent.range, element.range)) {
96
parent.children?.push(element);
97
parentStack.push(element);
98
break;
99
}
100
parentStack.pop();
101
}
102
}
103
return res;
104
}
105
}
106
107
class CodeLensAdapter {
108
109
private readonly _cache = new Cache<vscode.CodeLens>('CodeLens');
110
private readonly _disposables = new Map<number, DisposableStore>();
111
112
constructor(
113
private readonly _documents: ExtHostDocuments,
114
private readonly _commands: CommandsConverter,
115
private readonly _provider: vscode.CodeLensProvider,
116
private readonly _extension: IExtensionDescription,
117
private readonly _extTelemetry: ExtHostTelemetry,
118
private readonly _logService: ILogService,
119
) { }
120
121
async provideCodeLenses(resource: URI, token: CancellationToken): Promise<extHostProtocol.ICodeLensListDto | undefined> {
122
const doc = this._documents.getDocument(resource);
123
124
const lenses = await this._provider.provideCodeLenses(doc, token);
125
if (!lenses || token.isCancellationRequested) {
126
return undefined;
127
}
128
const cacheId = this._cache.add(lenses);
129
const disposables = new DisposableStore();
130
this._disposables.set(cacheId, disposables);
131
const result: extHostProtocol.ICodeLensListDto = {
132
cacheId,
133
lenses: [],
134
};
135
for (let i = 0; i < lenses.length; i++) {
136
137
if (!Range.isRange(lenses[i].range)) {
138
console.warn('INVALID code lens, range is not defined', this._extension.identifier.value);
139
continue;
140
}
141
142
result.lenses.push({
143
cacheId: [cacheId, i],
144
range: typeConvert.Range.from(lenses[i].range),
145
command: this._commands.toInternal(lenses[i].command, disposables)
146
});
147
}
148
return result;
149
}
150
151
async resolveCodeLens(symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise<extHostProtocol.ICodeLensDto | undefined> {
152
153
const lens = symbol.cacheId && this._cache.get(...symbol.cacheId);
154
if (!lens) {
155
return undefined;
156
}
157
158
let resolvedLens: vscode.CodeLens | undefined | null;
159
if (typeof this._provider.resolveCodeLens !== 'function' || lens.isResolved) {
160
resolvedLens = lens;
161
} else {
162
resolvedLens = await this._provider.resolveCodeLens(lens, token);
163
}
164
if (!resolvedLens) {
165
resolvedLens = lens;
166
}
167
168
if (token.isCancellationRequested) {
169
return undefined;
170
}
171
const disposables = symbol.cacheId && this._disposables.get(symbol.cacheId[0]);
172
if (!disposables) {
173
// disposed in the meantime
174
return undefined;
175
}
176
177
if (!resolvedLens.command) {
178
const error = new Error('INVALID code lens resolved, lacks command: ' + this._extension.identifier.value);
179
this._extTelemetry.onExtensionError(this._extension.identifier, error);
180
this._logService.error(error);
181
return undefined;
182
}
183
184
symbol.command = this._commands.toInternal(resolvedLens.command, disposables);
185
return symbol;
186
}
187
188
releaseCodeLenses(cachedId: number): void {
189
this._disposables.get(cachedId)?.dispose();
190
this._disposables.delete(cachedId);
191
this._cache.delete(cachedId);
192
}
193
}
194
195
function convertToLocationLinks(value: vscode.Location | vscode.Location[] | vscode.LocationLink[] | undefined | null): languages.LocationLink[] {
196
if (Array.isArray(value)) {
197
// eslint-disable-next-line local/code-no-any-casts
198
return (<any>value).map(typeConvert.DefinitionLink.from);
199
} else if (value) {
200
return [typeConvert.DefinitionLink.from(value)];
201
}
202
return [];
203
}
204
205
class DefinitionAdapter {
206
207
constructor(
208
private readonly _documents: ExtHostDocuments,
209
private readonly _provider: vscode.DefinitionProvider
210
) { }
211
212
async provideDefinition(resource: URI, position: IPosition, token: CancellationToken): Promise<languages.LocationLink[]> {
213
const doc = this._documents.getDocument(resource);
214
const pos = typeConvert.Position.to(position);
215
const value = await this._provider.provideDefinition(doc, pos, token);
216
return convertToLocationLinks(value);
217
}
218
}
219
220
class DeclarationAdapter {
221
222
constructor(
223
private readonly _documents: ExtHostDocuments,
224
private readonly _provider: vscode.DeclarationProvider
225
) { }
226
227
async provideDeclaration(resource: URI, position: IPosition, token: CancellationToken): Promise<languages.LocationLink[]> {
228
const doc = this._documents.getDocument(resource);
229
const pos = typeConvert.Position.to(position);
230
const value = await this._provider.provideDeclaration(doc, pos, token);
231
return convertToLocationLinks(value);
232
}
233
}
234
235
class ImplementationAdapter {
236
237
constructor(
238
private readonly _documents: ExtHostDocuments,
239
private readonly _provider: vscode.ImplementationProvider
240
) { }
241
242
async provideImplementation(resource: URI, position: IPosition, token: CancellationToken): Promise<languages.LocationLink[]> {
243
const doc = this._documents.getDocument(resource);
244
const pos = typeConvert.Position.to(position);
245
const value = await this._provider.provideImplementation(doc, pos, token);
246
return convertToLocationLinks(value);
247
}
248
}
249
250
class TypeDefinitionAdapter {
251
252
constructor(
253
private readonly _documents: ExtHostDocuments,
254
private readonly _provider: vscode.TypeDefinitionProvider
255
) { }
256
257
async provideTypeDefinition(resource: URI, position: IPosition, token: CancellationToken): Promise<languages.LocationLink[]> {
258
const doc = this._documents.getDocument(resource);
259
const pos = typeConvert.Position.to(position);
260
const value = await this._provider.provideTypeDefinition(doc, pos, token);
261
return convertToLocationLinks(value);
262
}
263
}
264
265
class HoverAdapter {
266
267
private _hoverCounter: number = 0;
268
private _hoverMap: Map<number, vscode.Hover> = new Map<number, vscode.Hover>();
269
270
private static HOVER_MAP_MAX_SIZE = 10;
271
272
constructor(
273
private readonly _documents: ExtHostDocuments,
274
private readonly _provider: vscode.HoverProvider,
275
) { }
276
277
async provideHover(resource: URI, position: IPosition, context: languages.HoverContext<{ id: number }> | undefined, token: CancellationToken): Promise<extHostProtocol.HoverWithId | undefined> {
278
279
const doc = this._documents.getDocument(resource);
280
const pos = typeConvert.Position.to(position);
281
282
let value: vscode.Hover | null | undefined;
283
if (context && context.verbosityRequest) {
284
const previousHoverId = context.verbosityRequest.previousHover.id;
285
const previousHover = this._hoverMap.get(previousHoverId);
286
if (!previousHover) {
287
throw new Error(`Hover with id ${previousHoverId} not found`);
288
}
289
const hoverContext: vscode.HoverContext = { verbosityDelta: context.verbosityRequest.verbosityDelta, previousHover };
290
value = await this._provider.provideHover(doc, pos, token, hoverContext);
291
} else {
292
value = await this._provider.provideHover(doc, pos, token);
293
}
294
if (!value || isFalsyOrEmpty(value.contents)) {
295
return undefined;
296
}
297
if (!value.range) {
298
value.range = doc.getWordRangeAtPosition(pos);
299
}
300
if (!value.range) {
301
value.range = new Range(pos, pos);
302
}
303
const convertedHover: languages.Hover = typeConvert.Hover.from(value);
304
const id = this._hoverCounter;
305
// Check if hover map has more than 10 elements and if yes, remove oldest from the map
306
if (this._hoverMap.size === HoverAdapter.HOVER_MAP_MAX_SIZE) {
307
const minimumId = Math.min(...this._hoverMap.keys());
308
this._hoverMap.delete(minimumId);
309
}
310
this._hoverMap.set(id, value);
311
this._hoverCounter += 1;
312
const hover: extHostProtocol.HoverWithId = {
313
...convertedHover,
314
id
315
};
316
return hover;
317
}
318
319
releaseHover(id: number): void {
320
this._hoverMap.delete(id);
321
}
322
}
323
324
class EvaluatableExpressionAdapter {
325
326
constructor(
327
private readonly _documents: ExtHostDocuments,
328
private readonly _provider: vscode.EvaluatableExpressionProvider,
329
) { }
330
331
async provideEvaluatableExpression(resource: URI, position: IPosition, token: CancellationToken): Promise<languages.EvaluatableExpression | undefined> {
332
333
const doc = this._documents.getDocument(resource);
334
const pos = typeConvert.Position.to(position);
335
336
const value = await this._provider.provideEvaluatableExpression(doc, pos, token);
337
if (value) {
338
return typeConvert.EvaluatableExpression.from(value);
339
}
340
return undefined;
341
}
342
}
343
344
class InlineValuesAdapter {
345
346
constructor(
347
private readonly _documents: ExtHostDocuments,
348
private readonly _provider: vscode.InlineValuesProvider,
349
) { }
350
351
async provideInlineValues(resource: URI, viewPort: IRange, context: extHostProtocol.IInlineValueContextDto, token: CancellationToken): Promise<languages.InlineValue[] | undefined> {
352
const doc = this._documents.getDocument(resource);
353
const value = await this._provider.provideInlineValues(doc, typeConvert.Range.to(viewPort), typeConvert.InlineValueContext.to(context), token);
354
if (Array.isArray(value)) {
355
return value.map(iv => typeConvert.InlineValue.from(iv));
356
}
357
return undefined;
358
}
359
}
360
361
class DocumentHighlightAdapter {
362
363
constructor(
364
private readonly _documents: ExtHostDocuments,
365
private readonly _provider: vscode.DocumentHighlightProvider
366
) { }
367
368
async provideDocumentHighlights(resource: URI, position: IPosition, token: CancellationToken): Promise<languages.DocumentHighlight[] | undefined> {
369
370
const doc = this._documents.getDocument(resource);
371
const pos = typeConvert.Position.to(position);
372
373
const value = await this._provider.provideDocumentHighlights(doc, pos, token);
374
if (Array.isArray(value)) {
375
return value.map(typeConvert.DocumentHighlight.from);
376
}
377
return undefined;
378
}
379
}
380
381
class MultiDocumentHighlightAdapter {
382
383
constructor(
384
private readonly _documents: ExtHostDocuments,
385
private readonly _provider: vscode.MultiDocumentHighlightProvider,
386
private readonly _logService: ILogService,
387
) { }
388
389
async provideMultiDocumentHighlights(resource: URI, position: IPosition, otherResources: URI[], token: CancellationToken): Promise<languages.MultiDocumentHighlight[] | undefined> {
390
const doc = this._documents.getDocument(resource);
391
const otherDocuments = otherResources.map(r => {
392
try {
393
return this._documents.getDocument(r);
394
} catch (err) {
395
this._logService.error('Error: Unable to retrieve document from URI: ' + r + '. Error message: ' + err);
396
return undefined;
397
}
398
}).filter(doc => doc !== undefined);
399
400
const pos = typeConvert.Position.to(position);
401
402
const value = await this._provider.provideMultiDocumentHighlights(doc, pos, otherDocuments, token);
403
if (Array.isArray(value)) {
404
return value.map(typeConvert.MultiDocumentHighlight.from);
405
}
406
return undefined;
407
}
408
}
409
410
class LinkedEditingRangeAdapter {
411
constructor(
412
private readonly _documents: ExtHostDocuments,
413
private readonly _provider: vscode.LinkedEditingRangeProvider
414
) { }
415
416
async provideLinkedEditingRanges(resource: URI, position: IPosition, token: CancellationToken): Promise<languages.LinkedEditingRanges | undefined> {
417
418
const doc = this._documents.getDocument(resource);
419
const pos = typeConvert.Position.to(position);
420
421
const value = await this._provider.provideLinkedEditingRanges(doc, pos, token);
422
if (value && Array.isArray(value.ranges)) {
423
return {
424
ranges: coalesce(value.ranges.map(typeConvert.Range.from)),
425
wordPattern: value.wordPattern
426
};
427
}
428
return undefined;
429
}
430
}
431
432
class ReferenceAdapter {
433
434
constructor(
435
private readonly _documents: ExtHostDocuments,
436
private readonly _provider: vscode.ReferenceProvider
437
) { }
438
439
async provideReferences(resource: URI, position: IPosition, context: languages.ReferenceContext, token: CancellationToken): Promise<languages.Location[] | undefined> {
440
const doc = this._documents.getDocument(resource);
441
const pos = typeConvert.Position.to(position);
442
443
const value = await this._provider.provideReferences(doc, pos, context, token);
444
if (Array.isArray(value)) {
445
return value.map(typeConvert.location.from);
446
}
447
return undefined;
448
}
449
}
450
451
export interface CustomCodeAction extends extHostProtocol.ICodeActionDto {
452
_isSynthetic?: boolean;
453
}
454
455
class CodeActionAdapter {
456
private static readonly _maxCodeActionsPerFile: number = 1000;
457
458
private readonly _cache = new Cache<vscode.CodeAction | vscode.Command>('CodeAction');
459
private readonly _disposables = new Map<number, DisposableStore>();
460
461
constructor(
462
private readonly _documents: ExtHostDocuments,
463
private readonly _commands: CommandsConverter,
464
private readonly _diagnostics: ExtHostDiagnostics,
465
private readonly _provider: vscode.CodeActionProvider,
466
private readonly _logService: ILogService,
467
private readonly _extension: IExtensionDescription,
468
private readonly _apiDeprecation: IExtHostApiDeprecationService,
469
) { }
470
471
async provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: languages.CodeActionContext, token: CancellationToken): Promise<extHostProtocol.ICodeActionListDto | undefined> {
472
473
const doc = this._documents.getDocument(resource);
474
const ran = Selection.isISelection(rangeOrSelection)
475
? <vscode.Selection>typeConvert.Selection.to(rangeOrSelection)
476
: <vscode.Range>typeConvert.Range.to(rangeOrSelection);
477
const allDiagnostics: vscode.Diagnostic[] = [];
478
479
for (const diagnostic of this._diagnostics.getDiagnostics(resource)) {
480
if (ran.intersection(diagnostic.range)) {
481
const newLen = allDiagnostics.push(diagnostic);
482
if (newLen > CodeActionAdapter._maxCodeActionsPerFile) {
483
break;
484
}
485
}
486
}
487
488
const codeActionContext: vscode.CodeActionContext = {
489
diagnostics: allDiagnostics,
490
only: context.only ? new CodeActionKind(context.only) : undefined,
491
triggerKind: typeConvert.CodeActionTriggerKind.to(context.trigger),
492
};
493
494
const commandsOrActions = await this._provider.provideCodeActions(doc, ran, codeActionContext, token);
495
if (!isNonEmptyArray(commandsOrActions) || token.isCancellationRequested) {
496
return undefined;
497
}
498
499
const cacheId = this._cache.add(commandsOrActions);
500
const disposables = new DisposableStore();
501
this._disposables.set(cacheId, disposables);
502
const actions: CustomCodeAction[] = [];
503
for (let i = 0; i < commandsOrActions.length; i++) {
504
const candidate = commandsOrActions[i];
505
if (!candidate) {
506
continue;
507
}
508
509
if (CodeActionAdapter._isCommand(candidate) && !(candidate instanceof CodeAction)) {
510
// old school: synthetic code action
511
this._apiDeprecation.report('CodeActionProvider.provideCodeActions - return commands', this._extension,
512
`Return 'CodeAction' instances instead.`);
513
514
actions.push({
515
_isSynthetic: true,
516
title: candidate.title,
517
command: this._commands.toInternal(candidate, disposables),
518
});
519
} else {
520
const toConvert = candidate as vscode.CodeAction;
521
522
// new school: convert code action
523
if (codeActionContext.only) {
524
if (!toConvert.kind) {
525
this._logService.warn(`${this._extension.identifier.value} - Code actions of kind '${codeActionContext.only.value}' requested but returned code action does not have a 'kind'. Code action will be dropped. Please set 'CodeAction.kind'.`);
526
} else if (!codeActionContext.only.contains(toConvert.kind)) {
527
this._logService.warn(`${this._extension.identifier.value} - Code actions of kind '${codeActionContext.only.value}' requested but returned code action is of kind '${toConvert.kind.value}'. Code action will be dropped. Please check 'CodeActionContext.only' to only return requested code actions.`);
528
}
529
}
530
531
// Ensures that this is either a Range[] or an empty array so we don't get Array<Range | undefined>
532
const range = toConvert.ranges ?? [];
533
534
actions.push({
535
cacheId: [cacheId, i],
536
title: toConvert.title,
537
command: toConvert.command && this._commands.toInternal(toConvert.command, disposables),
538
diagnostics: toConvert.diagnostics && toConvert.diagnostics.map(typeConvert.Diagnostic.from),
539
edit: toConvert.edit && typeConvert.WorkspaceEdit.from(toConvert.edit, undefined),
540
kind: toConvert.kind && toConvert.kind.value,
541
isPreferred: toConvert.isPreferred,
542
isAI: isProposedApiEnabled(this._extension, 'codeActionAI') ? toConvert.isAI : false,
543
ranges: isProposedApiEnabled(this._extension, 'codeActionRanges') ? coalesce(range.map(typeConvert.Range.from)) : undefined,
544
disabled: toConvert.disabled?.reason
545
});
546
}
547
}
548
return { cacheId, actions };
549
}
550
551
async resolveCodeAction(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<{ edit?: extHostProtocol.IWorkspaceEditDto; command?: extHostProtocol.ICommandDto }> {
552
const [sessionId, itemId] = id;
553
const item = this._cache.get(sessionId, itemId);
554
if (!item || CodeActionAdapter._isCommand(item)) {
555
return {}; // code actions only!
556
}
557
if (!this._provider.resolveCodeAction) {
558
return {}; // this should not happen...
559
}
560
561
562
const resolvedItem = (await this._provider.resolveCodeAction(item, token)) ?? item;
563
564
let resolvedEdit: extHostProtocol.IWorkspaceEditDto | undefined;
565
if (resolvedItem.edit) {
566
resolvedEdit = typeConvert.WorkspaceEdit.from(resolvedItem.edit, undefined);
567
}
568
569
let resolvedCommand: extHostProtocol.ICommandDto | undefined;
570
if (resolvedItem.command) {
571
const disposables = this._disposables.get(sessionId);
572
if (disposables) {
573
resolvedCommand = this._commands.toInternal(resolvedItem.command, disposables);
574
}
575
}
576
577
return { edit: resolvedEdit, command: resolvedCommand };
578
}
579
580
releaseCodeActions(cachedId: number): void {
581
this._disposables.get(cachedId)?.dispose();
582
this._disposables.delete(cachedId);
583
this._cache.delete(cachedId);
584
}
585
586
private static _isCommand(thing: any): thing is vscode.Command {
587
return typeof (<vscode.Command>thing).command === 'string' && typeof (<vscode.Command>thing).title === 'string';
588
}
589
}
590
591
class DocumentPasteEditProvider {
592
593
private _cachedPrepare?: Map<string, vscode.DataTransferItem>;
594
595
private readonly _editsCache = new Cache<vscode.DocumentPasteEdit>('DocumentPasteEdit.edits');
596
597
constructor(
598
private readonly _proxy: extHostProtocol.MainThreadLanguageFeaturesShape,
599
private readonly _documents: ExtHostDocuments,
600
private readonly _provider: vscode.DocumentPasteEditProvider,
601
private readonly _handle: number,
602
private readonly _extension: IExtensionDescription,
603
) { }
604
605
async prepareDocumentPaste(resource: URI, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
606
if (!this._provider.prepareDocumentPaste) {
607
return;
608
}
609
610
this._cachedPrepare = undefined;
611
612
const doc = this._documents.getDocument(resource);
613
const vscodeRanges = ranges.map(range => typeConvert.Range.to(range));
614
615
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, () => {
616
throw new NotImplementedError();
617
});
618
await this._provider.prepareDocumentPaste(doc, vscodeRanges, dataTransfer, token);
619
if (token.isCancellationRequested) {
620
return;
621
}
622
623
// Only send back values that have been added to the data transfer
624
const newEntries = Array.from(dataTransfer).filter(([, value]) => !(value instanceof InternalDataTransferItem));
625
626
// Store off original data transfer items so we can retrieve them on paste
627
const newCache = new Map<string, vscode.DataTransferItem>();
628
629
const items = await Promise.all(Array.from(newEntries, async ([mime, value]) => {
630
const id = generateUuid();
631
newCache.set(id, value);
632
return [mime, await typeConvert.DataTransferItem.from(mime, value, id)] as const;
633
}));
634
635
this._cachedPrepare = newCache;
636
637
return { items };
638
}
639
640
async providePasteEdits(requestId: number, resource: URI, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, context: extHostProtocol.IDocumentPasteContextDto, token: CancellationToken): Promise<extHostProtocol.IPasteEditDto[]> {
641
if (!this._provider.provideDocumentPasteEdits) {
642
return [];
643
}
644
645
const doc = this._documents.getDocument(resource);
646
const vscodeRanges = ranges.map(range => typeConvert.Range.to(range));
647
648
const items = dataTransferDto.items.map(([mime, value]): [string, vscode.DataTransferItem] => {
649
const cached = this._cachedPrepare?.get(value.id);
650
if (cached) {
651
return [mime, cached];
652
}
653
654
return [
655
mime,
656
typeConvert.DataTransferItem.to(mime, value, async id => {
657
return (await this._proxy.$resolvePasteFileData(this._handle, requestId, id)).buffer;
658
})
659
];
660
});
661
662
const dataTransfer = new DataTransfer(items);
663
664
const edits = await this._provider.provideDocumentPasteEdits(doc, vscodeRanges, dataTransfer, {
665
only: context.only ? new DocumentDropOrPasteEditKind(context.only) : undefined,
666
triggerKind: context.triggerKind,
667
}, token);
668
if (!edits || token.isCancellationRequested) {
669
return [];
670
}
671
672
const cacheId = this._editsCache.add(edits);
673
674
return edits.map((edit, i): extHostProtocol.IPasteEditDto => ({
675
_cacheId: [cacheId, i],
676
title: edit.title ?? localize('defaultPasteLabel', "Paste using '{0}' extension", this._extension.displayName || this._extension.name),
677
kind: edit.kind,
678
yieldTo: edit.yieldTo?.map(x => x.value),
679
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
680
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined,
681
}));
682
}
683
684
async resolvePasteEdit(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<{ insertText?: string | vscode.SnippetString; additionalEdit?: extHostProtocol.IWorkspaceEditDto }> {
685
const [sessionId, itemId] = id;
686
const item = this._editsCache.get(sessionId, itemId);
687
if (!item || !this._provider.resolveDocumentPasteEdit) {
688
return {}; // this should not happen...
689
}
690
691
const resolvedItem = (await this._provider.resolveDocumentPasteEdit(item, token)) ?? item;
692
return {
693
insertText: resolvedItem.insertText,
694
additionalEdit: resolvedItem.additionalEdit ? typeConvert.WorkspaceEdit.from(resolvedItem.additionalEdit, undefined) : undefined
695
};
696
}
697
698
releasePasteEdits(id: number): any {
699
this._editsCache.delete(id);
700
}
701
}
702
703
class DocumentFormattingAdapter {
704
705
constructor(
706
private readonly _documents: ExtHostDocuments,
707
private readonly _provider: vscode.DocumentFormattingEditProvider
708
) { }
709
710
async provideDocumentFormattingEdits(resource: URI, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> {
711
712
const document = this._documents.getDocument(resource);
713
714
// eslint-disable-next-line local/code-no-any-casts
715
const value = await this._provider.provideDocumentFormattingEdits(document, <any>options, token);
716
if (Array.isArray(value)) {
717
return value.map(typeConvert.TextEdit.from);
718
}
719
return undefined;
720
}
721
}
722
723
class RangeFormattingAdapter {
724
725
constructor(
726
private readonly _documents: ExtHostDocuments,
727
private readonly _provider: vscode.DocumentRangeFormattingEditProvider
728
) { }
729
730
async provideDocumentRangeFormattingEdits(resource: URI, range: IRange, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> {
731
732
const document = this._documents.getDocument(resource);
733
const ran = typeConvert.Range.to(range);
734
735
// eslint-disable-next-line local/code-no-any-casts
736
const value = await this._provider.provideDocumentRangeFormattingEdits(document, ran, <any>options, token);
737
if (Array.isArray(value)) {
738
return value.map(typeConvert.TextEdit.from);
739
}
740
return undefined;
741
}
742
743
async provideDocumentRangesFormattingEdits(resource: URI, ranges: IRange[], options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> {
744
assertType(typeof this._provider.provideDocumentRangesFormattingEdits === 'function', 'INVALID invocation of `provideDocumentRangesFormattingEdits`');
745
746
const document = this._documents.getDocument(resource);
747
const _ranges = <Range[]>ranges.map(typeConvert.Range.to);
748
// eslint-disable-next-line local/code-no-any-casts
749
const value = await this._provider.provideDocumentRangesFormattingEdits(document, _ranges, <any>options, token);
750
if (Array.isArray(value)) {
751
return value.map(typeConvert.TextEdit.from);
752
}
753
return undefined;
754
}
755
}
756
757
class OnTypeFormattingAdapter {
758
759
constructor(
760
private readonly _documents: ExtHostDocuments,
761
private readonly _provider: vscode.OnTypeFormattingEditProvider
762
) { }
763
764
autoFormatTriggerCharacters: string[] = []; // not here
765
766
async provideOnTypeFormattingEdits(resource: URI, position: IPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> {
767
768
const document = this._documents.getDocument(resource);
769
const pos = typeConvert.Position.to(position);
770
771
// eslint-disable-next-line local/code-no-any-casts
772
const value = await this._provider.provideOnTypeFormattingEdits(document, pos, ch, <any>options, token);
773
if (Array.isArray(value)) {
774
return value.map(typeConvert.TextEdit.from);
775
}
776
return undefined;
777
}
778
}
779
780
class NavigateTypeAdapter {
781
782
private readonly _cache = new Cache<vscode.SymbolInformation>('WorkspaceSymbols');
783
784
constructor(
785
private readonly _provider: vscode.WorkspaceSymbolProvider,
786
private readonly _logService: ILogService
787
) { }
788
789
async provideWorkspaceSymbols(search: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolsDto> {
790
const value = await this._provider.provideWorkspaceSymbols(search, token);
791
792
if (!isNonEmptyArray(value)) {
793
return { symbols: [] };
794
}
795
796
const sid = this._cache.add(value);
797
const result: extHostProtocol.IWorkspaceSymbolsDto = {
798
cacheId: sid,
799
symbols: []
800
};
801
802
for (let i = 0; i < value.length; i++) {
803
const item = value[i];
804
if (!item || !item.name) {
805
this._logService.warn('INVALID SymbolInformation', item);
806
continue;
807
}
808
result.symbols.push({
809
...typeConvert.WorkspaceSymbol.from(item),
810
cacheId: [sid, i]
811
});
812
}
813
814
return result;
815
}
816
817
async resolveWorkspaceSymbol(symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolDto | undefined> {
818
if (typeof this._provider.resolveWorkspaceSymbol !== 'function') {
819
return symbol;
820
}
821
if (!symbol.cacheId) {
822
return symbol;
823
}
824
const item = this._cache.get(...symbol.cacheId);
825
if (item) {
826
const value = await this._provider.resolveWorkspaceSymbol(item, token);
827
return value && mixin(symbol, typeConvert.WorkspaceSymbol.from(value), true);
828
}
829
return undefined;
830
}
831
832
releaseWorkspaceSymbols(id: number): any {
833
this._cache.delete(id);
834
}
835
}
836
837
class RenameAdapter {
838
839
static supportsResolving(provider: vscode.RenameProvider): boolean {
840
return typeof provider.prepareRename === 'function';
841
}
842
843
constructor(
844
private readonly _documents: ExtHostDocuments,
845
private readonly _provider: vscode.RenameProvider,
846
private readonly _logService: ILogService
847
) { }
848
849
async provideRenameEdits(resource: URI, position: IPosition, newName: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto & languages.Rejection | undefined> {
850
851
const doc = this._documents.getDocument(resource);
852
const pos = typeConvert.Position.to(position);
853
854
try {
855
const value = await this._provider.provideRenameEdits(doc, pos, newName, token);
856
if (!value) {
857
return undefined;
858
}
859
return typeConvert.WorkspaceEdit.from(value);
860
861
} catch (err) {
862
const rejectReason = RenameAdapter._asMessage(err);
863
if (rejectReason) {
864
return { rejectReason, edits: undefined! };
865
} else {
866
// generic error
867
return Promise.reject<extHostProtocol.IWorkspaceEditDto>(err);
868
}
869
}
870
}
871
872
async resolveRenameLocation(resource: URI, position: IPosition, token: CancellationToken): Promise<(languages.RenameLocation & languages.Rejection) | undefined> {
873
if (typeof this._provider.prepareRename !== 'function') {
874
return Promise.resolve(undefined);
875
}
876
877
const doc = this._documents.getDocument(resource);
878
const pos = typeConvert.Position.to(position);
879
880
try {
881
const rangeOrLocation = await this._provider.prepareRename(doc, pos, token);
882
883
let range: vscode.Range | undefined;
884
let text: string | undefined;
885
if (Range.isRange(rangeOrLocation)) {
886
range = rangeOrLocation;
887
text = doc.getText(rangeOrLocation);
888
889
} else if (isObject(rangeOrLocation)) {
890
range = rangeOrLocation.range;
891
text = rangeOrLocation.placeholder;
892
}
893
894
if (!range || !text) {
895
return undefined;
896
}
897
if (range.start.line > pos.line || range.end.line < pos.line) {
898
this._logService.warn('INVALID rename location: position line must be within range start/end lines');
899
return undefined;
900
}
901
return { range: typeConvert.Range.from(range), text };
902
903
} catch (err) {
904
const rejectReason = RenameAdapter._asMessage(err);
905
if (rejectReason) {
906
return { rejectReason, range: undefined!, text: undefined! };
907
} else {
908
return Promise.reject<any>(err);
909
}
910
}
911
}
912
913
private static _asMessage(err: any): string | undefined {
914
if (typeof err === 'string') {
915
return err;
916
} else if (err instanceof Error && typeof err.message === 'string') {
917
return err.message;
918
} else {
919
return undefined;
920
}
921
}
922
}
923
924
class NewSymbolNamesAdapter {
925
926
private static languageTriggerKindToVSCodeTriggerKind: Record<languages.NewSymbolNameTriggerKind, vscode.NewSymbolNameTriggerKind> = {
927
[languages.NewSymbolNameTriggerKind.Invoke]: NewSymbolNameTriggerKind.Invoke,
928
[languages.NewSymbolNameTriggerKind.Automatic]: NewSymbolNameTriggerKind.Automatic,
929
};
930
931
constructor(
932
private readonly _documents: ExtHostDocuments,
933
private readonly _provider: vscode.NewSymbolNamesProvider,
934
private readonly _logService: ILogService
935
) { }
936
937
async supportsAutomaticNewSymbolNamesTriggerKind() {
938
return this._provider.supportsAutomaticTriggerKind;
939
}
940
941
async provideNewSymbolNames(resource: URI, range: IRange, triggerKind: languages.NewSymbolNameTriggerKind, token: CancellationToken): Promise<languages.NewSymbolName[] | undefined> {
942
943
const doc = this._documents.getDocument(resource);
944
const pos = typeConvert.Range.to(range);
945
946
try {
947
const kind = NewSymbolNamesAdapter.languageTriggerKindToVSCodeTriggerKind[triggerKind];
948
const value = await this._provider.provideNewSymbolNames(doc, pos, kind, token);
949
if (!value) {
950
return undefined;
951
}
952
return value.map(v =>
953
typeof v === 'string' /* @ulugbekna: for backward compatibility because `value` used to be just `string[]` */
954
? { newSymbolName: v }
955
: { newSymbolName: v.newSymbolName, tags: v.tags }
956
);
957
} catch (err: unknown) {
958
this._logService.error(NewSymbolNamesAdapter._asMessage(err) ?? JSON.stringify(err, null, '\t') /* @ulugbekna: assuming `err` doesn't have circular references that could result in an exception when converting to JSON */);
959
return undefined;
960
}
961
}
962
963
// @ulugbekna: this method is also defined in RenameAdapter but seems OK to be duplicated
964
private static _asMessage(err: any): string | undefined {
965
if (typeof err === 'string') {
966
return err;
967
} else if (err instanceof Error && typeof err.message === 'string') {
968
return err.message;
969
} else {
970
return undefined;
971
}
972
}
973
}
974
975
class SemanticTokensPreviousResult {
976
constructor(
977
readonly resultId: string | undefined,
978
readonly tokens?: Uint32Array,
979
) { }
980
}
981
982
type RelaxedSemanticTokens = { readonly resultId?: string; readonly data: number[] };
983
type RelaxedSemanticTokensEdit = { readonly start: number; readonly deleteCount: number; readonly data?: number[] };
984
type RelaxedSemanticTokensEdits = { readonly resultId?: string; readonly edits: RelaxedSemanticTokensEdit[] };
985
986
type ProvidedSemanticTokens = vscode.SemanticTokens | RelaxedSemanticTokens;
987
type ProvidedSemanticTokensEdits = vscode.SemanticTokensEdits | RelaxedSemanticTokensEdits;
988
989
class DocumentSemanticTokensAdapter {
990
991
private readonly _previousResults: Map<number, SemanticTokensPreviousResult>;
992
private _nextResultId = 1;
993
994
constructor(
995
private readonly _documents: ExtHostDocuments,
996
private readonly _provider: vscode.DocumentSemanticTokensProvider,
997
) {
998
this._previousResults = new Map<number, SemanticTokensPreviousResult>();
999
}
1000
1001
async provideDocumentSemanticTokens(resource: URI, previousResultId: number, token: CancellationToken): Promise<VSBuffer | null> {
1002
const doc = this._documents.getDocument(resource);
1003
const previousResult = (previousResultId !== 0 ? this._previousResults.get(previousResultId) : null);
1004
let value = typeof previousResult?.resultId === 'string' && typeof this._provider.provideDocumentSemanticTokensEdits === 'function'
1005
? await this._provider.provideDocumentSemanticTokensEdits(doc, previousResult.resultId, token)
1006
: await this._provider.provideDocumentSemanticTokens(doc, token);
1007
1008
if (previousResult) {
1009
this._previousResults.delete(previousResultId);
1010
}
1011
if (!value) {
1012
return null;
1013
}
1014
value = DocumentSemanticTokensAdapter._fixProvidedSemanticTokens(value);
1015
return this._send(DocumentSemanticTokensAdapter._convertToEdits(previousResult, value), value);
1016
}
1017
1018
async releaseDocumentSemanticColoring(semanticColoringResultId: number): Promise<void> {
1019
this._previousResults.delete(semanticColoringResultId);
1020
}
1021
1022
private static _fixProvidedSemanticTokens(v: ProvidedSemanticTokens | ProvidedSemanticTokensEdits): vscode.SemanticTokens | vscode.SemanticTokensEdits {
1023
if (DocumentSemanticTokensAdapter._isSemanticTokens(v)) {
1024
if (DocumentSemanticTokensAdapter._isCorrectSemanticTokens(v)) {
1025
return v;
1026
}
1027
return new SemanticTokens(new Uint32Array(v.data), v.resultId);
1028
} else if (DocumentSemanticTokensAdapter._isSemanticTokensEdits(v)) {
1029
if (DocumentSemanticTokensAdapter._isCorrectSemanticTokensEdits(v)) {
1030
return v;
1031
}
1032
return new SemanticTokensEdits(v.edits.map(edit => new SemanticTokensEdit(edit.start, edit.deleteCount, edit.data ? new Uint32Array(edit.data) : edit.data)), v.resultId);
1033
}
1034
return v;
1035
}
1036
1037
private static _isSemanticTokens(v: ProvidedSemanticTokens | ProvidedSemanticTokensEdits): v is ProvidedSemanticTokens {
1038
return v && !!((v as ProvidedSemanticTokens).data);
1039
}
1040
1041
private static _isCorrectSemanticTokens(v: ProvidedSemanticTokens): v is vscode.SemanticTokens {
1042
return (v.data instanceof Uint32Array);
1043
}
1044
1045
private static _isSemanticTokensEdits(v: ProvidedSemanticTokens | ProvidedSemanticTokensEdits): v is ProvidedSemanticTokensEdits {
1046
return v && Array.isArray((v as ProvidedSemanticTokensEdits).edits);
1047
}
1048
1049
private static _isCorrectSemanticTokensEdits(v: ProvidedSemanticTokensEdits): v is vscode.SemanticTokensEdits {
1050
for (const edit of v.edits) {
1051
if (!(edit.data instanceof Uint32Array)) {
1052
return false;
1053
}
1054
}
1055
return true;
1056
}
1057
1058
private static _convertToEdits(previousResult: SemanticTokensPreviousResult | null | undefined, newResult: vscode.SemanticTokens | vscode.SemanticTokensEdits): vscode.SemanticTokens | vscode.SemanticTokensEdits {
1059
if (!DocumentSemanticTokensAdapter._isSemanticTokens(newResult)) {
1060
return newResult;
1061
}
1062
if (!previousResult || !previousResult.tokens) {
1063
return newResult;
1064
}
1065
const oldData = previousResult.tokens;
1066
const oldLength = oldData.length;
1067
const newData = newResult.data;
1068
const newLength = newData.length;
1069
1070
let commonPrefixLength = 0;
1071
const maxCommonPrefixLength = Math.min(oldLength, newLength);
1072
while (commonPrefixLength < maxCommonPrefixLength && oldData[commonPrefixLength] === newData[commonPrefixLength]) {
1073
commonPrefixLength++;
1074
}
1075
1076
if (commonPrefixLength === oldLength && commonPrefixLength === newLength) {
1077
// complete overlap!
1078
return new SemanticTokensEdits([], newResult.resultId);
1079
}
1080
1081
let commonSuffixLength = 0;
1082
const maxCommonSuffixLength = maxCommonPrefixLength - commonPrefixLength;
1083
while (commonSuffixLength < maxCommonSuffixLength && oldData[oldLength - commonSuffixLength - 1] === newData[newLength - commonSuffixLength - 1]) {
1084
commonSuffixLength++;
1085
}
1086
1087
return new SemanticTokensEdits([{
1088
start: commonPrefixLength,
1089
deleteCount: (oldLength - commonPrefixLength - commonSuffixLength),
1090
data: newData.subarray(commonPrefixLength, newLength - commonSuffixLength)
1091
}], newResult.resultId);
1092
}
1093
1094
private _send(value: vscode.SemanticTokens | vscode.SemanticTokensEdits, original: vscode.SemanticTokens | vscode.SemanticTokensEdits): VSBuffer | null {
1095
if (DocumentSemanticTokensAdapter._isSemanticTokens(value)) {
1096
const myId = this._nextResultId++;
1097
this._previousResults.set(myId, new SemanticTokensPreviousResult(value.resultId, value.data));
1098
return encodeSemanticTokensDto({
1099
id: myId,
1100
type: 'full',
1101
data: value.data
1102
});
1103
}
1104
1105
if (DocumentSemanticTokensAdapter._isSemanticTokensEdits(value)) {
1106
const myId = this._nextResultId++;
1107
if (DocumentSemanticTokensAdapter._isSemanticTokens(original)) {
1108
// store the original
1109
this._previousResults.set(myId, new SemanticTokensPreviousResult(original.resultId, original.data));
1110
} else {
1111
this._previousResults.set(myId, new SemanticTokensPreviousResult(value.resultId));
1112
}
1113
return encodeSemanticTokensDto({
1114
id: myId,
1115
type: 'delta',
1116
deltas: (value.edits || []).map(edit => ({ start: edit.start, deleteCount: edit.deleteCount, data: edit.data }))
1117
});
1118
}
1119
1120
return null;
1121
}
1122
}
1123
1124
class DocumentRangeSemanticTokensAdapter {
1125
1126
constructor(
1127
private readonly _documents: ExtHostDocuments,
1128
private readonly _provider: vscode.DocumentRangeSemanticTokensProvider,
1129
) { }
1130
1131
async provideDocumentRangeSemanticTokens(resource: URI, range: IRange, token: CancellationToken): Promise<VSBuffer | null> {
1132
const doc = this._documents.getDocument(resource);
1133
const value = await this._provider.provideDocumentRangeSemanticTokens(doc, typeConvert.Range.to(range), token);
1134
if (!value) {
1135
return null;
1136
}
1137
return this._send(value);
1138
}
1139
1140
private _send(value: vscode.SemanticTokens): VSBuffer {
1141
return encodeSemanticTokensDto({
1142
id: 0,
1143
type: 'full',
1144
data: value.data
1145
});
1146
}
1147
}
1148
1149
class CompletionsAdapter {
1150
1151
static supportsResolving(provider: vscode.CompletionItemProvider): boolean {
1152
return typeof provider.resolveCompletionItem === 'function';
1153
}
1154
1155
private _cache = new Cache<vscode.CompletionItem>('CompletionItem');
1156
private _disposables = new Map<number, DisposableStore>();
1157
1158
constructor(
1159
private readonly _documents: ExtHostDocuments,
1160
private readonly _commands: CommandsConverter,
1161
private readonly _provider: vscode.CompletionItemProvider,
1162
private readonly _apiDeprecation: IExtHostApiDeprecationService,
1163
private readonly _extension: IExtensionDescription,
1164
) { }
1165
1166
async provideCompletionItems(resource: URI, position: IPosition, context: languages.CompletionContext, token: CancellationToken): Promise<extHostProtocol.ISuggestResultDto | undefined> {
1167
1168
const doc = this._documents.getDocument(resource);
1169
const pos = typeConvert.Position.to(position);
1170
1171
// The default insert/replace ranges. It's important to compute them
1172
// before asynchronously asking the provider for its results. See
1173
// https://github.com/microsoft/vscode/issues/83400#issuecomment-546851421
1174
const replaceRange = doc.getWordRangeAtPosition(pos) || new Range(pos, pos);
1175
const insertRange = replaceRange.with({ end: pos });
1176
1177
const sw = new StopWatch();
1178
const itemsOrList = await this._provider.provideCompletionItems(doc, pos, token, typeConvert.CompletionContext.to(context));
1179
1180
if (!itemsOrList) {
1181
// undefined and null are valid results
1182
return undefined;
1183
}
1184
1185
if (token.isCancellationRequested) {
1186
// cancelled -> return without further ado, esp no caching
1187
// of results as they will leak
1188
return undefined;
1189
}
1190
1191
const list = Array.isArray(itemsOrList) ? new CompletionList(itemsOrList) : itemsOrList;
1192
1193
// keep result for providers that support resolving
1194
const pid: number = CompletionsAdapter.supportsResolving(this._provider) ? this._cache.add(list.items) : this._cache.add([]);
1195
const disposables = new DisposableStore();
1196
this._disposables.set(pid, disposables);
1197
1198
const completions: extHostProtocol.ISuggestDataDto[] = [];
1199
const result: extHostProtocol.ISuggestResultDto = {
1200
x: pid,
1201
[extHostProtocol.ISuggestResultDtoField.completions]: completions,
1202
[extHostProtocol.ISuggestResultDtoField.defaultRanges]: { replace: typeConvert.Range.from(replaceRange), insert: typeConvert.Range.from(insertRange) },
1203
[extHostProtocol.ISuggestResultDtoField.isIncomplete]: list.isIncomplete || undefined,
1204
[extHostProtocol.ISuggestResultDtoField.duration]: sw.elapsed()
1205
};
1206
1207
for (let i = 0; i < list.items.length; i++) {
1208
const item = list.items[i];
1209
// check for bad completion item first
1210
const dto = this._convertCompletionItem(item, [pid, i], insertRange, replaceRange);
1211
completions.push(dto);
1212
}
1213
1214
return result;
1215
}
1216
1217
async resolveCompletionItem(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
1218
1219
if (typeof this._provider.resolveCompletionItem !== 'function') {
1220
return undefined;
1221
}
1222
1223
const item = this._cache.get(...id);
1224
if (!item) {
1225
return undefined;
1226
}
1227
1228
const dto1 = this._convertCompletionItem(item, id);
1229
1230
const resolvedItem = await this._provider.resolveCompletionItem(item, token);
1231
1232
if (!resolvedItem) {
1233
return undefined;
1234
}
1235
1236
const dto2 = this._convertCompletionItem(resolvedItem, id);
1237
1238
if (dto1[extHostProtocol.ISuggestDataDtoField.insertText] !== dto2[extHostProtocol.ISuggestDataDtoField.insertText]
1239
|| dto1[extHostProtocol.ISuggestDataDtoField.insertTextRules] !== dto2[extHostProtocol.ISuggestDataDtoField.insertTextRules]
1240
) {
1241
this._apiDeprecation.report('CompletionItem.insertText', this._extension, 'extension MAY NOT change \'insertText\' of a CompletionItem during resolve');
1242
}
1243
1244
if (dto1[extHostProtocol.ISuggestDataDtoField.commandIdent] !== dto2[extHostProtocol.ISuggestDataDtoField.commandIdent]
1245
|| dto1[extHostProtocol.ISuggestDataDtoField.commandId] !== dto2[extHostProtocol.ISuggestDataDtoField.commandId]
1246
|| !equals(dto1[extHostProtocol.ISuggestDataDtoField.commandArguments], dto2[extHostProtocol.ISuggestDataDtoField.commandArguments])
1247
) {
1248
this._apiDeprecation.report('CompletionItem.command', this._extension, 'extension MAY NOT change \'command\' of a CompletionItem during resolve');
1249
}
1250
1251
return {
1252
...dto1,
1253
[extHostProtocol.ISuggestDataDtoField.documentation]: dto2[extHostProtocol.ISuggestDataDtoField.documentation],
1254
[extHostProtocol.ISuggestDataDtoField.detail]: dto2[extHostProtocol.ISuggestDataDtoField.detail],
1255
[extHostProtocol.ISuggestDataDtoField.additionalTextEdits]: dto2[extHostProtocol.ISuggestDataDtoField.additionalTextEdits],
1256
1257
// (fishy) async insertText
1258
[extHostProtocol.ISuggestDataDtoField.insertText]: dto2[extHostProtocol.ISuggestDataDtoField.insertText],
1259
[extHostProtocol.ISuggestDataDtoField.insertTextRules]: dto2[extHostProtocol.ISuggestDataDtoField.insertTextRules],
1260
1261
// (fishy) async command
1262
[extHostProtocol.ISuggestDataDtoField.commandIdent]: dto2[extHostProtocol.ISuggestDataDtoField.commandIdent],
1263
[extHostProtocol.ISuggestDataDtoField.commandId]: dto2[extHostProtocol.ISuggestDataDtoField.commandId],
1264
[extHostProtocol.ISuggestDataDtoField.commandArguments]: dto2[extHostProtocol.ISuggestDataDtoField.commandArguments],
1265
};
1266
}
1267
1268
releaseCompletionItems(id: number): any {
1269
this._disposables.get(id)?.dispose();
1270
this._disposables.delete(id);
1271
this._cache.delete(id);
1272
}
1273
1274
private _convertCompletionItem(item: vscode.CompletionItem, id: extHostProtocol.ChainedCacheId, defaultInsertRange?: vscode.Range, defaultReplaceRange?: vscode.Range): extHostProtocol.ISuggestDataDto {
1275
1276
const disposables = this._disposables.get(id[0]);
1277
if (!disposables) {
1278
throw Error('DisposableStore is missing...');
1279
}
1280
1281
const command = this._commands.toInternal(item.command, disposables);
1282
const result: extHostProtocol.ISuggestDataDto = {
1283
//
1284
x: id,
1285
//
1286
[extHostProtocol.ISuggestDataDtoField.label]: item.label,
1287
[extHostProtocol.ISuggestDataDtoField.kind]: item.kind !== undefined ? typeConvert.CompletionItemKind.from(item.kind) : undefined,
1288
[extHostProtocol.ISuggestDataDtoField.kindModifier]: item.tags && item.tags.map(typeConvert.CompletionItemTag.from),
1289
[extHostProtocol.ISuggestDataDtoField.detail]: item.detail,
1290
[extHostProtocol.ISuggestDataDtoField.documentation]: typeof item.documentation === 'undefined' ? undefined : typeConvert.MarkdownString.fromStrict(item.documentation),
1291
[extHostProtocol.ISuggestDataDtoField.sortText]: item.sortText !== item.label ? item.sortText : undefined,
1292
[extHostProtocol.ISuggestDataDtoField.filterText]: item.filterText !== item.label ? item.filterText : undefined,
1293
[extHostProtocol.ISuggestDataDtoField.preselect]: item.preselect || undefined,
1294
[extHostProtocol.ISuggestDataDtoField.insertTextRules]: item.keepWhitespace ? languages.CompletionItemInsertTextRule.KeepWhitespace : languages.CompletionItemInsertTextRule.None,
1295
[extHostProtocol.ISuggestDataDtoField.commitCharacters]: item.commitCharacters?.join(''),
1296
[extHostProtocol.ISuggestDataDtoField.additionalTextEdits]: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from),
1297
[extHostProtocol.ISuggestDataDtoField.commandIdent]: command?.$ident,
1298
[extHostProtocol.ISuggestDataDtoField.commandId]: command?.id,
1299
[extHostProtocol.ISuggestDataDtoField.commandArguments]: command?.$ident ? undefined : command?.arguments, // filled in on main side from $ident
1300
};
1301
1302
// 'insertText'-logic
1303
if (item.textEdit) {
1304
this._apiDeprecation.report('CompletionItem.textEdit', this._extension, `Use 'CompletionItem.insertText' and 'CompletionItem.range' instead.`);
1305
result[extHostProtocol.ISuggestDataDtoField.insertText] = item.textEdit.newText;
1306
1307
} else if (typeof item.insertText === 'string') {
1308
result[extHostProtocol.ISuggestDataDtoField.insertText] = item.insertText;
1309
1310
} else if (item.insertText instanceof SnippetString) {
1311
result[extHostProtocol.ISuggestDataDtoField.insertText] = item.insertText.value;
1312
result[extHostProtocol.ISuggestDataDtoField.insertTextRules]! |= languages.CompletionItemInsertTextRule.InsertAsSnippet;
1313
}
1314
1315
// 'overwrite[Before|After]'-logic
1316
let range: vscode.Range | { inserting: vscode.Range; replacing: vscode.Range } | undefined;
1317
if (item.textEdit) {
1318
range = item.textEdit.range;
1319
} else if (item.range) {
1320
range = item.range;
1321
}
1322
1323
if (Range.isRange(range)) {
1324
// "old" range
1325
result[extHostProtocol.ISuggestDataDtoField.range] = typeConvert.Range.from(range);
1326
1327
} else if (range && (!defaultInsertRange?.isEqual(range.inserting) || !defaultReplaceRange?.isEqual(range.replacing))) {
1328
// ONLY send range when it's different from the default ranges (safe bandwidth)
1329
result[extHostProtocol.ISuggestDataDtoField.range] = {
1330
insert: typeConvert.Range.from(range.inserting),
1331
replace: typeConvert.Range.from(range.replacing)
1332
};
1333
}
1334
1335
return result;
1336
}
1337
}
1338
1339
class InlineCompletionAdapter {
1340
private readonly _references = new ReferenceMap<{
1341
dispose(): void;
1342
items: readonly vscode.InlineCompletionItem[];
1343
list: vscode.InlineCompletionList | undefined;
1344
}>();
1345
1346
private readonly _isAdditionsProposedApiEnabled: boolean;
1347
1348
constructor(
1349
private readonly _extension: IExtensionDescription,
1350
private readonly _documents: ExtHostDocuments,
1351
private readonly _provider: vscode.InlineCompletionItemProvider,
1352
private readonly _commands: CommandsConverter,
1353
) {
1354
this._isAdditionsProposedApiEnabled = isProposedApiEnabled(this._extension, 'inlineCompletionsAdditions');
1355
}
1356
1357
public get supportsHandleEvents(): boolean {
1358
return isProposedApiEnabled(this._extension, 'inlineCompletionsAdditions')
1359
&& (typeof this._provider.handleDidShowCompletionItem === 'function'
1360
|| typeof this._provider.handleDidPartiallyAcceptCompletionItem === 'function'
1361
|| typeof this._provider.handleDidRejectCompletionItem === 'function'
1362
|| typeof this._provider.handleEndOfLifetime === 'function'
1363
);
1364
}
1365
1366
public get supportsSetModelId(): boolean {
1367
return isProposedApiEnabled(this._extension, 'inlineCompletionsAdditions')
1368
&& typeof this._provider.setCurrentModelId === 'function';
1369
}
1370
1371
private readonly languageTriggerKindToVSCodeTriggerKind: Record<languages.InlineCompletionTriggerKind, InlineCompletionTriggerKind> = {
1372
[languages.InlineCompletionTriggerKind.Automatic]: InlineCompletionTriggerKind.Automatic,
1373
[languages.InlineCompletionTriggerKind.Explicit]: InlineCompletionTriggerKind.Invoke,
1374
};
1375
1376
public get modelInfo(): extHostProtocol.IInlineCompletionModelInfoDto | undefined {
1377
if (!this._isAdditionsProposedApiEnabled) {
1378
return undefined;
1379
}
1380
return this._provider.modelInfo ? {
1381
models: this._provider.modelInfo.models,
1382
currentModelId: this._provider.modelInfo.currentModelId
1383
} : undefined;
1384
}
1385
1386
setCurrentModelId(modelId: string): void {
1387
if (!this._isAdditionsProposedApiEnabled) {
1388
return;
1389
}
1390
this._provider.setCurrentModelId?.(modelId);
1391
}
1392
1393
async provideInlineCompletions(resource: URI, position: IPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise<extHostProtocol.IdentifiableInlineCompletions | undefined> {
1394
const doc = this._documents.getDocument(resource);
1395
const pos = typeConvert.Position.to(position);
1396
1397
const result = await this._provider.provideInlineCompletionItems(doc, pos, {
1398
selectedCompletionInfo:
1399
context.selectedSuggestionInfo
1400
? {
1401
range: typeConvert.Range.to(context.selectedSuggestionInfo.range),
1402
text: context.selectedSuggestionInfo.text
1403
}
1404
: undefined,
1405
triggerKind: this.languageTriggerKindToVSCodeTriggerKind[context.triggerKind],
1406
requestUuid: context.requestUuid,
1407
requestIssuedDateTime: context.requestIssuedDateTime,
1408
earliestShownDateTime: context.earliestShownDateTime,
1409
changeHint: context.changeHint,
1410
}, token);
1411
1412
if (!result) {
1413
// undefined and null are valid results
1414
return undefined;
1415
}
1416
1417
const { resultItems, list } = Array.isArray(result) ? { resultItems: result, list: undefined } : { resultItems: result.items, list: result };
1418
const commands = this._isAdditionsProposedApiEnabled ? Array.isArray(result) ? [] : result.commands || [] : [];
1419
const enableForwardStability = this._isAdditionsProposedApiEnabled && !Array.isArray(result) ? result.enableForwardStability : undefined;
1420
1421
let disposableStore: DisposableStore | undefined = undefined;
1422
const pid = this._references.createReferenceId({
1423
dispose() {
1424
disposableStore?.dispose();
1425
},
1426
items: resultItems,
1427
list,
1428
});
1429
1430
const items = {
1431
pid,
1432
languageId: doc.languageId,
1433
items: resultItems.map<extHostProtocol.IdentifiableInlineCompletion>((item, idx) => {
1434
let command: languages.Command | undefined = undefined;
1435
if (item.command) {
1436
if (!disposableStore) {
1437
disposableStore = new DisposableStore();
1438
}
1439
command = this._commands.toInternal(item.command, disposableStore);
1440
}
1441
1442
let action: languages.Command | undefined = undefined;
1443
if (item.action) {
1444
if (!disposableStore) {
1445
disposableStore = new DisposableStore();
1446
}
1447
action = this._commands.toInternal(item.action, disposableStore);
1448
}
1449
1450
const insertText = item.insertText;
1451
return ({
1452
insertText: insertText === undefined ? undefined : (typeof insertText === 'string' ? insertText : { snippet: insertText.value }),
1453
range: item.range ? typeConvert.Range.from(item.range) : undefined,
1454
showRange: (this._isAdditionsProposedApiEnabled && item.showRange) ? typeConvert.Range.from(item.showRange) : undefined,
1455
command,
1456
gutterMenuLinkAction: action,
1457
idx: idx,
1458
completeBracketPairs: this._isAdditionsProposedApiEnabled ? item.completeBracketPairs : false,
1459
isInlineEdit: this._isAdditionsProposedApiEnabled ? item.isInlineEdit : false,
1460
showInlineEditMenu: this._isAdditionsProposedApiEnabled ? item.showInlineEditMenu : false,
1461
hint: (item.displayLocation && this._isAdditionsProposedApiEnabled) ? {
1462
range: typeConvert.Range.from(item.displayLocation.range),
1463
content: item.displayLocation.label,
1464
style: item.displayLocation.kind ? typeConvert.InlineCompletionHintStyle.from(item.displayLocation.kind) : languages.InlineCompletionHintStyle.Code,
1465
} : undefined,
1466
warning: (item.warning && this._isAdditionsProposedApiEnabled) ? {
1467
message: typeConvert.MarkdownString.from(item.warning.message),
1468
icon: item.warning.icon ? typeConvert.IconPath.fromThemeIcon(item.warning.icon) : undefined,
1469
} : undefined,
1470
correlationId: this._isAdditionsProposedApiEnabled ? item.correlationId : undefined,
1471
suggestionId: undefined,
1472
uri: (this._isAdditionsProposedApiEnabled && item.uri) ? item.uri : undefined,
1473
supportsRename: this._isAdditionsProposedApiEnabled ? item.supportsRename : false,
1474
jumpToPosition: (this._isAdditionsProposedApiEnabled && item.jumpToPosition) ? typeConvert.Position.from(item.jumpToPosition) : undefined,
1475
});
1476
}),
1477
commands: commands.map(c => {
1478
if (!disposableStore) {
1479
disposableStore = new DisposableStore();
1480
}
1481
return typeConvert.CompletionCommand.from(c, this._commands, disposableStore);
1482
}),
1483
suppressSuggestions: false,
1484
enableForwardStability,
1485
} satisfies extHostProtocol.IdentifiableInlineCompletions;
1486
return items;
1487
}
1488
1489
disposeCompletions(pid: number, reason: languages.InlineCompletionsDisposeReason) {
1490
const completionList = this._references.get(pid);
1491
if (this._provider.handleListEndOfLifetime && this._isAdditionsProposedApiEnabled && completionList?.list) {
1492
function translateReason(reason: languages.InlineCompletionsDisposeReason): vscode.InlineCompletionsDisposeReason {
1493
switch (reason.kind) {
1494
case 'lostRace':
1495
return { kind: InlineCompletionsDisposeReasonKind.LostRace };
1496
case 'tokenCancellation':
1497
return { kind: InlineCompletionsDisposeReasonKind.TokenCancellation };
1498
case 'other':
1499
return { kind: InlineCompletionsDisposeReasonKind.Other };
1500
case 'empty':
1501
return { kind: InlineCompletionsDisposeReasonKind.Empty };
1502
case 'notTaken':
1503
return { kind: InlineCompletionsDisposeReasonKind.NotTaken };
1504
default:
1505
return { kind: InlineCompletionsDisposeReasonKind.Other };
1506
}
1507
}
1508
1509
this._provider.handleListEndOfLifetime(completionList.list, translateReason(reason));
1510
}
1511
1512
const data = this._references.disposeReferenceId(pid);
1513
data?.dispose();
1514
}
1515
1516
handleDidShowCompletionItem(pid: number, idx: number, updatedInsertText: string): void {
1517
const completionItem = this._references.get(pid)?.items[idx];
1518
if (completionItem) {
1519
if (this._provider.handleDidShowCompletionItem && this._isAdditionsProposedApiEnabled) {
1520
this._provider.handleDidShowCompletionItem(completionItem, updatedInsertText);
1521
}
1522
}
1523
}
1524
1525
handlePartialAccept(pid: number, idx: number, acceptedCharacters: number, info: languages.PartialAcceptInfo): void {
1526
const completionItem = this._references.get(pid)?.items[idx];
1527
if (completionItem) {
1528
if (this._provider.handleDidPartiallyAcceptCompletionItem && this._isAdditionsProposedApiEnabled) {
1529
this._provider.handleDidPartiallyAcceptCompletionItem(completionItem, acceptedCharacters);
1530
this._provider.handleDidPartiallyAcceptCompletionItem(completionItem, typeConvert.PartialAcceptInfo.to(info));
1531
}
1532
}
1533
}
1534
1535
handleEndOfLifetime(pid: number, idx: number, reason: languages.InlineCompletionEndOfLifeReason<{ pid: number; idx: number }>): void {
1536
const completionItem = this._references.get(pid)?.items[idx];
1537
if (completionItem) {
1538
if (this._provider.handleEndOfLifetime && this._isAdditionsProposedApiEnabled) {
1539
const r = typeConvert.InlineCompletionEndOfLifeReason.to(reason, ref => this._references.get(ref.pid)?.items[ref.idx]);
1540
this._provider.handleEndOfLifetime(completionItem, r);
1541
}
1542
}
1543
}
1544
1545
handleRejection(pid: number, idx: number): void {
1546
const completionItem = this._references.get(pid)?.items[idx];
1547
if (completionItem) {
1548
if (this._provider.handleDidRejectCompletionItem && this._isAdditionsProposedApiEnabled) {
1549
this._provider.handleDidRejectCompletionItem(completionItem);
1550
}
1551
}
1552
}
1553
}
1554
1555
class ReferenceMap<T> {
1556
private readonly _references = new Map<number, T>();
1557
private _idPool = 1;
1558
1559
createReferenceId(value: T): number {
1560
const id = this._idPool++;
1561
this._references.set(id, value);
1562
return id;
1563
}
1564
1565
disposeReferenceId(referenceId: number): T | undefined {
1566
const value = this._references.get(referenceId);
1567
this._references.delete(referenceId);
1568
return value;
1569
}
1570
1571
get(referenceId: number): T | undefined {
1572
return this._references.get(referenceId);
1573
}
1574
}
1575
1576
class SignatureHelpAdapter {
1577
1578
private readonly _cache = new Cache<vscode.SignatureHelp>('SignatureHelp');
1579
1580
constructor(
1581
private readonly _documents: ExtHostDocuments,
1582
private readonly _provider: vscode.SignatureHelpProvider,
1583
) { }
1584
1585
async provideSignatureHelp(resource: URI, position: IPosition, context: extHostProtocol.ISignatureHelpContextDto, token: CancellationToken): Promise<extHostProtocol.ISignatureHelpDto | undefined> {
1586
const doc = this._documents.getDocument(resource);
1587
const pos = typeConvert.Position.to(position);
1588
const vscodeContext = this.reviveContext(context);
1589
1590
const value = await this._provider.provideSignatureHelp(doc, pos, token, vscodeContext);
1591
if (value) {
1592
const id = this._cache.add([value]);
1593
return { ...typeConvert.SignatureHelp.from(value), id };
1594
}
1595
return undefined;
1596
}
1597
1598
private reviveContext(context: extHostProtocol.ISignatureHelpContextDto): vscode.SignatureHelpContext {
1599
let activeSignatureHelp: vscode.SignatureHelp | undefined = undefined;
1600
if (context.activeSignatureHelp) {
1601
const revivedSignatureHelp = typeConvert.SignatureHelp.to(context.activeSignatureHelp);
1602
const saved = this._cache.get(context.activeSignatureHelp.id, 0);
1603
if (saved) {
1604
activeSignatureHelp = saved;
1605
activeSignatureHelp.activeSignature = revivedSignatureHelp.activeSignature;
1606
activeSignatureHelp.activeParameter = revivedSignatureHelp.activeParameter;
1607
} else {
1608
activeSignatureHelp = revivedSignatureHelp;
1609
}
1610
}
1611
return { ...context, activeSignatureHelp };
1612
}
1613
1614
releaseSignatureHelp(id: number): any {
1615
this._cache.delete(id);
1616
}
1617
}
1618
1619
class InlayHintsAdapter {
1620
1621
private _cache = new Cache<vscode.InlayHint>('InlayHints');
1622
private readonly _disposables = new Map<number, DisposableStore>();
1623
1624
constructor(
1625
private readonly _documents: ExtHostDocuments,
1626
private readonly _commands: CommandsConverter,
1627
private readonly _provider: vscode.InlayHintsProvider,
1628
private readonly _logService: ILogService,
1629
private readonly _extension: IExtensionDescription
1630
) { }
1631
1632
async provideInlayHints(resource: URI, ran: IRange, token: CancellationToken): Promise<extHostProtocol.IInlayHintsDto | undefined> {
1633
const doc = this._documents.getDocument(resource);
1634
const range = typeConvert.Range.to(ran);
1635
1636
const hints = await this._provider.provideInlayHints(doc, range, token);
1637
if (!Array.isArray(hints) || hints.length === 0) {
1638
// bad result
1639
this._logService.trace(`[InlayHints] NO inlay hints from '${this._extension.identifier.value}' for range ${JSON.stringify(ran)}`);
1640
return undefined;
1641
}
1642
if (token.isCancellationRequested) {
1643
// cancelled -> return without further ado, esp no caching
1644
// of results as they will leak
1645
return undefined;
1646
}
1647
const pid = this._cache.add(hints);
1648
this._disposables.set(pid, new DisposableStore());
1649
const result: extHostProtocol.IInlayHintsDto = { hints: [], cacheId: pid };
1650
for (let i = 0; i < hints.length; i++) {
1651
if (this._isValidInlayHint(hints[i], range)) {
1652
result.hints.push(this._convertInlayHint(hints[i], [pid, i]));
1653
}
1654
}
1655
this._logService.trace(`[InlayHints] ${result.hints.length} inlay hints from '${this._extension.identifier.value}' for range ${JSON.stringify(ran)}`);
1656
return result;
1657
}
1658
1659
async resolveInlayHint(id: extHostProtocol.ChainedCacheId, token: CancellationToken) {
1660
if (typeof this._provider.resolveInlayHint !== 'function') {
1661
return undefined;
1662
}
1663
const item = this._cache.get(...id);
1664
if (!item) {
1665
return undefined;
1666
}
1667
const hint = await this._provider.resolveInlayHint(item, token);
1668
if (!hint) {
1669
return undefined;
1670
}
1671
if (!this._isValidInlayHint(hint)) {
1672
return undefined;
1673
}
1674
return this._convertInlayHint(hint, id);
1675
}
1676
1677
releaseHints(id: number): any {
1678
this._disposables.get(id)?.dispose();
1679
this._disposables.delete(id);
1680
this._cache.delete(id);
1681
}
1682
1683
private _isValidInlayHint(hint: vscode.InlayHint, range?: vscode.Range): boolean {
1684
if (hint.label.length === 0 || Array.isArray(hint.label) && hint.label.every(part => part.value.length === 0)) {
1685
console.log('INVALID inlay hint, empty label', hint);
1686
return false;
1687
}
1688
if (range && !range.contains(hint.position)) {
1689
// console.log('INVALID inlay hint, position outside range', range, hint);
1690
return false;
1691
}
1692
return true;
1693
}
1694
1695
private _convertInlayHint(hint: vscode.InlayHint, id: extHostProtocol.ChainedCacheId): extHostProtocol.IInlayHintDto {
1696
1697
const disposables = this._disposables.get(id[0]);
1698
if (!disposables) {
1699
throw Error('DisposableStore is missing...');
1700
}
1701
1702
const result: extHostProtocol.IInlayHintDto = {
1703
label: '', // fill-in below
1704
cacheId: id,
1705
tooltip: typeConvert.MarkdownString.fromStrict(hint.tooltip),
1706
position: typeConvert.Position.from(hint.position),
1707
textEdits: hint.textEdits && hint.textEdits.map(typeConvert.TextEdit.from),
1708
kind: hint.kind && typeConvert.InlayHintKind.from(hint.kind),
1709
paddingLeft: hint.paddingLeft,
1710
paddingRight: hint.paddingRight,
1711
};
1712
1713
if (typeof hint.label === 'string') {
1714
result.label = hint.label;
1715
} else {
1716
const parts: languages.InlayHintLabelPart[] = [];
1717
result.label = parts;
1718
1719
for (const part of hint.label) {
1720
if (!part.value) {
1721
console.warn('INVALID inlay hint, empty label part', this._extension.identifier.value);
1722
continue;
1723
}
1724
const part2: languages.InlayHintLabelPart = {
1725
label: part.value,
1726
tooltip: typeConvert.MarkdownString.fromStrict(part.tooltip)
1727
};
1728
if (Location.isLocation(part.location)) {
1729
part2.location = typeConvert.location.from(part.location);
1730
}
1731
if (part.command) {
1732
part2.command = this._commands.toInternal(part.command, disposables);
1733
}
1734
parts.push(part2);
1735
}
1736
}
1737
return result;
1738
}
1739
}
1740
1741
class LinkProviderAdapter {
1742
1743
private _cache = new Cache<vscode.DocumentLink>('DocumentLink');
1744
1745
constructor(
1746
private readonly _documents: ExtHostDocuments,
1747
private readonly _provider: vscode.DocumentLinkProvider
1748
) { }
1749
1750
async provideLinks(resource: URI, token: CancellationToken): Promise<extHostProtocol.ILinksListDto | undefined> {
1751
const doc = this._documents.getDocument(resource);
1752
1753
const links = await this._provider.provideDocumentLinks(doc, token);
1754
if (!Array.isArray(links) || links.length === 0) {
1755
// bad result
1756
return undefined;
1757
}
1758
if (token.isCancellationRequested) {
1759
// cancelled -> return without further ado, esp no caching
1760
// of results as they will leak
1761
return undefined;
1762
}
1763
if (typeof this._provider.resolveDocumentLink !== 'function') {
1764
// no resolve -> no caching
1765
return { links: links.filter(LinkProviderAdapter._validateLink).map(typeConvert.DocumentLink.from) };
1766
1767
} else {
1768
// cache links for future resolving
1769
const pid = this._cache.add(links);
1770
const result: extHostProtocol.ILinksListDto = { links: [], cacheId: pid };
1771
for (let i = 0; i < links.length; i++) {
1772
1773
if (!LinkProviderAdapter._validateLink(links[i])) {
1774
continue;
1775
}
1776
1777
const dto: extHostProtocol.ILinkDto = typeConvert.DocumentLink.from(links[i]);
1778
dto.cacheId = [pid, i];
1779
result.links.push(dto);
1780
}
1781
return result;
1782
}
1783
}
1784
1785
private static _validateLink(link: vscode.DocumentLink): boolean {
1786
if (link.target && link.target.path.length > 50_000) {
1787
console.warn('DROPPING link because it is too long');
1788
return false;
1789
}
1790
return true;
1791
}
1792
1793
async resolveLink(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ILinkDto | undefined> {
1794
if (typeof this._provider.resolveDocumentLink !== 'function') {
1795
return undefined;
1796
}
1797
const item = this._cache.get(...id);
1798
if (!item) {
1799
return undefined;
1800
}
1801
const link = await this._provider.resolveDocumentLink(item, token);
1802
if (!link || !LinkProviderAdapter._validateLink(link)) {
1803
return undefined;
1804
}
1805
return typeConvert.DocumentLink.from(link);
1806
}
1807
1808
releaseLinks(id: number): any {
1809
this._cache.delete(id);
1810
}
1811
}
1812
1813
class ColorProviderAdapter {
1814
1815
constructor(
1816
private _documents: ExtHostDocuments,
1817
private _provider: vscode.DocumentColorProvider
1818
) { }
1819
1820
async provideColors(resource: URI, token: CancellationToken): Promise<extHostProtocol.IRawColorInfo[]> {
1821
const doc = this._documents.getDocument(resource);
1822
const colors = await this._provider.provideDocumentColors(doc, token);
1823
if (!Array.isArray(colors)) {
1824
return [];
1825
}
1826
const colorInfos: extHostProtocol.IRawColorInfo[] = colors.map(ci => {
1827
return {
1828
color: typeConvert.Color.from(ci.color),
1829
range: typeConvert.Range.from(ci.range)
1830
};
1831
});
1832
return colorInfos;
1833
}
1834
1835
async provideColorPresentations(resource: URI, raw: extHostProtocol.IRawColorInfo, token: CancellationToken): Promise<languages.IColorPresentation[] | undefined> {
1836
const document = this._documents.getDocument(resource);
1837
const range = typeConvert.Range.to(raw.range);
1838
const color = typeConvert.Color.to(raw.color);
1839
const value = await this._provider.provideColorPresentations(color, { document, range }, token);
1840
if (!Array.isArray(value)) {
1841
return undefined;
1842
}
1843
return value.map(typeConvert.ColorPresentation.from);
1844
}
1845
}
1846
1847
class FoldingProviderAdapter {
1848
1849
constructor(
1850
private _documents: ExtHostDocuments,
1851
private _provider: vscode.FoldingRangeProvider
1852
) { }
1853
1854
async provideFoldingRanges(resource: URI, context: languages.FoldingContext, token: CancellationToken): Promise<languages.FoldingRange[] | undefined> {
1855
const doc = this._documents.getDocument(resource);
1856
const ranges = await this._provider.provideFoldingRanges(doc, context, token);
1857
if (!Array.isArray(ranges)) {
1858
return undefined;
1859
}
1860
return ranges.map(typeConvert.FoldingRange.from);
1861
}
1862
}
1863
1864
class SelectionRangeAdapter {
1865
1866
constructor(
1867
private readonly _documents: ExtHostDocuments,
1868
private readonly _provider: vscode.SelectionRangeProvider,
1869
private readonly _logService: ILogService
1870
) { }
1871
1872
async provideSelectionRanges(resource: URI, pos: IPosition[], token: CancellationToken): Promise<languages.SelectionRange[][]> {
1873
const document = this._documents.getDocument(resource);
1874
const positions = pos.map(typeConvert.Position.to);
1875
1876
const allProviderRanges = await this._provider.provideSelectionRanges(document, positions, token);
1877
if (!isNonEmptyArray(allProviderRanges)) {
1878
return [];
1879
}
1880
if (allProviderRanges.length !== positions.length) {
1881
this._logService.warn('BAD selection ranges, provider must return ranges for each position');
1882
return [];
1883
}
1884
const allResults: languages.SelectionRange[][] = [];
1885
for (let i = 0; i < positions.length; i++) {
1886
const oneResult: languages.SelectionRange[] = [];
1887
allResults.push(oneResult);
1888
1889
let last: vscode.Position | vscode.Range = positions[i];
1890
let selectionRange = allProviderRanges[i];
1891
1892
while (true) {
1893
if (!selectionRange.range.contains(last)) {
1894
throw new Error('INVALID selection range, must contain the previous range');
1895
}
1896
oneResult.push(typeConvert.SelectionRange.from(selectionRange));
1897
if (!selectionRange.parent) {
1898
break;
1899
}
1900
last = selectionRange.range;
1901
selectionRange = selectionRange.parent;
1902
}
1903
}
1904
return allResults;
1905
}
1906
}
1907
1908
class CallHierarchyAdapter {
1909
1910
private readonly _idPool = new IdGenerator('');
1911
private readonly _cache = new Map<string, Map<string, vscode.CallHierarchyItem>>();
1912
1913
constructor(
1914
private readonly _documents: ExtHostDocuments,
1915
private readonly _provider: vscode.CallHierarchyProvider
1916
) { }
1917
1918
async prepareSession(uri: URI, position: IPosition, token: CancellationToken): Promise<extHostProtocol.ICallHierarchyItemDto[] | undefined> {
1919
const doc = this._documents.getDocument(uri);
1920
const pos = typeConvert.Position.to(position);
1921
1922
const items = await this._provider.prepareCallHierarchy(doc, pos, token);
1923
if (!items) {
1924
return undefined;
1925
}
1926
1927
const sessionId = this._idPool.nextId();
1928
this._cache.set(sessionId, new Map());
1929
1930
if (Array.isArray(items)) {
1931
return items.map(item => this._cacheAndConvertItem(sessionId, item));
1932
} else {
1933
return [this._cacheAndConvertItem(sessionId, items)];
1934
}
1935
}
1936
1937
async provideCallsTo(sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.IIncomingCallDto[] | undefined> {
1938
const item = this._itemFromCache(sessionId, itemId);
1939
if (!item) {
1940
throw new Error('missing call hierarchy item');
1941
}
1942
const calls = await this._provider.provideCallHierarchyIncomingCalls(item, token);
1943
if (!calls) {
1944
return undefined;
1945
}
1946
return calls.map(call => {
1947
return {
1948
from: this._cacheAndConvertItem(sessionId, call.from),
1949
fromRanges: call.fromRanges.map(r => typeConvert.Range.from(r))
1950
};
1951
});
1952
}
1953
1954
async provideCallsFrom(sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.IOutgoingCallDto[] | undefined> {
1955
const item = this._itemFromCache(sessionId, itemId);
1956
if (!item) {
1957
throw new Error('missing call hierarchy item');
1958
}
1959
const calls = await this._provider.provideCallHierarchyOutgoingCalls(item, token);
1960
if (!calls) {
1961
return undefined;
1962
}
1963
return calls.map(call => {
1964
return {
1965
to: this._cacheAndConvertItem(sessionId, call.to),
1966
fromRanges: call.fromRanges.map(r => typeConvert.Range.from(r))
1967
};
1968
});
1969
}
1970
1971
releaseSession(sessionId: string): void {
1972
this._cache.delete(sessionId);
1973
}
1974
1975
private _cacheAndConvertItem(sessionId: string, item: vscode.CallHierarchyItem): extHostProtocol.ICallHierarchyItemDto {
1976
const map = this._cache.get(sessionId)!;
1977
const dto = typeConvert.CallHierarchyItem.from(item, sessionId, map.size.toString(36));
1978
map.set(dto._itemId, item);
1979
return dto;
1980
}
1981
1982
private _itemFromCache(sessionId: string, itemId: string): vscode.CallHierarchyItem | undefined {
1983
const map = this._cache.get(sessionId);
1984
return map?.get(itemId);
1985
}
1986
}
1987
1988
class TypeHierarchyAdapter {
1989
1990
private readonly _idPool = new IdGenerator('');
1991
private readonly _cache = new Map<string, Map<string, vscode.TypeHierarchyItem>>();
1992
1993
constructor(
1994
private readonly _documents: ExtHostDocuments,
1995
private readonly _provider: vscode.TypeHierarchyProvider
1996
) { }
1997
1998
async prepareSession(uri: URI, position: IPosition, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
1999
const doc = this._documents.getDocument(uri);
2000
const pos = typeConvert.Position.to(position);
2001
2002
const items = await this._provider.prepareTypeHierarchy(doc, pos, token);
2003
if (!items) {
2004
return undefined;
2005
}
2006
2007
const sessionId = this._idPool.nextId();
2008
this._cache.set(sessionId, new Map());
2009
2010
if (Array.isArray(items)) {
2011
return items.map(item => this._cacheAndConvertItem(sessionId, item));
2012
} else {
2013
return [this._cacheAndConvertItem(sessionId, items)];
2014
}
2015
}
2016
2017
async provideSupertypes(sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
2018
const item = this._itemFromCache(sessionId, itemId);
2019
if (!item) {
2020
throw new Error('missing type hierarchy item');
2021
}
2022
const supertypes = await this._provider.provideTypeHierarchySupertypes(item, token);
2023
if (!supertypes) {
2024
return undefined;
2025
}
2026
return supertypes.map(supertype => {
2027
return this._cacheAndConvertItem(sessionId, supertype);
2028
});
2029
}
2030
2031
async provideSubtypes(sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
2032
const item = this._itemFromCache(sessionId, itemId);
2033
if (!item) {
2034
throw new Error('missing type hierarchy item');
2035
}
2036
const subtypes = await this._provider.provideTypeHierarchySubtypes(item, token);
2037
if (!subtypes) {
2038
return undefined;
2039
}
2040
return subtypes.map(subtype => {
2041
return this._cacheAndConvertItem(sessionId, subtype);
2042
});
2043
}
2044
2045
releaseSession(sessionId: string): void {
2046
this._cache.delete(sessionId);
2047
}
2048
2049
private _cacheAndConvertItem(sessionId: string, item: vscode.TypeHierarchyItem): extHostProtocol.ITypeHierarchyItemDto {
2050
const map = this._cache.get(sessionId)!;
2051
const dto = typeConvert.TypeHierarchyItem.from(item, sessionId, map.size.toString(36));
2052
map.set(dto._itemId, item);
2053
return dto;
2054
}
2055
2056
private _itemFromCache(sessionId: string, itemId: string): vscode.TypeHierarchyItem | undefined {
2057
const map = this._cache.get(sessionId);
2058
return map?.get(itemId);
2059
}
2060
}
2061
2062
class DocumentDropEditAdapter {
2063
2064
private readonly _cache = new Cache<vscode.DocumentDropEdit>('DocumentDropEdit');
2065
2066
constructor(
2067
private readonly _proxy: extHostProtocol.MainThreadLanguageFeaturesShape,
2068
private readonly _documents: ExtHostDocuments,
2069
private readonly _provider: vscode.DocumentDropEditProvider,
2070
private readonly _handle: number,
2071
private readonly _extension: IExtensionDescription,
2072
) { }
2073
2074
async provideDocumentOnDropEdits(requestId: number, uri: URI, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IDocumentDropEditDto[] | undefined> {
2075
const doc = this._documents.getDocument(uri);
2076
const pos = typeConvert.Position.to(position);
2077
const dataTransfer = typeConvert.DataTransfer.toDataTransfer(dataTransferDto, async (id) => {
2078
return (await this._proxy.$resolveDocumentOnDropFileData(this._handle, requestId, id)).buffer;
2079
});
2080
2081
const edits = await this._provider.provideDocumentDropEdits(doc, pos, dataTransfer, token);
2082
if (!edits) {
2083
return undefined;
2084
}
2085
2086
const editsArray = asArray(edits);
2087
const cacheId = this._cache.add(editsArray);
2088
2089
return editsArray.map((edit, i): extHostProtocol.IDocumentDropEditDto => ({
2090
_cacheId: [cacheId, i],
2091
title: edit.title ?? localize('defaultDropLabel', "Drop using '{0}' extension", this._extension.displayName || this._extension.name),
2092
kind: edit.kind?.value,
2093
yieldTo: edit.yieldTo?.map(x => x.value),
2094
insertText: typeof edit.insertText === 'string' ? edit.insertText : { snippet: edit.insertText.value },
2095
additionalEdit: edit.additionalEdit ? typeConvert.WorkspaceEdit.from(edit.additionalEdit, undefined) : undefined,
2096
}));
2097
}
2098
2099
async resolveDropEdit(id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<{ additionalEdit?: extHostProtocol.IWorkspaceEditDto }> {
2100
const [sessionId, itemId] = id;
2101
const item = this._cache.get(sessionId, itemId);
2102
if (!item || !this._provider.resolveDocumentDropEdit) {
2103
return {}; // this should not happen...
2104
}
2105
2106
const resolvedItem = (await this._provider.resolveDocumentDropEdit(item, token)) ?? item;
2107
const additionalEdit = resolvedItem.additionalEdit ? typeConvert.WorkspaceEdit.from(resolvedItem.additionalEdit, undefined) : undefined;
2108
return { additionalEdit };
2109
}
2110
2111
releaseDropEdits(id: number): any {
2112
this._cache.delete(id);
2113
}
2114
}
2115
2116
type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | HoverAdapter
2117
| DocumentHighlightAdapter | MultiDocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter
2118
| DocumentPasteEditProvider | DocumentFormattingAdapter | RangeFormattingAdapter
2119
| OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
2120
| CompletionsAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
2121
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
2122
| SelectionRangeAdapter | CallHierarchyAdapter | TypeHierarchyAdapter
2123
| DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter
2124
| EvaluatableExpressionAdapter | InlineValuesAdapter
2125
| LinkedEditingRangeAdapter | InlayHintsAdapter | InlineCompletionAdapter
2126
| DocumentDropEditAdapter | NewSymbolNamesAdapter;
2127
2128
class AdapterData {
2129
constructor(
2130
readonly adapter: Adapter,
2131
readonly extension: IExtensionDescription
2132
) { }
2133
}
2134
2135
export class ExtHostLanguageFeatures extends CoreDisposable implements extHostProtocol.ExtHostLanguageFeaturesShape {
2136
2137
private static _handlePool: number = 0;
2138
2139
private readonly _proxy: extHostProtocol.MainThreadLanguageFeaturesShape;
2140
private readonly _adapter = new Map<number, AdapterData>();
2141
2142
private _inlineCompletionsUnificationState: vscode.InlineCompletionsUnificationState;
2143
public get inlineCompletionsUnificationState(): vscode.InlineCompletionsUnificationState {
2144
return this._inlineCompletionsUnificationState;
2145
}
2146
2147
private readonly _onDidChangeInlineCompletionsUnificationState = this._register(new Emitter<void>());
2148
readonly onDidChangeInlineCompletionsUnificationState = this._onDidChangeInlineCompletionsUnificationState.event;
2149
2150
constructor(
2151
mainContext: extHostProtocol.IMainContext,
2152
private readonly _uriTransformer: IURITransformer,
2153
private readonly _documents: ExtHostDocuments,
2154
private readonly _commands: ExtHostCommands,
2155
private readonly _diagnostics: ExtHostDiagnostics,
2156
private readonly _logService: ILogService,
2157
private readonly _apiDeprecation: IExtHostApiDeprecationService,
2158
private readonly _extensionTelemetry: IExtHostTelemetry
2159
) {
2160
super();
2161
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadLanguageFeatures);
2162
this._inlineCompletionsUnificationState = {
2163
codeUnification: false,
2164
modelUnification: false,
2165
extensionUnification: false,
2166
expAssignments: []
2167
};
2168
}
2169
2170
private _transformDocumentSelector(selector: vscode.DocumentSelector, extension: IExtensionDescription): Array<extHostProtocol.IDocumentFilterDto> {
2171
return typeConvert.DocumentSelector.from(selector, this._uriTransformer, extension);
2172
}
2173
2174
private _createDisposable(handle: number): Disposable {
2175
return new Disposable(() => {
2176
this._adapter.delete(handle);
2177
this._proxy.$unregister(handle);
2178
});
2179
}
2180
2181
private _nextHandle(): number {
2182
return ExtHostLanguageFeatures._handlePool++;
2183
}
2184
2185
private async _withAdapter<A, R>(
2186
handle: number,
2187
ctor: { new(...args: any[]): A },
2188
callback: (adapter: A, extension: IExtensionDescription) => Promise<R>,
2189
fallbackValue: R,
2190
tokenToRaceAgainst: CancellationToken | undefined,
2191
doNotLog: boolean = false
2192
): Promise<R> {
2193
const data = this._adapter.get(handle);
2194
if (!data || !(data.adapter instanceof ctor)) {
2195
return fallbackValue;
2196
}
2197
2198
const t1: number = Date.now();
2199
if (!doNotLog) {
2200
this._logService.trace(`[${data.extension.identifier.value}] INVOKE provider '${callback.toString().replace(/[\r\n]/g, '')}'`);
2201
}
2202
2203
const result = callback(data.adapter, data.extension);
2204
2205
// logging,tracing
2206
Promise.resolve(result).catch(err => {
2207
if (!isCancellationError(err)) {
2208
this._logService.error(`[${data.extension.identifier.value}] provider FAILED`);
2209
this._logService.error(err);
2210
2211
this._extensionTelemetry.onExtensionError(data.extension.identifier, err);
2212
}
2213
}).finally(() => {
2214
if (!doNotLog) {
2215
this._logService.trace(`[${data.extension.identifier.value}] provider DONE after ${Date.now() - t1}ms`);
2216
}
2217
});
2218
2219
if (CancellationToken.isCancellationToken(tokenToRaceAgainst)) {
2220
return raceCancellationError(result, tokenToRaceAgainst);
2221
}
2222
return result;
2223
}
2224
2225
private _addNewAdapter(adapter: Adapter, extension: IExtensionDescription): number {
2226
const handle = this._nextHandle();
2227
this._adapter.set(handle, new AdapterData(adapter, extension));
2228
return handle;
2229
}
2230
2231
private static _extLabel(ext: IExtensionDescription): string {
2232
return ext.displayName || ext.name;
2233
}
2234
2235
private static _extId(ext: IExtensionDescription): string {
2236
return ext.identifier.value;
2237
}
2238
2239
// --- outline
2240
2241
registerDocumentSymbolProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentSymbolProvider, metadata?: vscode.DocumentSymbolProviderMetadata): vscode.Disposable {
2242
const handle = this._addNewAdapter(new DocumentSymbolAdapter(this._documents, provider), extension);
2243
const displayName = (metadata && metadata.label) || ExtHostLanguageFeatures._extLabel(extension);
2244
this._proxy.$registerDocumentSymbolProvider(handle, this._transformDocumentSelector(selector, extension), displayName);
2245
return this._createDisposable(handle);
2246
}
2247
2248
$provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise<languages.DocumentSymbol[] | undefined> {
2249
return this._withAdapter(handle, DocumentSymbolAdapter, adapter => adapter.provideDocumentSymbols(URI.revive(resource), token), undefined, token);
2250
}
2251
2252
// --- code lens
2253
2254
registerCodeLensProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable {
2255
const handle = this._nextHandle();
2256
const eventHandle = typeof provider.onDidChangeCodeLenses === 'function' ? this._nextHandle() : undefined;
2257
2258
this._adapter.set(handle, new AdapterData(new CodeLensAdapter(this._documents, this._commands.converter, provider, extension, this._extensionTelemetry, this._logService), extension));
2259
this._proxy.$registerCodeLensSupport(handle, this._transformDocumentSelector(selector, extension), eventHandle);
2260
let result = this._createDisposable(handle);
2261
2262
if (eventHandle !== undefined) {
2263
const subscription = provider.onDidChangeCodeLenses!(_ => this._proxy.$emitCodeLensEvent(eventHandle));
2264
result = Disposable.from(result, subscription);
2265
}
2266
2267
return result;
2268
}
2269
2270
$provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.ICodeLensListDto | undefined> {
2271
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), undefined, token, resource.scheme === 'output');
2272
}
2273
2274
$resolveCodeLens(handle: number, symbol: extHostProtocol.ICodeLensDto, token: CancellationToken): Promise<extHostProtocol.ICodeLensDto | undefined> {
2275
return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(symbol, token), undefined, undefined, true);
2276
}
2277
2278
$releaseCodeLenses(handle: number, cacheId: number): void {
2279
this._withAdapter(handle, CodeLensAdapter, adapter => Promise.resolve(adapter.releaseCodeLenses(cacheId)), undefined, undefined, true);
2280
}
2281
2282
// --- declaration
2283
2284
registerDefinitionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable {
2285
const handle = this._addNewAdapter(new DefinitionAdapter(this._documents, provider), extension);
2286
this._proxy.$registerDefinitionSupport(handle, this._transformDocumentSelector(selector, extension));
2287
return this._createDisposable(handle);
2288
}
2289
2290
$provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.LocationLink[]> {
2291
return this._withAdapter(handle, DefinitionAdapter, adapter => adapter.provideDefinition(URI.revive(resource), position, token), [], token);
2292
}
2293
2294
registerDeclarationProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DeclarationProvider): vscode.Disposable {
2295
const handle = this._addNewAdapter(new DeclarationAdapter(this._documents, provider), extension);
2296
this._proxy.$registerDeclarationSupport(handle, this._transformDocumentSelector(selector, extension));
2297
return this._createDisposable(handle);
2298
}
2299
2300
$provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.LocationLink[]> {
2301
return this._withAdapter(handle, DeclarationAdapter, adapter => adapter.provideDeclaration(URI.revive(resource), position, token), [], token);
2302
}
2303
2304
registerImplementationProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.ImplementationProvider): vscode.Disposable {
2305
const handle = this._addNewAdapter(new ImplementationAdapter(this._documents, provider), extension);
2306
this._proxy.$registerImplementationSupport(handle, this._transformDocumentSelector(selector, extension));
2307
return this._createDisposable(handle);
2308
}
2309
2310
$provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.LocationLink[]> {
2311
return this._withAdapter(handle, ImplementationAdapter, adapter => adapter.provideImplementation(URI.revive(resource), position, token), [], token);
2312
}
2313
2314
registerTypeDefinitionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.TypeDefinitionProvider): vscode.Disposable {
2315
const handle = this._addNewAdapter(new TypeDefinitionAdapter(this._documents, provider), extension);
2316
this._proxy.$registerTypeDefinitionSupport(handle, this._transformDocumentSelector(selector, extension));
2317
return this._createDisposable(handle);
2318
}
2319
2320
$provideTypeDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.LocationLink[]> {
2321
return this._withAdapter(handle, TypeDefinitionAdapter, adapter => adapter.provideTypeDefinition(URI.revive(resource), position, token), [], token);
2322
}
2323
2324
// --- extra info
2325
2326
registerHoverProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.HoverProvider, extensionId?: ExtensionIdentifier): vscode.Disposable {
2327
const handle = this._addNewAdapter(new HoverAdapter(this._documents, provider), extension);
2328
this._proxy.$registerHoverProvider(handle, this._transformDocumentSelector(selector, extension));
2329
return this._createDisposable(handle);
2330
}
2331
2332
$provideHover(handle: number, resource: UriComponents, position: IPosition, context: languages.HoverContext<{ id: number }> | undefined, token: CancellationToken,): Promise<extHostProtocol.HoverWithId | undefined> {
2333
return this._withAdapter(handle, HoverAdapter, adapter => adapter.provideHover(URI.revive(resource), position, context, token), undefined, token);
2334
}
2335
2336
$releaseHover(handle: number, id: number): void {
2337
this._withAdapter(handle, HoverAdapter, adapter => Promise.resolve(adapter.releaseHover(id)), undefined, undefined);
2338
}
2339
2340
// --- debug hover
2341
2342
registerEvaluatableExpressionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.EvaluatableExpressionProvider, extensionId?: ExtensionIdentifier): vscode.Disposable {
2343
const handle = this._addNewAdapter(new EvaluatableExpressionAdapter(this._documents, provider), extension);
2344
this._proxy.$registerEvaluatableExpressionProvider(handle, this._transformDocumentSelector(selector, extension));
2345
return this._createDisposable(handle);
2346
}
2347
2348
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.EvaluatableExpression | undefined> {
2349
return this._withAdapter(handle, EvaluatableExpressionAdapter, adapter => adapter.provideEvaluatableExpression(URI.revive(resource), position, token), undefined, token);
2350
}
2351
2352
// --- debug inline values
2353
2354
registerInlineValuesProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineValuesProvider, extensionId?: ExtensionIdentifier): vscode.Disposable {
2355
2356
const eventHandle = typeof provider.onDidChangeInlineValues === 'function' ? this._nextHandle() : undefined;
2357
const handle = this._addNewAdapter(new InlineValuesAdapter(this._documents, provider), extension);
2358
2359
this._proxy.$registerInlineValuesProvider(handle, this._transformDocumentSelector(selector, extension), eventHandle);
2360
let result = this._createDisposable(handle);
2361
2362
if (eventHandle !== undefined) {
2363
const subscription = provider.onDidChangeInlineValues!(_ => this._proxy.$emitInlineValuesEvent(eventHandle));
2364
result = Disposable.from(result, subscription);
2365
}
2366
return result;
2367
}
2368
2369
$provideInlineValues(handle: number, resource: UriComponents, range: IRange, context: extHostProtocol.IInlineValueContextDto, token: CancellationToken): Promise<languages.InlineValue[] | undefined> {
2370
return this._withAdapter(handle, InlineValuesAdapter, adapter => adapter.provideInlineValues(URI.revive(resource), range, context, token), undefined, token);
2371
}
2372
2373
// --- occurrences
2374
2375
registerDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
2376
const handle = this._addNewAdapter(new DocumentHighlightAdapter(this._documents, provider), extension);
2377
this._proxy.$registerDocumentHighlightProvider(handle, this._transformDocumentSelector(selector, extension));
2378
return this._createDisposable(handle);
2379
}
2380
2381
registerMultiDocumentHighlightProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.MultiDocumentHighlightProvider): vscode.Disposable {
2382
const handle = this._addNewAdapter(new MultiDocumentHighlightAdapter(this._documents, provider, this._logService), extension);
2383
this._proxy.$registerMultiDocumentHighlightProvider(handle, this._transformDocumentSelector(selector, extension));
2384
return this._createDisposable(handle);
2385
}
2386
2387
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<languages.DocumentHighlight[] | undefined> {
2388
return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(URI.revive(resource), position, token), undefined, token);
2389
}
2390
2391
$provideMultiDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, otherModels: UriComponents[], token: CancellationToken): Promise<languages.MultiDocumentHighlight[] | undefined> {
2392
return this._withAdapter(handle, MultiDocumentHighlightAdapter, adapter => adapter.provideMultiDocumentHighlights(URI.revive(resource), position, otherModels.map(model => URI.revive(model)), token), undefined, token);
2393
}
2394
2395
// --- linked editing
2396
2397
registerLinkedEditingRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.LinkedEditingRangeProvider): vscode.Disposable {
2398
const handle = this._addNewAdapter(new LinkedEditingRangeAdapter(this._documents, provider), extension);
2399
this._proxy.$registerLinkedEditingRangeProvider(handle, this._transformDocumentSelector(selector, extension));
2400
return this._createDisposable(handle);
2401
}
2402
2403
$provideLinkedEditingRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<extHostProtocol.ILinkedEditingRangesDto | undefined> {
2404
return this._withAdapter(handle, LinkedEditingRangeAdapter, async adapter => {
2405
const res = await adapter.provideLinkedEditingRanges(URI.revive(resource), position, token);
2406
if (res) {
2407
return {
2408
ranges: res.ranges,
2409
wordPattern: res.wordPattern ? ExtHostLanguageFeatures._serializeRegExp(res.wordPattern) : undefined
2410
};
2411
}
2412
return undefined;
2413
}, undefined, token);
2414
}
2415
2416
// --- references
2417
2418
registerReferenceProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
2419
const handle = this._addNewAdapter(new ReferenceAdapter(this._documents, provider), extension);
2420
this._proxy.$registerReferenceSupport(handle, this._transformDocumentSelector(selector, extension));
2421
return this._createDisposable(handle);
2422
}
2423
2424
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: languages.ReferenceContext, token: CancellationToken): Promise<languages.Location[] | undefined> {
2425
return this._withAdapter(handle, ReferenceAdapter, adapter => adapter.provideReferences(URI.revive(resource), position, context, token), undefined, token);
2426
}
2427
2428
// --- code actions
2429
2430
registerCodeActionProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CodeActionProvider, metadata?: vscode.CodeActionProviderMetadata): vscode.Disposable {
2431
const store = new DisposableStore();
2432
const handle = this._addNewAdapter(new CodeActionAdapter(this._documents, this._commands.converter, this._diagnostics, provider, this._logService, extension, this._apiDeprecation), extension);
2433
this._proxy.$registerCodeActionSupport(handle, this._transformDocumentSelector(selector, extension), {
2434
providedKinds: metadata?.providedCodeActionKinds?.map(kind => kind.value),
2435
documentation: metadata?.documentation?.map(x => ({
2436
kind: x.kind.value,
2437
command: this._commands.converter.toInternal(x.command, store),
2438
}))
2439
}, ExtHostLanguageFeatures._extLabel(extension), ExtHostLanguageFeatures._extId(extension), Boolean(provider.resolveCodeAction));
2440
store.add(this._createDisposable(handle));
2441
return store;
2442
}
2443
2444
2445
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: languages.CodeActionContext, token: CancellationToken): Promise<extHostProtocol.ICodeActionListDto | undefined> {
2446
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context, token), undefined, token);
2447
}
2448
2449
$resolveCodeAction(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<{ edit?: extHostProtocol.IWorkspaceEditDto; command?: extHostProtocol.ICommandDto }> {
2450
return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.resolveCodeAction(id, token), {}, undefined);
2451
}
2452
2453
$releaseCodeActions(handle: number, cacheId: number): void {
2454
this._withAdapter(handle, CodeActionAdapter, adapter => Promise.resolve(adapter.releaseCodeActions(cacheId)), undefined, undefined);
2455
}
2456
2457
// --- formatting
2458
2459
registerDocumentFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable {
2460
const handle = this._addNewAdapter(new DocumentFormattingAdapter(this._documents, provider), extension);
2461
this._proxy.$registerDocumentFormattingSupport(handle, this._transformDocumentSelector(selector, extension), extension.identifier, extension.displayName || extension.name);
2462
return this._createDisposable(handle);
2463
}
2464
2465
$provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> {
2466
return this._withAdapter(handle, DocumentFormattingAdapter, adapter => adapter.provideDocumentFormattingEdits(URI.revive(resource), options, token), undefined, token);
2467
}
2468
2469
registerDocumentRangeFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentRangeFormattingEditProvider): vscode.Disposable {
2470
const canFormatMultipleRanges = typeof provider.provideDocumentRangesFormattingEdits === 'function';
2471
const handle = this._addNewAdapter(new RangeFormattingAdapter(this._documents, provider), extension);
2472
this._proxy.$registerRangeFormattingSupport(handle, this._transformDocumentSelector(selector, extension), extension.identifier, extension.displayName || extension.name, canFormatMultipleRanges);
2473
return this._createDisposable(handle);
2474
}
2475
2476
$provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> {
2477
return this._withAdapter(handle, RangeFormattingAdapter, adapter => adapter.provideDocumentRangeFormattingEdits(URI.revive(resource), range, options, token), undefined, token);
2478
}
2479
2480
$provideDocumentRangesFormattingEdits(handle: number, resource: UriComponents, ranges: IRange[], options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> {
2481
return this._withAdapter(handle, RangeFormattingAdapter, adapter => adapter.provideDocumentRangesFormattingEdits(URI.revive(resource), ranges, options, token), undefined, token);
2482
}
2483
2484
registerOnTypeFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.OnTypeFormattingEditProvider, triggerCharacters: string[]): vscode.Disposable {
2485
const handle = this._addNewAdapter(new OnTypeFormattingAdapter(this._documents, provider), extension);
2486
this._proxy.$registerOnTypeFormattingSupport(handle, this._transformDocumentSelector(selector, extension), triggerCharacters, extension.identifier);
2487
return this._createDisposable(handle);
2488
}
2489
2490
$provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> {
2491
return this._withAdapter(handle, OnTypeFormattingAdapter, adapter => adapter.provideOnTypeFormattingEdits(URI.revive(resource), position, ch, options, token), undefined, token);
2492
}
2493
2494
// --- navigate types
2495
2496
registerWorkspaceSymbolProvider(extension: IExtensionDescription, provider: vscode.WorkspaceSymbolProvider): vscode.Disposable {
2497
const handle = this._addNewAdapter(new NavigateTypeAdapter(provider, this._logService), extension);
2498
this._proxy.$registerNavigateTypeSupport(handle, typeof provider.resolveWorkspaceSymbol === 'function');
2499
return this._createDisposable(handle);
2500
}
2501
2502
$provideWorkspaceSymbols(handle: number, search: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolsDto> {
2503
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.provideWorkspaceSymbols(search, token), { symbols: [] }, token);
2504
}
2505
2506
$resolveWorkspaceSymbol(handle: number, symbol: extHostProtocol.IWorkspaceSymbolDto, token: CancellationToken): Promise<extHostProtocol.IWorkspaceSymbolDto | undefined> {
2507
return this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.resolveWorkspaceSymbol(symbol, token), undefined, undefined);
2508
}
2509
2510
$releaseWorkspaceSymbols(handle: number, id: number): void {
2511
this._withAdapter(handle, NavigateTypeAdapter, adapter => adapter.releaseWorkspaceSymbols(id), undefined, undefined);
2512
}
2513
2514
// --- rename
2515
2516
registerRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.RenameProvider): vscode.Disposable {
2517
const handle = this._addNewAdapter(new RenameAdapter(this._documents, provider, this._logService), extension);
2518
this._proxy.$registerRenameSupport(handle, this._transformDocumentSelector(selector, extension), RenameAdapter.supportsResolving(provider));
2519
return this._createDisposable(handle);
2520
}
2521
2522
$provideRenameEdits(handle: number, resource: UriComponents, position: IPosition, newName: string, token: CancellationToken): Promise<extHostProtocol.IWorkspaceEditDto | undefined> {
2523
return this._withAdapter(handle, RenameAdapter, adapter => adapter.provideRenameEdits(URI.revive(resource), position, newName, token), undefined, token);
2524
}
2525
2526
$resolveRenameLocation(handle: number, resource: URI, position: IPosition, token: CancellationToken): Promise<languages.RenameLocation | undefined> {
2527
return this._withAdapter(handle, RenameAdapter, adapter => adapter.resolveRenameLocation(URI.revive(resource), position, token), undefined, token);
2528
}
2529
2530
registerNewSymbolNamesProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.NewSymbolNamesProvider): vscode.Disposable {
2531
const handle = this._addNewAdapter(new NewSymbolNamesAdapter(this._documents, provider, this._logService), extension);
2532
this._proxy.$registerNewSymbolNamesProvider(handle, this._transformDocumentSelector(selector, extension));
2533
return this._createDisposable(handle);
2534
}
2535
2536
$supportsAutomaticNewSymbolNamesTriggerKind(handle: number): Promise<boolean | undefined> {
2537
return this._withAdapter(
2538
handle,
2539
NewSymbolNamesAdapter,
2540
adapter => adapter.supportsAutomaticNewSymbolNamesTriggerKind(),
2541
false,
2542
undefined
2543
);
2544
}
2545
2546
$provideNewSymbolNames(handle: number, resource: UriComponents, range: IRange, triggerKind: languages.NewSymbolNameTriggerKind, token: CancellationToken): Promise<languages.NewSymbolName[] | undefined> {
2547
return this._withAdapter(handle, NewSymbolNamesAdapter, adapter => adapter.provideNewSymbolNames(URI.revive(resource), range, triggerKind, token), undefined, token);
2548
}
2549
2550
//#region semantic coloring
2551
2552
registerDocumentSemanticTokensProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentSemanticTokensProvider, legend: vscode.SemanticTokensLegend): vscode.Disposable {
2553
const handle = this._addNewAdapter(new DocumentSemanticTokensAdapter(this._documents, provider), extension);
2554
const eventHandle = (typeof provider.onDidChangeSemanticTokens === 'function' ? this._nextHandle() : undefined);
2555
this._proxy.$registerDocumentSemanticTokensProvider(handle, this._transformDocumentSelector(selector, extension), legend, eventHandle);
2556
let result = this._createDisposable(handle);
2557
2558
if (eventHandle) {
2559
const subscription = provider.onDidChangeSemanticTokens!(_ => this._proxy.$emitDocumentSemanticTokensEvent(eventHandle));
2560
result = Disposable.from(result, subscription);
2561
}
2562
2563
return result;
2564
}
2565
2566
$provideDocumentSemanticTokens(handle: number, resource: UriComponents, previousResultId: number, token: CancellationToken): Promise<VSBuffer | null> {
2567
return this._withAdapter(handle, DocumentSemanticTokensAdapter, adapter => adapter.provideDocumentSemanticTokens(URI.revive(resource), previousResultId, token), null, token);
2568
}
2569
2570
$releaseDocumentSemanticTokens(handle: number, semanticColoringResultId: number): void {
2571
this._withAdapter(handle, DocumentSemanticTokensAdapter, adapter => adapter.releaseDocumentSemanticColoring(semanticColoringResultId), undefined, undefined);
2572
}
2573
2574
registerDocumentRangeSemanticTokensProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentRangeSemanticTokensProvider, legend: vscode.SemanticTokensLegend): vscode.Disposable {
2575
const handle = this._addNewAdapter(new DocumentRangeSemanticTokensAdapter(this._documents, provider), extension);
2576
const eventHandle = (typeof provider.onDidChangeSemanticTokens === 'function' ? this._nextHandle() : undefined);
2577
this._proxy.$registerDocumentRangeSemanticTokensProvider(handle, this._transformDocumentSelector(selector, extension), legend, eventHandle);
2578
let result = this._createDisposable(handle);
2579
2580
if (eventHandle) {
2581
const subscription = provider.onDidChangeSemanticTokens!(_ => this._proxy.$emitDocumentRangeSemanticTokensEvent(eventHandle));
2582
result = Disposable.from(result, subscription);
2583
}
2584
2585
return result;
2586
}
2587
2588
$provideDocumentRangeSemanticTokens(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<VSBuffer | null> {
2589
return this._withAdapter(handle, DocumentRangeSemanticTokensAdapter, adapter => adapter.provideDocumentRangeSemanticTokens(URI.revive(resource), range, token), null, token);
2590
}
2591
2592
//#endregion
2593
2594
// --- suggestion
2595
2596
registerCompletionItemProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, triggerCharacters: string[]): vscode.Disposable {
2597
const handle = this._addNewAdapter(new CompletionsAdapter(this._documents, this._commands.converter, provider, this._apiDeprecation, extension), extension);
2598
this._proxy.$registerCompletionsProvider(handle, this._transformDocumentSelector(selector, extension), triggerCharacters, CompletionsAdapter.supportsResolving(provider), extension.identifier);
2599
return this._createDisposable(handle);
2600
}
2601
2602
$provideCompletionItems(handle: number, resource: UriComponents, position: IPosition, context: languages.CompletionContext, token: CancellationToken): Promise<extHostProtocol.ISuggestResultDto | undefined> {
2603
return this._withAdapter(handle, CompletionsAdapter, adapter => adapter.provideCompletionItems(URI.revive(resource), position, context, token), undefined, token);
2604
}
2605
2606
$resolveCompletionItem(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ISuggestDataDto | undefined> {
2607
return this._withAdapter(handle, CompletionsAdapter, adapter => adapter.resolveCompletionItem(id, token), undefined, token);
2608
}
2609
2610
$releaseCompletionItems(handle: number, id: number): void {
2611
this._withAdapter(handle, CompletionsAdapter, adapter => adapter.releaseCompletionItems(id), undefined, undefined);
2612
}
2613
2614
// --- ghost text
2615
2616
registerInlineCompletionsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlineCompletionItemProvider, metadata: vscode.InlineCompletionItemProviderMetadata | undefined): vscode.Disposable {
2617
const adapter = new InlineCompletionAdapter(extension, this._documents, provider, this._commands.converter);
2618
const handle = this._addNewAdapter(adapter, extension);
2619
let result = this._createDisposable(handle);
2620
2621
const supportsOnDidChange = isProposedApiEnabled(extension, 'inlineCompletionsAdditions') && typeof provider.onDidChange === 'function';
2622
if (supportsOnDidChange) {
2623
const subscription = provider.onDidChange!(e => this._proxy.$emitInlineCompletionsChange(handle, e ? { data: e.data } : undefined));
2624
result = Disposable.from(result, subscription);
2625
}
2626
2627
const supportsOnDidChangeModelInfo = isProposedApiEnabled(extension, 'inlineCompletionsAdditions') && typeof provider.onDidChangeModelInfo === 'function';
2628
if (supportsOnDidChangeModelInfo) {
2629
const subscription = provider.onDidChangeModelInfo!(_ => this._proxy.$emitInlineCompletionModelInfoChange(handle, adapter.modelInfo));
2630
result = Disposable.from(result, subscription);
2631
}
2632
this._proxy.$registerInlineCompletionsSupport(
2633
handle,
2634
this._transformDocumentSelector(selector, extension),
2635
adapter.supportsHandleEvents,
2636
ExtensionIdentifier.toKey(extension.identifier.value),
2637
extension.version,
2638
metadata?.groupId ? ExtensionIdentifier.toKey(metadata.groupId) : undefined,
2639
metadata?.yieldTo?.map(extId => ExtensionIdentifier.toKey(extId)) || [],
2640
metadata?.displayName,
2641
metadata?.debounceDelayMs,
2642
metadata?.excludes?.map(extId => ExtensionIdentifier.toKey(extId)) || [],
2643
supportsOnDidChange,
2644
adapter.supportsSetModelId,
2645
adapter.modelInfo,
2646
supportsOnDidChangeModelInfo,
2647
);
2648
return result;
2649
}
2650
2651
$provideInlineCompletions(handle: number, resource: UriComponents, position: IPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise<extHostProtocol.IdentifiableInlineCompletions | undefined> {
2652
return this._withAdapter(handle, InlineCompletionAdapter, adapter => adapter.provideInlineCompletions(URI.revive(resource), position, context, token), undefined, undefined);
2653
}
2654
2655
$handleInlineCompletionDidShow(handle: number, pid: number, idx: number, updatedInsertText: string): void {
2656
this._withAdapter(handle, InlineCompletionAdapter, async adapter => {
2657
adapter.handleDidShowCompletionItem(pid, idx, updatedInsertText);
2658
}, undefined, undefined);
2659
}
2660
2661
$handleInlineCompletionPartialAccept(handle: number, pid: number, idx: number, acceptedCharacters: number, info: languages.PartialAcceptInfo): void {
2662
this._withAdapter(handle, InlineCompletionAdapter, async adapter => {
2663
adapter.handlePartialAccept(pid, idx, acceptedCharacters, info);
2664
}, undefined, undefined);
2665
}
2666
2667
$handleInlineCompletionEndOfLifetime(handle: number, pid: number, idx: number, reason: languages.InlineCompletionEndOfLifeReason<{ pid: number; idx: number }>): void {
2668
this._withAdapter(handle, InlineCompletionAdapter, async adapter => {
2669
adapter.handleEndOfLifetime(pid, idx, reason);
2670
}, undefined, undefined);
2671
}
2672
2673
$handleInlineCompletionRejection(handle: number, pid: number, idx: number): void {
2674
this._withAdapter(handle, InlineCompletionAdapter, async adapter => {
2675
adapter.handleRejection(pid, idx);
2676
}, undefined, undefined);
2677
}
2678
2679
$freeInlineCompletionsList(handle: number, pid: number, reason: languages.InlineCompletionsDisposeReason): void {
2680
this._withAdapter(handle, InlineCompletionAdapter, async adapter => { adapter.disposeCompletions(pid, reason); }, undefined, undefined);
2681
}
2682
2683
$acceptInlineCompletionsUnificationState(state: IInlineCompletionsUnificationState): void {
2684
this._inlineCompletionsUnificationState = state;
2685
this._onDidChangeInlineCompletionsUnificationState.fire();
2686
}
2687
2688
$handleInlineCompletionSetCurrentModelId(handle: number, modelId: string): void {
2689
this._withAdapter(handle, InlineCompletionAdapter, async adapter => {
2690
adapter.setCurrentModelId(modelId);
2691
}, undefined, undefined);
2692
}
2693
2694
// --- parameter hints
2695
2696
registerSignatureHelpProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SignatureHelpProvider, metadataOrTriggerChars: string[] | vscode.SignatureHelpProviderMetadata): vscode.Disposable {
2697
const metadata: extHostProtocol.ISignatureHelpProviderMetadataDto | undefined = Array.isArray(metadataOrTriggerChars)
2698
? { triggerCharacters: metadataOrTriggerChars, retriggerCharacters: [] }
2699
: metadataOrTriggerChars;
2700
2701
const handle = this._addNewAdapter(new SignatureHelpAdapter(this._documents, provider), extension);
2702
this._proxy.$registerSignatureHelpProvider(handle, this._transformDocumentSelector(selector, extension), metadata);
2703
return this._createDisposable(handle);
2704
}
2705
2706
$provideSignatureHelp(handle: number, resource: UriComponents, position: IPosition, context: extHostProtocol.ISignatureHelpContextDto, token: CancellationToken): Promise<extHostProtocol.ISignatureHelpDto | undefined> {
2707
return this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.provideSignatureHelp(URI.revive(resource), position, context, token), undefined, token);
2708
}
2709
2710
$releaseSignatureHelp(handle: number, id: number): void {
2711
this._withAdapter(handle, SignatureHelpAdapter, adapter => adapter.releaseSignatureHelp(id), undefined, undefined);
2712
}
2713
2714
// --- inline hints
2715
2716
registerInlayHintsProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.InlayHintsProvider): vscode.Disposable {
2717
2718
const eventHandle = typeof provider.onDidChangeInlayHints === 'function' ? this._nextHandle() : undefined;
2719
const handle = this._addNewAdapter(new InlayHintsAdapter(this._documents, this._commands.converter, provider, this._logService, extension), extension);
2720
2721
this._proxy.$registerInlayHintsProvider(handle, this._transformDocumentSelector(selector, extension), typeof provider.resolveInlayHint === 'function', eventHandle, ExtHostLanguageFeatures._extLabel(extension));
2722
let result = this._createDisposable(handle);
2723
2724
if (eventHandle !== undefined) {
2725
const subscription = provider.onDidChangeInlayHints!(uri => this._proxy.$emitInlayHintsEvent(eventHandle));
2726
result = Disposable.from(result, subscription);
2727
}
2728
return result;
2729
}
2730
2731
$provideInlayHints(handle: number, resource: UriComponents, range: IRange, token: CancellationToken): Promise<extHostProtocol.IInlayHintsDto | undefined> {
2732
return this._withAdapter(handle, InlayHintsAdapter, adapter => adapter.provideInlayHints(URI.revive(resource), range, token), undefined, token);
2733
}
2734
2735
$resolveInlayHint(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.IInlayHintDto | undefined> {
2736
return this._withAdapter(handle, InlayHintsAdapter, adapter => adapter.resolveInlayHint(id, token), undefined, token);
2737
}
2738
2739
$releaseInlayHints(handle: number, id: number): void {
2740
this._withAdapter(handle, InlayHintsAdapter, adapter => adapter.releaseHints(id), undefined, undefined);
2741
}
2742
2743
// --- links
2744
2745
registerDocumentLinkProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentLinkProvider): vscode.Disposable {
2746
const handle = this._addNewAdapter(new LinkProviderAdapter(this._documents, provider), extension);
2747
this._proxy.$registerDocumentLinkProvider(handle, this._transformDocumentSelector(selector, extension), typeof provider.resolveDocumentLink === 'function');
2748
return this._createDisposable(handle);
2749
}
2750
2751
$provideDocumentLinks(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.ILinksListDto | undefined> {
2752
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.provideLinks(URI.revive(resource), token), undefined, token, resource.scheme === 'output');
2753
}
2754
2755
$resolveDocumentLink(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<extHostProtocol.ILinkDto | undefined> {
2756
return this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.resolveLink(id, token), undefined, undefined, true);
2757
}
2758
2759
$releaseDocumentLinks(handle: number, id: number): void {
2760
this._withAdapter(handle, LinkProviderAdapter, adapter => adapter.releaseLinks(id), undefined, undefined, true);
2761
}
2762
2763
registerColorProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentColorProvider): vscode.Disposable {
2764
const handle = this._addNewAdapter(new ColorProviderAdapter(this._documents, provider), extension);
2765
this._proxy.$registerDocumentColorProvider(handle, this._transformDocumentSelector(selector, extension));
2766
return this._createDisposable(handle);
2767
}
2768
2769
$provideDocumentColors(handle: number, resource: UriComponents, token: CancellationToken): Promise<extHostProtocol.IRawColorInfo[]> {
2770
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColors(URI.revive(resource), token), [], token);
2771
}
2772
2773
$provideColorPresentations(handle: number, resource: UriComponents, colorInfo: extHostProtocol.IRawColorInfo, token: CancellationToken): Promise<languages.IColorPresentation[] | undefined> {
2774
return this._withAdapter(handle, ColorProviderAdapter, adapter => adapter.provideColorPresentations(URI.revive(resource), colorInfo, token), undefined, token);
2775
}
2776
2777
registerFoldingRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.FoldingRangeProvider): vscode.Disposable {
2778
const handle = this._nextHandle();
2779
const eventHandle = typeof provider.onDidChangeFoldingRanges === 'function' ? this._nextHandle() : undefined;
2780
2781
this._adapter.set(handle, new AdapterData(new FoldingProviderAdapter(this._documents, provider), extension));
2782
this._proxy.$registerFoldingRangeProvider(handle, this._transformDocumentSelector(selector, extension), extension.identifier, eventHandle);
2783
let result = this._createDisposable(handle);
2784
2785
if (eventHandle !== undefined) {
2786
const subscription = provider.onDidChangeFoldingRanges!(() => this._proxy.$emitFoldingRangeEvent(eventHandle));
2787
result = Disposable.from(result, subscription);
2788
}
2789
2790
return result;
2791
}
2792
2793
$provideFoldingRanges(handle: number, resource: UriComponents, context: vscode.FoldingContext, token: CancellationToken): Promise<languages.FoldingRange[] | undefined> {
2794
return this._withAdapter(
2795
handle,
2796
FoldingProviderAdapter,
2797
(adapter) =>
2798
adapter.provideFoldingRanges(URI.revive(resource), context, token),
2799
undefined,
2800
token
2801
);
2802
}
2803
2804
// --- smart select
2805
2806
registerSelectionRangeProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.SelectionRangeProvider): vscode.Disposable {
2807
const handle = this._addNewAdapter(new SelectionRangeAdapter(this._documents, provider, this._logService), extension);
2808
this._proxy.$registerSelectionRangeProvider(handle, this._transformDocumentSelector(selector, extension));
2809
return this._createDisposable(handle);
2810
}
2811
2812
$provideSelectionRanges(handle: number, resource: UriComponents, positions: IPosition[], token: CancellationToken): Promise<languages.SelectionRange[][]> {
2813
return this._withAdapter(handle, SelectionRangeAdapter, adapter => adapter.provideSelectionRanges(URI.revive(resource), positions, token), [], token);
2814
}
2815
2816
// --- call hierarchy
2817
2818
registerCallHierarchyProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CallHierarchyProvider): vscode.Disposable {
2819
const handle = this._addNewAdapter(new CallHierarchyAdapter(this._documents, provider), extension);
2820
this._proxy.$registerCallHierarchyProvider(handle, this._transformDocumentSelector(selector, extension));
2821
return this._createDisposable(handle);
2822
}
2823
2824
$prepareCallHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<extHostProtocol.ICallHierarchyItemDto[] | undefined> {
2825
return this._withAdapter(handle, CallHierarchyAdapter, adapter => Promise.resolve(adapter.prepareSession(URI.revive(resource), position, token)), undefined, token);
2826
}
2827
2828
$provideCallHierarchyIncomingCalls(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.IIncomingCallDto[] | undefined> {
2829
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsTo(sessionId, itemId, token), undefined, token);
2830
}
2831
2832
$provideCallHierarchyOutgoingCalls(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.IOutgoingCallDto[] | undefined> {
2833
return this._withAdapter(handle, CallHierarchyAdapter, adapter => adapter.provideCallsFrom(sessionId, itemId, token), undefined, token);
2834
}
2835
2836
$releaseCallHierarchy(handle: number, sessionId: string): void {
2837
this._withAdapter(handle, CallHierarchyAdapter, adapter => Promise.resolve(adapter.releaseSession(sessionId)), undefined, undefined);
2838
}
2839
2840
// --- type hierarchy
2841
registerTypeHierarchyProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.TypeHierarchyProvider): vscode.Disposable {
2842
const handle = this._addNewAdapter(new TypeHierarchyAdapter(this._documents, provider), extension);
2843
this._proxy.$registerTypeHierarchyProvider(handle, this._transformDocumentSelector(selector, extension));
2844
return this._createDisposable(handle);
2845
}
2846
2847
$prepareTypeHierarchy(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
2848
return this._withAdapter(handle, TypeHierarchyAdapter, adapter => Promise.resolve(adapter.prepareSession(URI.revive(resource), position, token)), undefined, token);
2849
}
2850
2851
$provideTypeHierarchySupertypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
2852
return this._withAdapter(handle, TypeHierarchyAdapter, adapter => adapter.provideSupertypes(sessionId, itemId, token), undefined, token);
2853
}
2854
2855
$provideTypeHierarchySubtypes(handle: number, sessionId: string, itemId: string, token: CancellationToken): Promise<extHostProtocol.ITypeHierarchyItemDto[] | undefined> {
2856
return this._withAdapter(handle, TypeHierarchyAdapter, adapter => adapter.provideSubtypes(sessionId, itemId, token), undefined, token);
2857
}
2858
2859
$releaseTypeHierarchy(handle: number, sessionId: string): void {
2860
this._withAdapter(handle, TypeHierarchyAdapter, adapter => Promise.resolve(adapter.releaseSession(sessionId)), undefined, undefined);
2861
}
2862
2863
// --- Document on drop
2864
2865
registerDocumentOnDropEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentDropEditProvider, metadata?: vscode.DocumentDropEditProviderMetadata) {
2866
const handle = this._nextHandle();
2867
this._adapter.set(handle, new AdapterData(new DocumentDropEditAdapter(this._proxy, this._documents, provider, handle, extension), extension));
2868
2869
this._proxy.$registerDocumentOnDropEditProvider(handle, this._transformDocumentSelector(selector, extension), metadata ? {
2870
supportsResolve: !!provider.resolveDocumentDropEdit,
2871
dropMimeTypes: metadata.dropMimeTypes,
2872
providedDropKinds: metadata.providedDropEditKinds?.map(x => x.value),
2873
} : undefined);
2874
2875
return this._createDisposable(handle);
2876
}
2877
2878
$provideDocumentOnDropEdits(handle: number, requestId: number, resource: UriComponents, position: IPosition, dataTransferDto: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.IDocumentDropEditDto[] | undefined> {
2879
return this._withAdapter(handle, DocumentDropEditAdapter, adapter =>
2880
Promise.resolve(adapter.provideDocumentOnDropEdits(requestId, URI.revive(resource), position, dataTransferDto, token)), undefined, undefined);
2881
}
2882
2883
$resolveDropEdit(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<{ additionalEdit?: extHostProtocol.IWorkspaceEditDto }> {
2884
return this._withAdapter(handle, DocumentDropEditAdapter, adapter => adapter.resolveDropEdit(id, token), {}, undefined);
2885
}
2886
2887
$releaseDocumentOnDropEdits(handle: number, cacheId: number): void {
2888
this._withAdapter(handle, DocumentDropEditAdapter, adapter => Promise.resolve(adapter.releaseDropEdits(cacheId)), undefined, undefined);
2889
}
2890
2891
// --- copy/paste actions
2892
2893
registerDocumentPasteEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentPasteEditProvider, metadata: vscode.DocumentPasteProviderMetadata): vscode.Disposable {
2894
const handle = this._nextHandle();
2895
this._adapter.set(handle, new AdapterData(new DocumentPasteEditProvider(this._proxy, this._documents, provider, handle, extension), extension));
2896
this._proxy.$registerPasteEditProvider(handle, this._transformDocumentSelector(selector, extension), {
2897
supportsCopy: !!provider.prepareDocumentPaste,
2898
supportsPaste: !!provider.provideDocumentPasteEdits,
2899
supportsResolve: !!provider.resolveDocumentPasteEdit,
2900
providedPasteEditKinds: metadata.providedPasteEditKinds?.map(x => x.value),
2901
copyMimeTypes: metadata.copyMimeTypes,
2902
pasteMimeTypes: metadata.pasteMimeTypes,
2903
});
2904
return this._createDisposable(handle);
2905
}
2906
2907
$prepareDocumentPaste(handle: number, resource: UriComponents, ranges: IRange[], dataTransfer: extHostProtocol.DataTransferDTO, token: CancellationToken): Promise<extHostProtocol.DataTransferDTO | undefined> {
2908
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.prepareDocumentPaste(URI.revive(resource), ranges, dataTransfer, token), undefined, token);
2909
}
2910
2911
$providePasteEdits(handle: number, requestId: number, resource: UriComponents, ranges: IRange[], dataTransferDto: extHostProtocol.DataTransferDTO, context: extHostProtocol.IDocumentPasteContextDto, token: CancellationToken): Promise<extHostProtocol.IPasteEditDto[] | undefined> {
2912
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.providePasteEdits(requestId, URI.revive(resource), ranges, dataTransferDto, context, token), undefined, token);
2913
}
2914
2915
$resolvePasteEdit(handle: number, id: extHostProtocol.ChainedCacheId, token: CancellationToken): Promise<{ additionalEdit?: extHostProtocol.IWorkspaceEditDto }> {
2916
return this._withAdapter(handle, DocumentPasteEditProvider, adapter => adapter.resolvePasteEdit(id, token), {}, undefined);
2917
}
2918
2919
$releasePasteEdits(handle: number, cacheId: number): void {
2920
this._withAdapter(handle, DocumentPasteEditProvider, adapter => Promise.resolve(adapter.releasePasteEdits(cacheId)), undefined, undefined);
2921
}
2922
2923
// --- configuration
2924
2925
private static _serializeRegExp(regExp: RegExp): extHostProtocol.IRegExpDto {
2926
return {
2927
pattern: regExp.source,
2928
flags: regExp.flags,
2929
};
2930
}
2931
2932
private static _serializeIndentationRule(indentationRule: vscode.IndentationRule): extHostProtocol.IIndentationRuleDto {
2933
return {
2934
decreaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.decreaseIndentPattern),
2935
increaseIndentPattern: ExtHostLanguageFeatures._serializeRegExp(indentationRule.increaseIndentPattern),
2936
indentNextLinePattern: indentationRule.indentNextLinePattern ? ExtHostLanguageFeatures._serializeRegExp(indentationRule.indentNextLinePattern) : undefined,
2937
unIndentedLinePattern: indentationRule.unIndentedLinePattern ? ExtHostLanguageFeatures._serializeRegExp(indentationRule.unIndentedLinePattern) : undefined,
2938
};
2939
}
2940
2941
private static _serializeOnEnterRule(onEnterRule: vscode.OnEnterRule): extHostProtocol.IOnEnterRuleDto {
2942
return {
2943
beforeText: ExtHostLanguageFeatures._serializeRegExp(onEnterRule.beforeText),
2944
afterText: onEnterRule.afterText ? ExtHostLanguageFeatures._serializeRegExp(onEnterRule.afterText) : undefined,
2945
previousLineText: onEnterRule.previousLineText ? ExtHostLanguageFeatures._serializeRegExp(onEnterRule.previousLineText) : undefined,
2946
action: onEnterRule.action
2947
};
2948
}
2949
2950
private static _serializeOnEnterRules(onEnterRules: vscode.OnEnterRule[]): extHostProtocol.IOnEnterRuleDto[] {
2951
return onEnterRules.map(ExtHostLanguageFeatures._serializeOnEnterRule);
2952
}
2953
2954
private static _serializeAutoClosingPair(autoClosingPair: vscode.AutoClosingPair): IAutoClosingPairConditional {
2955
return {
2956
open: autoClosingPair.open,
2957
close: autoClosingPair.close,
2958
notIn: autoClosingPair.notIn ? autoClosingPair.notIn.map(v => SyntaxTokenType.toString(v)) : undefined,
2959
};
2960
}
2961
2962
private static _serializeAutoClosingPairs(autoClosingPairs: vscode.AutoClosingPair[]): IAutoClosingPairConditional[] {
2963
return autoClosingPairs.map(ExtHostLanguageFeatures._serializeAutoClosingPair);
2964
}
2965
2966
setLanguageConfiguration(extension: IExtensionDescription, languageId: string, configuration: vscode.LanguageConfiguration): vscode.Disposable {
2967
const { wordPattern } = configuration;
2968
2969
// check for a valid word pattern
2970
if (wordPattern && regExpLeadsToEndlessLoop(wordPattern)) {
2971
throw new Error(`Invalid language configuration: wordPattern '${wordPattern}' is not allowed to match the empty string.`);
2972
}
2973
2974
// word definition
2975
if (wordPattern) {
2976
this._documents.setWordDefinitionFor(languageId, wordPattern);
2977
} else {
2978
this._documents.setWordDefinitionFor(languageId, undefined);
2979
}
2980
2981
if (configuration.__electricCharacterSupport) {
2982
this._apiDeprecation.report('LanguageConfiguration.__electricCharacterSupport', extension,
2983
`Do not use.`);
2984
}
2985
2986
if (configuration.__characterPairSupport) {
2987
this._apiDeprecation.report('LanguageConfiguration.__characterPairSupport', extension,
2988
`Do not use.`);
2989
}
2990
2991
const handle = this._nextHandle();
2992
const serializedConfiguration: extHostProtocol.ILanguageConfigurationDto = {
2993
comments: configuration.comments,
2994
brackets: configuration.brackets,
2995
wordPattern: configuration.wordPattern ? ExtHostLanguageFeatures._serializeRegExp(configuration.wordPattern) : undefined,
2996
indentationRules: configuration.indentationRules ? ExtHostLanguageFeatures._serializeIndentationRule(configuration.indentationRules) : undefined,
2997
onEnterRules: configuration.onEnterRules ? ExtHostLanguageFeatures._serializeOnEnterRules(configuration.onEnterRules) : undefined,
2998
__electricCharacterSupport: configuration.__electricCharacterSupport,
2999
__characterPairSupport: configuration.__characterPairSupport,
3000
autoClosingPairs: configuration.autoClosingPairs ? ExtHostLanguageFeatures._serializeAutoClosingPairs(configuration.autoClosingPairs) : undefined,
3001
};
3002
3003
this._proxy.$setLanguageConfiguration(handle, languageId, serializedConfiguration);
3004
return this._createDisposable(handle);
3005
}
3006
3007
$setWordDefinitions(wordDefinitions: extHostProtocol.ILanguageWordDefinitionDto[]): void {
3008
for (const wordDefinition of wordDefinitions) {
3009
this._documents.setWordDefinitionFor(wordDefinition.languageId, new RegExp(wordDefinition.regexSource, wordDefinition.regexFlags));
3010
}
3011
}
3012
}
3013
3014