Path: blob/main/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
5222 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { VSBuffer } from '../../../base/common/buffer.js';6import { CancellationToken } from '../../../base/common/cancellation.js';7import { createStringDataTransferItem, IReadonlyVSDataTransfer, VSDataTransfer } from '../../../base/common/dataTransfer.js';8import { CancellationError } from '../../../base/common/errors.js';9import { Emitter, Event } from '../../../base/common/event.js';10import { HierarchicalKind } from '../../../base/common/hierarchicalKind.js';11import { combinedDisposable, Disposable, DisposableMap, toDisposable } from '../../../base/common/lifecycle.js';12import { ResourceMap } from '../../../base/common/map.js';13import { revive } from '../../../base/common/marshalling.js';14import { mixin } from '../../../base/common/objects.js';15import { URI } from '../../../base/common/uri.js';16import { Position as EditorPosition, IPosition } from '../../../editor/common/core/position.js';17import { Range as EditorRange, IRange } from '../../../editor/common/core/range.js';18import { Selection } from '../../../editor/common/core/selection.js';19import * as languages from '../../../editor/common/languages.js';20import { ILanguageService } from '../../../editor/common/languages/language.js';21import { IndentationRule, LanguageConfiguration, OnEnterRule } from '../../../editor/common/languages/languageConfiguration.js';22import { ILanguageConfigurationService } from '../../../editor/common/languages/languageConfigurationRegistry.js';23import { ITextModel } from '../../../editor/common/model.js';24import { ILanguageFeaturesService } from '../../../editor/common/services/languageFeatures.js';25import { decodeSemanticTokensDto } from '../../../editor/common/services/semanticTokensDto.js';26import { ExtensionIdentifier } from '../../../platform/extensions/common/extensions.js';27import { IUriIdentityService } from '../../../platform/uriIdentity/common/uriIdentity.js';28import { reviveWorkspaceEditDto } from './mainThreadBulkEdits.js';29import * as typeConvert from '../common/extHostTypeConverters.js';30import { DataTransferFileCache } from '../common/shared/dataTransferCache.js';31import * as callh from '../../contrib/callHierarchy/common/callHierarchy.js';32import * as search from '../../contrib/search/common/search.js';33import * as typeh from '../../contrib/typeHierarchy/common/typeHierarchy.js';34import { extHostNamedCustomer, IExtHostContext } from '../../services/extensions/common/extHostCustomers.js';35import { ExtHostContext, ExtHostLanguageFeaturesShape, HoverWithId, ICallHierarchyItemDto, ICodeActionDto, ICodeActionProviderMetadataDto, IdentifiableInlineCompletion, IdentifiableInlineCompletions, IDocumentDropEditDto, IDocumentDropEditProviderMetadata, IDocumentFilterDto, IIndentationRuleDto, IInlayHintDto, IInlineCompletionChangeHintDto, IInlineCompletionModelInfoDto, ILanguageConfigurationDto, ILanguageWordDefinitionDto, ILinkDto, ILocationDto, ILocationLinkDto, IOnEnterRuleDto, IPasteEditDto, IPasteEditProviderMetadataDto, IRegExpDto, ISignatureHelpProviderMetadataDto, ISuggestDataDto, ISuggestDataDtoField, ISuggestResultDtoField, ITypeHierarchyItemDto, IWorkspaceSymbolDto, MainContext, MainThreadLanguageFeaturesShape } from '../common/extHost.protocol.js';36import { InlineCompletionEndOfLifeReasonKind } from '../common/extHostTypes.js';37import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';38import { DataChannelForwardingTelemetryService, forwardToChannelIf, isCopilotLikeExtension } from '../../../platform/dataChannel/browser/forwardingTelemetryService.js';39import { IAiEditTelemetryService } from '../../contrib/editTelemetry/browser/telemetry/aiEditTelemetry/aiEditTelemetryService.js';40import { EditDeltaInfo } from '../../../editor/common/textModelEditSource.js';41import { IInlineCompletionsUnificationService } from '../../services/inlineCompletions/common/inlineCompletionsUnification.js';42import { InlineCompletionEndOfLifeEvent, sendInlineCompletionsEndOfLifeTelemetry } from '../../../editor/contrib/inlineCompletions/browser/telemetry.js';4344@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)45export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape {4647private readonly _proxy: ExtHostLanguageFeaturesShape;48private readonly _registrations = this._register(new DisposableMap<number>());4950constructor(51extHostContext: IExtHostContext,52@ILanguageService private readonly _languageService: ILanguageService,53@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService,54@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,55@IUriIdentityService private readonly _uriIdentService: IUriIdentityService,56@IInstantiationService private readonly _instantiationService: IInstantiationService,57@IInlineCompletionsUnificationService private readonly _inlineCompletionsUnificationService: IInlineCompletionsUnificationService,58) {59super();6061this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageFeatures);6263if (this._languageService) {64const updateAllWordDefinitions = () => {65const wordDefinitionDtos: ILanguageWordDefinitionDto[] = [];66for (const languageId of _languageService.getRegisteredLanguageIds()) {67const wordDefinition = this._languageConfigurationService.getLanguageConfiguration(languageId).getWordDefinition();68wordDefinitionDtos.push({69languageId: languageId,70regexSource: wordDefinition.source,71regexFlags: wordDefinition.flags72});73}74this._proxy.$setWordDefinitions(wordDefinitionDtos);75};76this._register(this._languageConfigurationService.onDidChange((e) => {77if (!e.languageId) {78updateAllWordDefinitions();79} else {80const wordDefinition = this._languageConfigurationService.getLanguageConfiguration(e.languageId).getWordDefinition();81this._proxy.$setWordDefinitions([{82languageId: e.languageId,83regexSource: wordDefinition.source,84regexFlags: wordDefinition.flags85}]);86}87}));88updateAllWordDefinitions();89}9091if (this._inlineCompletionsUnificationService) {92this._register(this._inlineCompletionsUnificationService.onDidStateChange(() => {93this._proxy.$acceptInlineCompletionsUnificationState(this._inlineCompletionsUnificationService.state);94}));95this._proxy.$acceptInlineCompletionsUnificationState(this._inlineCompletionsUnificationService.state);96}97}9899$unregister(handle: number): void {100this._registrations.deleteAndDispose(handle);101}102103//#region --- revive functions104105private static _reviveLocationDto(data?: ILocationDto): languages.Location;106private static _reviveLocationDto(data?: ILocationDto[]): languages.Location[];107private static _reviveLocationDto(data: ILocationDto | ILocationDto[] | undefined): languages.Location | languages.Location[] | undefined {108if (!data) {109return data;110} else if (Array.isArray(data)) {111data.forEach(l => MainThreadLanguageFeatures._reviveLocationDto(l));112return <languages.Location[]>data;113} else {114data.uri = URI.revive(data.uri);115return <languages.Location>data;116}117}118119private static _reviveLocationLinkDto(data: ILocationLinkDto): languages.LocationLink;120private static _reviveLocationLinkDto(data: ILocationLinkDto[]): languages.LocationLink[];121private static _reviveLocationLinkDto(data: ILocationLinkDto | ILocationLinkDto[]): languages.LocationLink | languages.LocationLink[] {122if (!data) {123return <languages.LocationLink>data;124} else if (Array.isArray(data)) {125data.forEach(l => MainThreadLanguageFeatures._reviveLocationLinkDto(l));126return <languages.LocationLink[]>data;127} else {128data.uri = URI.revive(data.uri);129return <languages.LocationLink>data;130}131}132133private static _reviveWorkspaceSymbolDto(data: IWorkspaceSymbolDto): search.IWorkspaceSymbol;134private static _reviveWorkspaceSymbolDto(data: IWorkspaceSymbolDto[]): search.IWorkspaceSymbol[];135private static _reviveWorkspaceSymbolDto(data: undefined): undefined;136private static _reviveWorkspaceSymbolDto(data: IWorkspaceSymbolDto | IWorkspaceSymbolDto[] | undefined): search.IWorkspaceSymbol | search.IWorkspaceSymbol[] | undefined {137if (!data) {138return data;139} else if (Array.isArray(data)) {140data.forEach(MainThreadLanguageFeatures._reviveWorkspaceSymbolDto);141return <search.IWorkspaceSymbol[]>data;142} else {143data.location = MainThreadLanguageFeatures._reviveLocationDto(data.location);144return <search.IWorkspaceSymbol>data;145}146}147148private static _reviveCodeActionDto(data: ReadonlyArray<ICodeActionDto>, uriIdentService: IUriIdentityService): languages.CodeAction[] {149data?.forEach(code => reviveWorkspaceEditDto(code.edit, uriIdentService));150return <languages.CodeAction[]>data;151}152153private static _reviveLinkDTO(data: ILinkDto): languages.ILink {154if (data.url && typeof data.url !== 'string') {155data.url = URI.revive(data.url);156}157return <languages.ILink>data;158}159160private static _reviveCallHierarchyItemDto(data: ICallHierarchyItemDto | undefined): callh.CallHierarchyItem {161if (data) {162data.uri = URI.revive(data.uri);163}164return data as callh.CallHierarchyItem;165}166167private static _reviveTypeHierarchyItemDto(data: ITypeHierarchyItemDto | undefined): typeh.TypeHierarchyItem {168if (data) {169data.uri = URI.revive(data.uri);170}171return data as typeh.TypeHierarchyItem;172}173174//#endregion175176// --- outline177178$registerDocumentSymbolProvider(handle: number, selector: IDocumentFilterDto[], displayName: string): void {179this._registrations.set(handle, this._languageFeaturesService.documentSymbolProvider.register(selector, {180displayName,181provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise<languages.DocumentSymbol[] | undefined> => {182return this._proxy.$provideDocumentSymbols(handle, model.uri, token);183}184}));185}186187// --- code lens188189$registerCodeLensSupport(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {190191const provider: languages.CodeLensProvider = {192provideCodeLenses: async (model: ITextModel, token: CancellationToken): Promise<languages.CodeLensList | undefined> => {193const listDto = await this._proxy.$provideCodeLenses(handle, model.uri, token);194if (!listDto) {195return undefined;196}197return {198lenses: listDto.lenses,199dispose: () => listDto.cacheId && this._proxy.$releaseCodeLenses(handle, listDto.cacheId)200};201},202resolveCodeLens: async (model: ITextModel, codeLens: languages.CodeLens, token: CancellationToken): Promise<languages.CodeLens | undefined> => {203const result = await this._proxy.$resolveCodeLens(handle, codeLens, token);204if (!result || token.isCancellationRequested) {205return undefined;206}207208return {209...result,210range: model.validateRange(result.range),211};212}213};214215if (typeof eventHandle === 'number') {216const emitter = new Emitter<languages.CodeLensProvider>();217this._registrations.set(eventHandle, emitter);218provider.onDidChange = emitter.event;219}220221this._registrations.set(handle, this._languageFeaturesService.codeLensProvider.register(selector, provider));222}223224$emitCodeLensEvent(eventHandle: number, event?: unknown): void {225const obj = this._registrations.get(eventHandle);226if (obj instanceof Emitter) {227obj.fire(event);228}229}230231// --- declaration232233$registerDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void {234this._registrations.set(handle, this._languageFeaturesService.definitionProvider.register(selector, {235provideDefinition: (model, position, token): Promise<languages.LocationLink[]> => {236return this._proxy.$provideDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);237}238}));239}240241$registerDeclarationSupport(handle: number, selector: IDocumentFilterDto[]): void {242this._registrations.set(handle, this._languageFeaturesService.declarationProvider.register(selector, {243provideDeclaration: (model, position, token) => {244return this._proxy.$provideDeclaration(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);245}246}));247}248249$registerImplementationSupport(handle: number, selector: IDocumentFilterDto[]): void {250this._registrations.set(handle, this._languageFeaturesService.implementationProvider.register(selector, {251provideImplementation: (model, position, token): Promise<languages.LocationLink[]> => {252return this._proxy.$provideImplementation(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);253}254}));255}256257$registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void {258this._registrations.set(handle, this._languageFeaturesService.typeDefinitionProvider.register(selector, {259provideTypeDefinition: (model, position, token): Promise<languages.LocationLink[]> => {260return this._proxy.$provideTypeDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);261}262}));263}264265// --- extra info266267$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void {268/*269const hoverFinalizationRegistry = new FinalizationRegistry((hoverId: number) => {270this._proxy.$releaseHover(handle, hoverId);271});272*/273this._registrations.set(handle, this._languageFeaturesService.hoverProvider.register(selector, {274provideHover: async (model: ITextModel, position: EditorPosition, token: CancellationToken, context?: languages.HoverContext<HoverWithId>): Promise<HoverWithId | undefined> => {275const serializedContext: languages.HoverContext<{ id: number }> = {276verbosityRequest: context?.verbosityRequest ? {277verbosityDelta: context.verbosityRequest.verbosityDelta,278previousHover: { id: context.verbosityRequest.previousHover.id }279} : undefined,280};281const hover = await this._proxy.$provideHover(handle, model.uri, position, serializedContext, token);282// hoverFinalizationRegistry.register(hover, hover.id);283return hover;284}285}));286}287288// --- debug hover289290$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void {291this._registrations.set(handle, this._languageFeaturesService.evaluatableExpressionProvider.register(selector, {292provideEvaluatableExpression: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<languages.EvaluatableExpression | undefined> => {293return this._proxy.$provideEvaluatableExpression(handle, model.uri, position, token);294}295}));296}297298// --- inline values299300$registerInlineValuesProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {301const provider: languages.InlineValuesProvider = {302provideInlineValues: (model: ITextModel, viewPort: EditorRange, context: languages.InlineValueContext, token: CancellationToken): Promise<languages.InlineValue[] | undefined> => {303return this._proxy.$provideInlineValues(handle, model.uri, viewPort, context, token);304}305};306307if (typeof eventHandle === 'number') {308const emitter = new Emitter<void>();309this._registrations.set(eventHandle, emitter);310provider.onDidChangeInlineValues = emitter.event;311}312313this._registrations.set(handle, this._languageFeaturesService.inlineValuesProvider.register(selector, provider));314}315316$emitInlineValuesEvent(eventHandle: number, event?: unknown): void {317const obj = this._registrations.get(eventHandle);318if (obj instanceof Emitter) {319obj.fire(event);320}321}322323// --- occurrences324325$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void {326this._registrations.set(handle, this._languageFeaturesService.documentHighlightProvider.register(selector, {327provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<languages.DocumentHighlight[] | undefined> => {328return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token);329}330}));331}332333$registerMultiDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void {334this._registrations.set(handle, this._languageFeaturesService.multiDocumentHighlightProvider.register(selector, {335selector: selector,336provideMultiDocumentHighlights: (model: ITextModel, position: EditorPosition, otherModels: ITextModel[], token: CancellationToken): Promise<Map<URI, languages.DocumentHighlight[]> | undefined> => {337return this._proxy.$provideMultiDocumentHighlights(handle, model.uri, position, otherModels.map(model => model.uri), token).then(dto => {338// dto should be non-null + non-undefined339// dto length of 0 is valid, just no highlights, pass this through.340if (dto === undefined || dto === null) {341return undefined;342}343const result = new ResourceMap<languages.DocumentHighlight[]>();344dto?.forEach(value => {345// check if the URI exists already, if so, combine the highlights, otherwise create a new entry346const uri = URI.revive(value.uri);347if (result.has(uri)) {348result.get(uri)!.push(...value.highlights);349} else {350result.set(uri, value.highlights);351}352});353return result;354});355}356}));357}358359// --- linked editing360361$registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void {362this._registrations.set(handle, this._languageFeaturesService.linkedEditingRangeProvider.register(selector, {363provideLinkedEditingRanges: async (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<languages.LinkedEditingRanges | undefined> => {364const res = await this._proxy.$provideLinkedEditingRanges(handle, model.uri, position, token);365if (res) {366return {367ranges: res.ranges,368wordPattern: res.wordPattern ? MainThreadLanguageFeatures._reviveRegExp(res.wordPattern) : undefined369};370}371return undefined;372}373}));374}375376// --- references377378$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void {379this._registrations.set(handle, this._languageFeaturesService.referenceProvider.register(selector, {380provideReferences: (model: ITextModel, position: EditorPosition, context: languages.ReferenceContext, token: CancellationToken): Promise<languages.Location[]> => {381return this._proxy.$provideReferences(handle, model.uri, position, context, token).then(MainThreadLanguageFeatures._reviveLocationDto);382}383}));384}385386// --- code actions387388$registerCodeActionSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, extensionId: string, supportsResolve: boolean): void {389const provider: languages.CodeActionProvider = {390provideCodeActions: async (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: languages.CodeActionContext, token: CancellationToken): Promise<languages.CodeActionList | undefined> => {391const listDto = await this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token);392if (!listDto) {393return undefined;394}395return {396actions: MainThreadLanguageFeatures._reviveCodeActionDto(listDto.actions, this._uriIdentService),397dispose: () => {398if (typeof listDto.cacheId === 'number') {399this._proxy.$releaseCodeActions(handle, listDto.cacheId);400}401}402};403},404providedCodeActionKinds: metadata.providedKinds,405documentation: metadata.documentation,406displayName,407extensionId,408};409410if (supportsResolve) {411provider.resolveCodeAction = async (codeAction: languages.CodeAction, token: CancellationToken): Promise<languages.CodeAction> => {412const resolved = await this._proxy.$resolveCodeAction(handle, (<ICodeActionDto>codeAction).cacheId!, token);413if (resolved.edit) {414codeAction.edit = reviveWorkspaceEditDto(resolved.edit, this._uriIdentService);415}416417if (resolved.command) {418codeAction.command = resolved.command;419}420421return codeAction;422};423}424425this._registrations.set(handle, this._languageFeaturesService.codeActionProvider.register(selector, provider));426}427428// --- copy paste action provider429430private readonly _pasteEditProviders = new Map<number, MainThreadPasteEditProvider>();431432$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], metadata: IPasteEditProviderMetadataDto): void {433const provider = new MainThreadPasteEditProvider(handle, this._proxy, metadata, this._uriIdentService);434this._pasteEditProviders.set(handle, provider);435this._registrations.set(handle, combinedDisposable(436this._languageFeaturesService.documentPasteEditProvider.register(selector, provider),437toDisposable(() => this._pasteEditProviders.delete(handle)),438));439}440441$resolvePasteFileData(handle: number, requestId: number, dataId: string): Promise<VSBuffer> {442const provider = this._pasteEditProviders.get(handle);443if (!provider) {444throw new Error('Could not find provider');445}446return provider.resolveFileData(requestId, dataId);447}448449// --- formatting450451$registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void {452this._registrations.set(handle, this._languageFeaturesService.documentFormattingEditProvider.register(selector, {453extensionId,454displayName,455provideDocumentFormattingEdits: (model: ITextModel, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> => {456return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token);457}458}));459}460461$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string, supportsRanges: boolean): void {462this._registrations.set(handle, this._languageFeaturesService.documentRangeFormattingEditProvider.register(selector, {463extensionId,464displayName,465provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> => {466return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token);467},468provideDocumentRangesFormattingEdits: !supportsRanges469? undefined470: (model, ranges, options, token) => {471return this._proxy.$provideDocumentRangesFormattingEdits(handle, model.uri, ranges, options, token);472},473}));474}475476$registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void {477this._registrations.set(handle, this._languageFeaturesService.onTypeFormattingEditProvider.register(selector, {478extensionId,479autoFormatTriggerCharacters,480provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> => {481return this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options, token);482}483}));484}485486// --- navigate type487488$registerNavigateTypeSupport(handle: number, supportsResolve: boolean): void {489let lastResultId: number | undefined;490491const provider: search.IWorkspaceSymbolProvider = {492provideWorkspaceSymbols: async (search: string, token: CancellationToken): Promise<search.IWorkspaceSymbol[]> => {493const result = await this._proxy.$provideWorkspaceSymbols(handle, search, token);494if (lastResultId !== undefined) {495this._proxy.$releaseWorkspaceSymbols(handle, lastResultId);496}497lastResultId = result.cacheId;498return MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(result.symbols);499}500};501if (supportsResolve) {502provider.resolveWorkspaceSymbol = async (item: search.IWorkspaceSymbol, token: CancellationToken): Promise<search.IWorkspaceSymbol | undefined> => {503const resolvedItem = await this._proxy.$resolveWorkspaceSymbol(handle, item, token);504return resolvedItem && MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(resolvedItem);505};506}507this._registrations.set(handle, search.WorkspaceSymbolProviderRegistry.register(provider));508}509510// --- rename511512$registerRenameSupport(handle: number, selector: IDocumentFilterDto[], supportResolveLocation: boolean): void {513this._registrations.set(handle, this._languageFeaturesService.renameProvider.register(selector, {514provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken) => {515return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(data => reviveWorkspaceEditDto(data, this._uriIdentService));516},517resolveRenameLocation: supportResolveLocation518? (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<languages.RenameLocation | undefined> => this._proxy.$resolveRenameLocation(handle, model.uri, position, token)519: undefined520}));521}522523$registerNewSymbolNamesProvider(handle: number, selector: IDocumentFilterDto[]): void {524this._registrations.set(handle, this._languageFeaturesService.newSymbolNamesProvider.register(selector, {525supportsAutomaticNewSymbolNamesTriggerKind: this._proxy.$supportsAutomaticNewSymbolNamesTriggerKind(handle),526provideNewSymbolNames: (model: ITextModel, range: IRange, triggerKind: languages.NewSymbolNameTriggerKind, token: CancellationToken): Promise<languages.NewSymbolName[] | undefined> => {527return this._proxy.$provideNewSymbolNames(handle, model.uri, range, triggerKind, token);528}529} satisfies languages.NewSymbolNamesProvider));530}531532// --- semantic tokens533534$registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: languages.SemanticTokensLegend, eventHandle: number | undefined): void {535let event: Event<void> | undefined = undefined;536if (typeof eventHandle === 'number') {537const emitter = new Emitter<void>();538this._registrations.set(eventHandle, emitter);539event = emitter.event;540}541this._registrations.set(handle, this._languageFeaturesService.documentSemanticTokensProvider.register(selector, new MainThreadDocumentSemanticTokensProvider(this._proxy, handle, legend, event)));542}543544$emitDocumentSemanticTokensEvent(eventHandle: number): void {545const obj = this._registrations.get(eventHandle);546if (obj instanceof Emitter) {547obj.fire(undefined);548}549}550551$emitDocumentRangeSemanticTokensEvent(eventHandle: number): void {552const obj = this._registrations.get(eventHandle);553if (obj instanceof Emitter) {554obj.fire(undefined);555}556}557558$registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: languages.SemanticTokensLegend, eventHandle: number | undefined): void {559let event: Event<void> | undefined = undefined;560if (typeof eventHandle === 'number') {561const emitter = new Emitter<void>();562this._registrations.set(eventHandle, emitter);563event = emitter.event;564}565this._registrations.set(handle, this._languageFeaturesService.documentRangeSemanticTokensProvider.register(selector, new MainThreadDocumentRangeSemanticTokensProvider(this._proxy, handle, legend, event)));566}567568// --- suggest569570private static _inflateSuggestDto(defaultRange: IRange | { insert: IRange; replace: IRange }, data: ISuggestDataDto, extensionId: ExtensionIdentifier): languages.CompletionItem {571572const label = data[ISuggestDataDtoField.label];573const commandId = data[ISuggestDataDtoField.commandId];574const commandIdent = data[ISuggestDataDtoField.commandIdent];575const commitChars = data[ISuggestDataDtoField.commitCharacters];576577type IdentCommand = languages.Command & { $ident: string | undefined };578579let command: IdentCommand | undefined;580if (commandId) {581command = {582$ident: commandIdent,583id: commandId,584title: '',585arguments: commandIdent ? [commandIdent] : data[ISuggestDataDtoField.commandArguments], // Automatically fill in ident as first argument586};587}588589return {590label,591extensionId,592kind: data[ISuggestDataDtoField.kind] ?? languages.CompletionItemKind.Property,593tags: data[ISuggestDataDtoField.kindModifier],594detail: data[ISuggestDataDtoField.detail],595documentation: data[ISuggestDataDtoField.documentation],596sortText: data[ISuggestDataDtoField.sortText],597filterText: data[ISuggestDataDtoField.filterText],598preselect: data[ISuggestDataDtoField.preselect],599insertText: data[ISuggestDataDtoField.insertText] ?? (typeof label === 'string' ? label : label.label),600range: data[ISuggestDataDtoField.range] ?? defaultRange,601insertTextRules: data[ISuggestDataDtoField.insertTextRules],602commitCharacters: commitChars ? Array.from(commitChars) : undefined,603additionalTextEdits: data[ISuggestDataDtoField.additionalTextEdits],604command,605// not-standard606_id: data.x,607};608}609610$registerCompletionsProvider(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void {611const provider: languages.CompletionItemProvider = {612triggerCharacters,613_debugDisplayName: `${extensionId.value}(${triggerCharacters.join('')})`,614provideCompletionItems: async (model: ITextModel, position: EditorPosition, context: languages.CompletionContext, token: CancellationToken): Promise<languages.CompletionList | undefined> => {615const result = await this._proxy.$provideCompletionItems(handle, model.uri, position, context, token);616if (!result) {617return result;618}619return {620suggestions: result[ISuggestResultDtoField.completions].map(d => MainThreadLanguageFeatures._inflateSuggestDto(result[ISuggestResultDtoField.defaultRanges], d, extensionId)),621incomplete: result[ISuggestResultDtoField.isIncomplete] || false,622duration: result[ISuggestResultDtoField.duration],623dispose: () => {624if (typeof result.x === 'number') {625this._proxy.$releaseCompletionItems(handle, result.x);626}627}628};629}630};631if (supportsResolveDetails) {632provider.resolveCompletionItem = (suggestion, token) => {633return this._proxy.$resolveCompletionItem(handle, suggestion._id!, token).then(result => {634if (!result) {635return suggestion;636}637638const newSuggestion = MainThreadLanguageFeatures._inflateSuggestDto(suggestion.range, result, extensionId);639return mixin(suggestion, newSuggestion, true);640});641};642}643this._registrations.set(handle, this._languageFeaturesService.completionProvider.register(selector, provider));644}645646$registerInlineCompletionsSupport(647handle: number,648selector: IDocumentFilterDto[],649supportsHandleEvents: boolean,650extensionId: string,651extensionVersion: string,652groupId: string | undefined,653yieldsToExtensionIds: string[],654displayName: string | undefined,655debounceDelayMs: number | undefined,656excludesExtensionIds: string[],657supportsOnDidChange: boolean,658supportsSetModelId: boolean,659initialModelInfo: IInlineCompletionModelInfoDto | undefined,660supportsOnDidChangeModelInfo: boolean,661): void {662const providerId = new languages.ProviderId(extensionId, extensionVersion, groupId);663664const provider = this._instantiationService.createInstance(665ExtensionBackedInlineCompletionsProvider,666handle,667groupId ?? extensionId,668providerId,669yieldsToExtensionIds,670excludesExtensionIds,671debounceDelayMs,672displayName,673initialModelInfo,674supportsHandleEvents,675supportsSetModelId,676supportsOnDidChange,677supportsOnDidChangeModelInfo,678selector,679this._proxy,680);681682this._registrations.set(handle, provider);683}684685$emitInlineCompletionsChange(handle: number, changeHint: IInlineCompletionChangeHintDto | undefined): void {686const obj = this._registrations.get(handle);687if (obj instanceof ExtensionBackedInlineCompletionsProvider) {688obj._emitDidChange(changeHint);689}690}691692$emitInlineCompletionModelInfoChange(handle: number, data: IInlineCompletionModelInfoDto | undefined): void {693const obj = this._registrations.get(handle);694if (obj instanceof ExtensionBackedInlineCompletionsProvider) {695obj._setModelInfo(data);696}697}698699// --- parameter hints700701$registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void {702this._registrations.set(handle, this._languageFeaturesService.signatureHelpProvider.register(selector, {703704signatureHelpTriggerCharacters: metadata.triggerCharacters,705signatureHelpRetriggerCharacters: metadata.retriggerCharacters,706707provideSignatureHelp: async (model: ITextModel, position: EditorPosition, token: CancellationToken, context: languages.SignatureHelpContext): Promise<languages.SignatureHelpResult | undefined> => {708const result = await this._proxy.$provideSignatureHelp(handle, model.uri, position, context, token);709if (!result) {710return undefined;711}712return {713value: result,714dispose: () => {715this._proxy.$releaseSignatureHelp(handle, result.id);716}717};718}719}));720}721722// --- inline hints723724$registerInlayHintsProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean, eventHandle: number | undefined, displayName: string | undefined): void {725const provider: languages.InlayHintsProvider = {726displayName,727provideInlayHints: async (model: ITextModel, range: EditorRange, token: CancellationToken): Promise<languages.InlayHintList | undefined> => {728const result = await this._proxy.$provideInlayHints(handle, model.uri, range, token);729if (!result) {730return;731}732return {733hints: revive(result.hints),734dispose: () => {735if (result.cacheId) {736this._proxy.$releaseInlayHints(handle, result.cacheId);737}738}739};740}741};742if (supportsResolve) {743provider.resolveInlayHint = async (hint, token) => {744const dto: IInlayHintDto = hint;745if (!dto.cacheId) {746return hint;747}748const result = await this._proxy.$resolveInlayHint(handle, dto.cacheId, token);749if (token.isCancellationRequested) {750throw new CancellationError();751}752if (!result) {753return hint;754}755return {756...hint,757tooltip: result.tooltip,758label: revive<string | languages.InlayHintLabelPart[]>(result.label),759textEdits: result.textEdits760};761};762}763if (typeof eventHandle === 'number') {764const emitter = new Emitter<void>();765this._registrations.set(eventHandle, emitter);766provider.onDidChangeInlayHints = emitter.event;767}768769this._registrations.set(handle, this._languageFeaturesService.inlayHintsProvider.register(selector, provider));770}771772$emitInlayHintsEvent(eventHandle: number): void {773const obj = this._registrations.get(eventHandle);774if (obj instanceof Emitter) {775obj.fire(undefined);776}777}778779// --- links780781$registerDocumentLinkProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean): void {782const provider: languages.LinkProvider = {783provideLinks: (model, token) => {784return this._proxy.$provideDocumentLinks(handle, model.uri, token).then(dto => {785if (!dto) {786return undefined;787}788return {789links: dto.links.map(MainThreadLanguageFeatures._reviveLinkDTO),790dispose: () => {791if (typeof dto.cacheId === 'number') {792this._proxy.$releaseDocumentLinks(handle, dto.cacheId);793}794}795};796});797}798};799if (supportsResolve) {800provider.resolveLink = (link, token) => {801const dto: ILinkDto = link;802if (!dto.cacheId) {803return link;804}805return this._proxy.$resolveDocumentLink(handle, dto.cacheId, token).then(obj => {806return obj && MainThreadLanguageFeatures._reviveLinkDTO(obj);807});808};809}810this._registrations.set(handle, this._languageFeaturesService.linkProvider.register(selector, provider));811}812813// --- colors814815$registerDocumentColorProvider(handle: number, selector: IDocumentFilterDto[]): void {816const proxy = this._proxy;817this._registrations.set(handle, this._languageFeaturesService.colorProvider.register(selector, {818provideDocumentColors: (model, token) => {819return proxy.$provideDocumentColors(handle, model.uri, token)820.then(documentColors => {821return documentColors.map(documentColor => {822const [red, green, blue, alpha] = documentColor.color;823const color = {824red: red,825green: green,826blue: blue,827alpha828};829830return {831color,832range: documentColor.range833};834});835});836},837838provideColorPresentations: (model, colorInfo, token) => {839return proxy.$provideColorPresentations(handle, model.uri, {840color: [colorInfo.color.red, colorInfo.color.green, colorInfo.color.blue, colorInfo.color.alpha],841range: colorInfo.range842}, token);843}844}));845}846847// --- folding848849$registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, eventHandle: number | undefined): void {850const provider: languages.FoldingRangeProvider = {851id: extensionId.value,852provideFoldingRanges: (model, context, token) => {853return this._proxy.$provideFoldingRanges(handle, model.uri, context, token);854}855};856857if (typeof eventHandle === 'number') {858const emitter = new Emitter<languages.FoldingRangeProvider>();859this._registrations.set(eventHandle, emitter);860provider.onDidChange = emitter.event;861}862863this._registrations.set(handle, this._languageFeaturesService.foldingRangeProvider.register(selector, provider));864}865866$emitFoldingRangeEvent(eventHandle: number, event?: unknown): void {867const obj = this._registrations.get(eventHandle);868if (obj instanceof Emitter) {869obj.fire(event);870}871}872873// -- smart select874875$registerSelectionRangeProvider(handle: number, selector: IDocumentFilterDto[]): void {876this._registrations.set(handle, this._languageFeaturesService.selectionRangeProvider.register(selector, {877provideSelectionRanges: (model, positions, token) => {878return this._proxy.$provideSelectionRanges(handle, model.uri, positions, token);879}880}));881}882883// --- call hierarchy884885$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {886this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, {887888prepareCallHierarchy: async (document, position, token) => {889const items = await this._proxy.$prepareCallHierarchy(handle, document.uri, position, token);890if (!items || items.length === 0) {891return undefined;892}893return {894dispose: () => {895for (const item of items) {896this._proxy.$releaseCallHierarchy(handle, item._sessionId);897}898},899roots: items.map(MainThreadLanguageFeatures._reviveCallHierarchyItemDto)900};901},902903provideOutgoingCalls: async (item, token) => {904const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, item._sessionId, item._itemId, token);905if (!outgoing) {906return outgoing;907}908outgoing.forEach(value => {909value.to = MainThreadLanguageFeatures._reviveCallHierarchyItemDto(value.to);910});911// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any912return <any>outgoing;913},914provideIncomingCalls: async (item, token) => {915const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, item._sessionId, item._itemId, token);916if (!incoming) {917return incoming;918}919incoming.forEach(value => {920value.from = MainThreadLanguageFeatures._reviveCallHierarchyItemDto(value.from);921});922// eslint-disable-next-line local/code-no-any-casts, @typescript-eslint/no-explicit-any923return <any>incoming;924}925}));926}927928// --- configuration929930private static _reviveRegExp(regExp: IRegExpDto): RegExp {931return new RegExp(regExp.pattern, regExp.flags);932}933934private static _reviveIndentationRule(indentationRule: IIndentationRuleDto): IndentationRule {935return {936decreaseIndentPattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.decreaseIndentPattern),937increaseIndentPattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.increaseIndentPattern),938indentNextLinePattern: indentationRule.indentNextLinePattern ? MainThreadLanguageFeatures._reviveRegExp(indentationRule.indentNextLinePattern) : undefined,939unIndentedLinePattern: indentationRule.unIndentedLinePattern ? MainThreadLanguageFeatures._reviveRegExp(indentationRule.unIndentedLinePattern) : undefined,940};941}942943private static _reviveOnEnterRule(onEnterRule: IOnEnterRuleDto): OnEnterRule {944return {945beforeText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.beforeText),946afterText: onEnterRule.afterText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.afterText) : undefined,947previousLineText: onEnterRule.previousLineText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.previousLineText) : undefined,948action: onEnterRule.action949};950}951952private static _reviveOnEnterRules(onEnterRules: IOnEnterRuleDto[]): OnEnterRule[] {953return onEnterRules.map(MainThreadLanguageFeatures._reviveOnEnterRule);954}955956$setLanguageConfiguration(handle: number, languageId: string, _configuration: ILanguageConfigurationDto): void {957958const configuration: LanguageConfiguration = {959comments: _configuration.comments,960brackets: _configuration.brackets,961wordPattern: _configuration.wordPattern ? MainThreadLanguageFeatures._reviveRegExp(_configuration.wordPattern) : undefined,962indentationRules: _configuration.indentationRules ? MainThreadLanguageFeatures._reviveIndentationRule(_configuration.indentationRules) : undefined,963onEnterRules: _configuration.onEnterRules ? MainThreadLanguageFeatures._reviveOnEnterRules(_configuration.onEnterRules) : undefined,964965autoClosingPairs: undefined,966surroundingPairs: undefined,967__electricCharacterSupport: undefined968};969970if (_configuration.autoClosingPairs) {971configuration.autoClosingPairs = _configuration.autoClosingPairs;972} else if (_configuration.__characterPairSupport) {973// backwards compatibility974configuration.autoClosingPairs = _configuration.__characterPairSupport.autoClosingPairs;975}976977if (_configuration.__electricCharacterSupport && _configuration.__electricCharacterSupport.docComment) {978configuration.__electricCharacterSupport = {979docComment: {980open: _configuration.__electricCharacterSupport.docComment.open,981close: _configuration.__electricCharacterSupport.docComment.close982}983};984}985986if (this._languageService.isRegisteredLanguageId(languageId)) {987this._registrations.set(handle, this._languageConfigurationService.register(languageId, configuration, 100));988}989}990991// --- type hierarchy992993$registerTypeHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {994this._registrations.set(handle, typeh.TypeHierarchyProviderRegistry.register(selector, {995996prepareTypeHierarchy: async (document, position, token) => {997const items = await this._proxy.$prepareTypeHierarchy(handle, document.uri, position, token);998if (!items) {999return undefined;1000}1001return {1002dispose: () => {1003for (const item of items) {1004this._proxy.$releaseTypeHierarchy(handle, item._sessionId);1005}1006},1007roots: items.map(MainThreadLanguageFeatures._reviveTypeHierarchyItemDto)1008};1009},10101011provideSupertypes: async (item, token) => {1012const supertypes = await this._proxy.$provideTypeHierarchySupertypes(handle, item._sessionId, item._itemId, token);1013if (!supertypes) {1014return supertypes;1015}1016return supertypes.map(MainThreadLanguageFeatures._reviveTypeHierarchyItemDto);1017},1018provideSubtypes: async (item, token) => {1019const subtypes = await this._proxy.$provideTypeHierarchySubtypes(handle, item._sessionId, item._itemId, token);1020if (!subtypes) {1021return subtypes;1022}1023return subtypes.map(MainThreadLanguageFeatures._reviveTypeHierarchyItemDto);1024}1025}));1026}102710281029// --- document drop Edits10301031private readonly _documentOnDropEditProviders = new Map<number, MainThreadDocumentOnDropEditProvider>();10321033$registerDocumentOnDropEditProvider(handle: number, selector: IDocumentFilterDto[], metadata: IDocumentDropEditProviderMetadata): void {1034const provider = new MainThreadDocumentOnDropEditProvider(handle, this._proxy, metadata, this._uriIdentService);1035this._documentOnDropEditProviders.set(handle, provider);1036this._registrations.set(handle, combinedDisposable(1037this._languageFeaturesService.documentDropEditProvider.register(selector, provider),1038toDisposable(() => this._documentOnDropEditProviders.delete(handle)),1039));1040}10411042async $resolveDocumentOnDropFileData(handle: number, requestId: number, dataId: string): Promise<VSBuffer> {1043const provider = this._documentOnDropEditProviders.get(handle);1044if (!provider) {1045throw new Error('Could not find provider');1046}1047return provider.resolveDocumentOnDropFileData(requestId, dataId);1048}1049}10501051class MainThreadPasteEditProvider implements languages.DocumentPasteEditProvider {10521053private readonly dataTransfers = new DataTransferFileCache();10541055public readonly copyMimeTypes: readonly string[];1056public readonly pasteMimeTypes: readonly string[];1057public readonly providedPasteEditKinds: readonly HierarchicalKind[];10581059readonly prepareDocumentPaste?: languages.DocumentPasteEditProvider['prepareDocumentPaste'];1060readonly provideDocumentPasteEdits?: languages.DocumentPasteEditProvider['provideDocumentPasteEdits'];1061readonly resolveDocumentPasteEdit?: languages.DocumentPasteEditProvider['resolveDocumentPasteEdit'];10621063constructor(1064private readonly _handle: number,1065private readonly _proxy: ExtHostLanguageFeaturesShape,1066metadata: IPasteEditProviderMetadataDto,1067@IUriIdentityService private readonly _uriIdentService: IUriIdentityService1068) {1069this.copyMimeTypes = metadata.copyMimeTypes ?? [];1070this.pasteMimeTypes = metadata.pasteMimeTypes ?? [];1071this.providedPasteEditKinds = metadata.providedPasteEditKinds?.map(kind => new HierarchicalKind(kind)) ?? [];10721073if (metadata.supportsCopy) {1074this.prepareDocumentPaste = async (model: ITextModel, selections: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<IReadonlyVSDataTransfer | undefined> => {1075const dataTransferDto = await typeConvert.DataTransfer.fromList(dataTransfer);1076if (token.isCancellationRequested) {1077return undefined;1078}10791080const newDataTransfer = await this._proxy.$prepareDocumentPaste(_handle, model.uri, selections, dataTransferDto, token);1081if (!newDataTransfer) {1082return undefined;1083}10841085const dataTransferOut = new VSDataTransfer();1086for (const [type, item] of newDataTransfer.items) {1087dataTransferOut.replace(type, createStringDataTransferItem(item.asString, item.id));1088}1089return dataTransferOut;1090};1091}10921093if (metadata.supportsPaste) {1094this.provideDocumentPasteEdits = async (model: ITextModel, selections: Selection[], dataTransfer: IReadonlyVSDataTransfer, context: languages.DocumentPasteContext, token: CancellationToken) => {1095const request = this.dataTransfers.add(dataTransfer);1096try {1097const dataTransferDto = await typeConvert.DataTransfer.fromList(dataTransfer);1098if (token.isCancellationRequested) {1099return;1100}11011102const edits = await this._proxy.$providePasteEdits(this._handle, request.id, model.uri, selections, dataTransferDto, {1103only: context.only?.value,1104triggerKind: context.triggerKind,1105}, token);1106if (!edits) {1107return;1108}11091110return {1111edits: edits.map((edit): languages.DocumentPasteEdit => {1112return {1113...edit,1114kind: edit.kind ? new HierarchicalKind(edit.kind.value) : new HierarchicalKind(''),1115yieldTo: edit.yieldTo?.map(x => ({ kind: new HierarchicalKind(x) })),1116additionalEdit: edit.additionalEdit ? reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveFileData(request.id, dataId)) : undefined,1117};1118}),1119dispose: () => {1120this._proxy.$releasePasteEdits(this._handle, request.id);1121},1122};1123} finally {1124request.dispose();1125}1126};1127}1128if (metadata.supportsResolve) {1129this.resolveDocumentPasteEdit = async (edit: languages.DocumentPasteEdit, token: CancellationToken) => {1130const resolved = await this._proxy.$resolvePasteEdit(this._handle, (<IPasteEditDto>edit)._cacheId!, token);1131if (typeof resolved.insertText !== 'undefined') {1132edit.insertText = resolved.insertText;1133}11341135if (resolved.additionalEdit) {1136edit.additionalEdit = reviveWorkspaceEditDto(resolved.additionalEdit, this._uriIdentService);1137}1138return edit;1139};1140}1141}11421143resolveFileData(requestId: number, dataId: string): Promise<VSBuffer> {1144return this.dataTransfers.resolveFileData(requestId, dataId);1145}1146}11471148class MainThreadDocumentOnDropEditProvider implements languages.DocumentDropEditProvider {11491150private readonly dataTransfers = new DataTransferFileCache();11511152readonly dropMimeTypes?: readonly string[];11531154readonly providedDropEditKinds: readonly HierarchicalKind[] | undefined;11551156readonly resolveDocumentDropEdit?: languages.DocumentDropEditProvider['resolveDocumentDropEdit'];11571158constructor(1159private readonly _handle: number,1160private readonly _proxy: ExtHostLanguageFeaturesShape,1161metadata: IDocumentDropEditProviderMetadata | undefined,1162@IUriIdentityService private readonly _uriIdentService: IUriIdentityService1163) {1164this.dropMimeTypes = metadata?.dropMimeTypes ?? ['*/*'];1165this.providedDropEditKinds = metadata?.providedDropKinds?.map(kind => new HierarchicalKind(kind));11661167if (metadata?.supportsResolve) {1168this.resolveDocumentDropEdit = async (edit, token) => {1169const resolved = await this._proxy.$resolvePasteEdit(this._handle, (<IDocumentDropEditDto>edit)._cacheId!, token);1170if (resolved.additionalEdit) {1171edit.additionalEdit = reviveWorkspaceEditDto(resolved.additionalEdit, this._uriIdentService);1172}1173return edit;1174};1175}1176}11771178async provideDocumentDropEdits(model: ITextModel, position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<languages.DocumentDropEditsSession | undefined> {1179const request = this.dataTransfers.add(dataTransfer);1180try {1181const dataTransferDto = await typeConvert.DataTransfer.fromList(dataTransfer);1182if (token.isCancellationRequested) {1183return;1184}11851186const edits = await this._proxy.$provideDocumentOnDropEdits(this._handle, request.id, model.uri, position, dataTransferDto, token);1187if (!edits) {1188return;1189}11901191return {1192edits: edits.map(edit => {1193return {1194...edit,1195yieldTo: edit.yieldTo?.map(x => ({ kind: new HierarchicalKind(x) })),1196kind: edit.kind ? new HierarchicalKind(edit.kind) : undefined,1197additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveDocumentOnDropFileData(request.id, dataId)),1198};1199}),1200dispose: () => {1201this._proxy.$releaseDocumentOnDropEdits(this._handle, request.id);1202},1203};1204} finally {1205request.dispose();1206}1207}12081209public resolveDocumentOnDropFileData(requestId: number, dataId: string): Promise<VSBuffer> {1210return this.dataTransfers.resolveFileData(requestId, dataId);1211}1212}12131214export class MainThreadDocumentSemanticTokensProvider implements languages.DocumentSemanticTokensProvider {12151216constructor(1217private readonly _proxy: ExtHostLanguageFeaturesShape,1218private readonly _handle: number,1219private readonly _legend: languages.SemanticTokensLegend,1220public readonly onDidChange: Event<void> | undefined,1221) {1222}12231224public releaseDocumentSemanticTokens(resultId: string | undefined): void {1225if (resultId) {1226this._proxy.$releaseDocumentSemanticTokens(this._handle, parseInt(resultId, 10));1227}1228}12291230public getLegend(): languages.SemanticTokensLegend {1231return this._legend;1232}12331234async provideDocumentSemanticTokens(model: ITextModel, lastResultId: string | null, token: CancellationToken): Promise<languages.SemanticTokens | languages.SemanticTokensEdits | null> {1235const nLastResultId = lastResultId ? parseInt(lastResultId, 10) : 0;1236const encodedDto = await this._proxy.$provideDocumentSemanticTokens(this._handle, model.uri, nLastResultId, token);1237if (!encodedDto) {1238return null;1239}1240if (token.isCancellationRequested) {1241return null;1242}1243const dto = decodeSemanticTokensDto(encodedDto);1244if (dto.type === 'full') {1245return {1246resultId: String(dto.id),1247data: dto.data1248};1249}1250return {1251resultId: String(dto.id),1252edits: dto.deltas1253};1254}1255}12561257export class MainThreadDocumentRangeSemanticTokensProvider implements languages.DocumentRangeSemanticTokensProvider {12581259constructor(1260private readonly _proxy: ExtHostLanguageFeaturesShape,1261private readonly _handle: number,1262private readonly _legend: languages.SemanticTokensLegend,1263public readonly onDidChange: Event<void> | undefined,1264) {1265}12661267public getLegend(): languages.SemanticTokensLegend {1268return this._legend;1269}12701271async provideDocumentRangeSemanticTokens(model: ITextModel, range: EditorRange, token: CancellationToken): Promise<languages.SemanticTokens | null> {1272const encodedDto = await this._proxy.$provideDocumentRangeSemanticTokens(this._handle, model.uri, range, token);1273if (!encodedDto) {1274return null;1275}1276if (token.isCancellationRequested) {1277return null;1278}1279const dto = decodeSemanticTokensDto(encodedDto);1280if (dto.type === 'full') {1281return {1282resultId: String(dto.id),1283data: dto.data1284};1285}1286throw new Error(`Unexpected`);1287}1288}12891290class ExtensionBackedInlineCompletionsProvider extends Disposable implements languages.InlineCompletionsProvider<IdentifiableInlineCompletions> {1291public readonly setModelId: ((modelId: string) => Promise<void>) | undefined;1292public readonly _onDidChangeEmitter = new Emitter<languages.IInlineCompletionChangeHint | void>();1293public readonly onDidChangeInlineCompletions: Event<languages.IInlineCompletionChangeHint | void> | undefined;12941295public readonly _onDidChangeModelInfoEmitter = new Emitter<void>();1296public readonly onDidChangeModelInfo: Event<void> | undefined;12971298constructor(1299public readonly handle: number,1300public readonly groupId: string,1301public readonly providerId: languages.ProviderId,1302public readonly yieldsToGroupIds: string[],1303public readonly excludesGroupIds: string[],1304public readonly debounceDelayMs: number | undefined,1305public readonly displayName: string | undefined,1306public modelInfo: languages.IInlineCompletionModelInfo | undefined,1307private readonly _supportsHandleEvents: boolean,1308private readonly _supportsSetModelId: boolean,1309private readonly _supportsOnDidChange: boolean,1310private readonly _supportsOnDidChangeModelInfo: boolean,1311private readonly _selector: IDocumentFilterDto[],1312private readonly _proxy: ExtHostLanguageFeaturesShape,1313@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,1314@IAiEditTelemetryService private readonly _aiEditTelemetryService: IAiEditTelemetryService,1315@IInstantiationService private readonly _instantiationService: IInstantiationService,1316) {1317super();13181319this.setModelId = this._supportsSetModelId ? async (modelId: string) => {1320await this._proxy.$handleInlineCompletionSetCurrentModelId(this.handle, modelId);1321} : undefined;13221323this.onDidChangeInlineCompletions = this._supportsOnDidChange ? this._onDidChangeEmitter.event : undefined;1324this.onDidChangeModelInfo = this._supportsOnDidChangeModelInfo ? this._onDidChangeModelInfoEmitter.event : undefined;13251326this._register(this._languageFeaturesService.inlineCompletionsProvider.register(this._selector, this));1327}13281329public _setModelInfo(newModelInfo: languages.IInlineCompletionModelInfo | undefined) {1330this.modelInfo = newModelInfo;1331if (this._supportsOnDidChangeModelInfo) {1332this._onDidChangeModelInfoEmitter.fire();1333}1334}13351336public _emitDidChange(changeHint: IInlineCompletionChangeHintDto | undefined) {1337if (this._supportsOnDidChange) {1338this._onDidChangeEmitter.fire(changeHint);1339}1340}13411342public async provideInlineCompletions(model: ITextModel, position: EditorPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise<IdentifiableInlineCompletions | undefined> {1343const result = await this._proxy.$provideInlineCompletions(this.handle, model.uri, position, context, token);1344return result;1345}13461347public async handleItemDidShow(completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion, updatedInsertText: string, editDeltaInfo: EditDeltaInfo): Promise<void> {1348if (item.suggestionId === undefined) {1349item.suggestionId = this._aiEditTelemetryService.createSuggestionId({1350applyCodeBlockSuggestionId: undefined,1351feature: 'inlineSuggestion',1352source: this.providerId,1353languageId: completions.languageId,1354editDeltaInfo: editDeltaInfo,1355modeId: undefined,1356modelId: undefined,1357presentation: item.isInlineEdit ? 'nextEditSuggestion' : 'inlineCompletion',1358});1359}13601361if (this._supportsHandleEvents) {1362await this._proxy.$handleInlineCompletionDidShow(this.handle, completions.pid, item.idx, updatedInsertText);1363}1364}13651366public async handlePartialAccept(completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion, acceptedCharacters: number, info: languages.PartialAcceptInfo): Promise<void> {1367if (this._supportsHandleEvents) {1368await this._proxy.$handleInlineCompletionPartialAccept(this.handle, completions.pid, item.idx, acceptedCharacters, info);1369}1370}13711372public async handleEndOfLifetime(completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion, reason: languages.InlineCompletionEndOfLifeReason<IdentifiableInlineCompletion>, lifetimeSummary: languages.LifetimeSummary): Promise<void> {1373function mapReason<T1, T2>(reason: languages.InlineCompletionEndOfLifeReason<T1>, f: (reason: T1) => T2): languages.InlineCompletionEndOfLifeReason<T2> {1374if (reason.kind === languages.InlineCompletionEndOfLifeReasonKind.Ignored) {1375return {1376...reason,1377supersededBy: reason.supersededBy ? f(reason.supersededBy) : undefined,1378};1379}1380return reason;1381}13821383if (this._supportsHandleEvents) {1384await this._proxy.$handleInlineCompletionEndOfLifetime(this.handle, completions.pid, item.idx, mapReason(reason, i => ({ pid: completions.pid, idx: i.idx })));1385}13861387if (reason.kind === languages.InlineCompletionEndOfLifeReasonKind.Accepted) {1388if (item.suggestionId !== undefined) {1389this._aiEditTelemetryService.handleCodeAccepted({1390suggestionId: item.suggestionId,1391feature: 'inlineSuggestion',1392source: this.providerId,1393languageId: completions.languageId,1394editDeltaInfo: EditDeltaInfo.tryCreate(1395lifetimeSummary.lineCountModified,1396lifetimeSummary.lineCountOriginal,1397lifetimeSummary.characterCountModified,1398lifetimeSummary.characterCountOriginal,1399),1400modeId: undefined,1401modelId: undefined,1402presentation: item.isInlineEdit ? 'nextEditSuggestion' : 'inlineCompletion',1403acceptanceMethod: 'accept',1404applyCodeBlockSuggestionId: undefined,1405});1406}1407}14081409const endOfLifeSummary: InlineCompletionEndOfLifeEvent = {1410opportunityId: lifetimeSummary.requestUuid,1411correlationId: lifetimeSummary.correlationId,1412shown: lifetimeSummary.shown,1413shownDuration: lifetimeSummary.shownDuration,1414shownDurationUncollapsed: lifetimeSummary.shownDurationUncollapsed,1415timeUntilShown: lifetimeSummary.timeUntilShown,1416timeUntilProviderRequest: lifetimeSummary.timeUntilProviderRequest,1417timeUntilProviderResponse: lifetimeSummary.timeUntilProviderResponse,1418editorType: lifetimeSummary.editorType,1419viewKind: lifetimeSummary.viewKind,1420preceeded: lifetimeSummary.preceeded,1421requestReason: lifetimeSummary.requestReason,1422typingInterval: lifetimeSummary.typingInterval,1423typingIntervalCharacterCount: lifetimeSummary.typingIntervalCharacterCount,1424languageId: lifetimeSummary.languageId,1425cursorColumnDistance: lifetimeSummary.cursorColumnDistance,1426cursorLineDistance: lifetimeSummary.cursorLineDistance,1427lineCountOriginal: lifetimeSummary.lineCountOriginal,1428lineCountModified: lifetimeSummary.lineCountModified,1429characterCountOriginal: lifetimeSummary.characterCountOriginal,1430characterCountModified: lifetimeSummary.characterCountModified,1431disjointReplacements: lifetimeSummary.disjointReplacements,1432sameShapeReplacements: lifetimeSummary.sameShapeReplacements,1433selectedSuggestionInfo: lifetimeSummary.selectedSuggestionInfo,1434extensionId: this.providerId.extensionId!,1435extensionVersion: this.providerId.extensionVersion!,1436groupId: extractEngineFromCorrelationId(lifetimeSummary.correlationId) ?? this.groupId,1437skuPlan: lifetimeSummary.skuPlan,1438skuType: lifetimeSummary.skuType,1439performanceMarkers: lifetimeSummary.performanceMarkers,1440availableProviders: lifetimeSummary.availableProviders,1441partiallyAccepted: lifetimeSummary.partiallyAccepted,1442partiallyAcceptedCountSinceOriginal: lifetimeSummary.partiallyAcceptedCountSinceOriginal,1443partiallyAcceptedRatioSinceOriginal: lifetimeSummary.partiallyAcceptedRatioSinceOriginal,1444partiallyAcceptedCharactersSinceOriginal: lifetimeSummary.partiallyAcceptedCharactersSinceOriginal,1445superseded: reason.kind === InlineCompletionEndOfLifeReasonKind.Ignored && !!reason.supersededBy,1446reason: reason.kind === InlineCompletionEndOfLifeReasonKind.Accepted ? 'accepted'1447: reason.kind === InlineCompletionEndOfLifeReasonKind.Rejected ? 'rejected'1448: reason.kind === InlineCompletionEndOfLifeReasonKind.Ignored ? 'ignored' : undefined,1449acceptedAlternativeAction: reason.kind === InlineCompletionEndOfLifeReasonKind.Accepted && reason.alternativeAction,1450noSuggestionReason: undefined,1451notShownReason: lifetimeSummary.notShownReason,1452renameCreated: lifetimeSummary.renameCreated,1453renameDuration: lifetimeSummary.renameDuration,1454renameTimedOut: lifetimeSummary.renameTimedOut,1455renameDroppedOtherEdits: lifetimeSummary.renameDroppedOtherEdits,1456renameDroppedRenameEdits: lifetimeSummary.renameDroppedRenameEdits,1457editKind: lifetimeSummary.editKind,1458longDistanceHintVisible: lifetimeSummary.longDistanceHintVisible,1459longDistanceHintDistance: lifetimeSummary.longDistanceHintDistance,1460...forwardToChannelIf(isCopilotLikeExtension(this.providerId.extensionId!)),1461};14621463const dataChannelForwardingTelemetryService = this._instantiationService.createInstance(DataChannelForwardingTelemetryService);1464sendInlineCompletionsEndOfLifeTelemetry(dataChannelForwardingTelemetryService, endOfLifeSummary);1465}14661467public disposeInlineCompletions(completions: IdentifiableInlineCompletions, reason: languages.InlineCompletionsDisposeReason): void {1468this._proxy.$freeInlineCompletionsList(this.handle, completions.pid, reason);1469}14701471public async handleRejection(completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion): Promise<void> {1472if (this._supportsHandleEvents) {1473await this._proxy.$handleInlineCompletionRejection(this.handle, completions.pid, item.idx);1474}1475}14761477override toString() {1478return `InlineCompletionsProvider(${this.providerId.toString()})`;1479}1480}14811482function extractEngineFromCorrelationId(correlationId: string | undefined): string | undefined {1483if (!correlationId) {1484return undefined;1485}1486try {1487const parsed = JSON.parse(correlationId);1488if (typeof parsed === 'object' && parsed !== null && typeof parsed.engine === 'string') {1489return parsed.engine;1490}1491return undefined;1492} catch {1493return undefined;1494}1495}149614971498