Path: blob/main/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts
3296 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, 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 '../../contrib/editTelemetry/browser/telemetry/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';4243@extHostNamedCustomer(MainContext.MainThreadLanguageFeatures)44export class MainThreadLanguageFeatures extends Disposable implements MainThreadLanguageFeaturesShape {4546private readonly _proxy: ExtHostLanguageFeaturesShape;47private readonly _registrations = this._register(new DisposableMap<number>());4849constructor(50extHostContext: IExtHostContext,51@ILanguageService private readonly _languageService: ILanguageService,52@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService,53@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,54@IUriIdentityService private readonly _uriIdentService: IUriIdentityService,55@IInstantiationService private readonly _instantiationService: IInstantiationService,56@IInlineCompletionsUnificationService private readonly _inlineCompletionsUnificationService: IInlineCompletionsUnificationService,57) {58super();5960this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageFeatures);6162if (this._languageService) {63const updateAllWordDefinitions = () => {64const wordDefinitionDtos: ILanguageWordDefinitionDto[] = [];65for (const languageId of _languageService.getRegisteredLanguageIds()) {66const wordDefinition = this._languageConfigurationService.getLanguageConfiguration(languageId).getWordDefinition();67wordDefinitionDtos.push({68languageId: languageId,69regexSource: wordDefinition.source,70regexFlags: wordDefinition.flags71});72}73this._proxy.$setWordDefinitions(wordDefinitionDtos);74};75this._register(this._languageConfigurationService.onDidChange((e) => {76if (!e.languageId) {77updateAllWordDefinitions();78} else {79const wordDefinition = this._languageConfigurationService.getLanguageConfiguration(e.languageId).getWordDefinition();80this._proxy.$setWordDefinitions([{81languageId: e.languageId,82regexSource: wordDefinition.source,83regexFlags: wordDefinition.flags84}]);85}86}));87updateAllWordDefinitions();88}8990if (this._inlineCompletionsUnificationService) {91this._register(this._inlineCompletionsUnificationService.onDidStateChange(() => {92this._proxy.$acceptInlineCompletionsUnificationState(this._inlineCompletionsUnificationService.state);93}));94this._proxy.$acceptInlineCompletionsUnificationState(this._inlineCompletionsUnificationService.state);95}96}9798$unregister(handle: number): void {99this._registrations.deleteAndDispose(handle);100}101102//#region --- revive functions103104private static _reviveLocationDto(data?: ILocationDto): languages.Location;105private static _reviveLocationDto(data?: ILocationDto[]): languages.Location[];106private static _reviveLocationDto(data: ILocationDto | ILocationDto[] | undefined): languages.Location | languages.Location[] | undefined {107if (!data) {108return data;109} else if (Array.isArray(data)) {110data.forEach(l => MainThreadLanguageFeatures._reviveLocationDto(l));111return <languages.Location[]>data;112} else {113data.uri = URI.revive(data.uri);114return <languages.Location>data;115}116}117118private static _reviveLocationLinkDto(data: ILocationLinkDto): languages.LocationLink;119private static _reviveLocationLinkDto(data: ILocationLinkDto[]): languages.LocationLink[];120private static _reviveLocationLinkDto(data: ILocationLinkDto | ILocationLinkDto[]): languages.LocationLink | languages.LocationLink[] {121if (!data) {122return <languages.LocationLink>data;123} else if (Array.isArray(data)) {124data.forEach(l => MainThreadLanguageFeatures._reviveLocationLinkDto(l));125return <languages.LocationLink[]>data;126} else {127data.uri = URI.revive(data.uri);128return <languages.LocationLink>data;129}130}131132private static _reviveWorkspaceSymbolDto(data: IWorkspaceSymbolDto): search.IWorkspaceSymbol;133private static _reviveWorkspaceSymbolDto(data: IWorkspaceSymbolDto[]): search.IWorkspaceSymbol[];134private static _reviveWorkspaceSymbolDto(data: undefined): undefined;135private static _reviveWorkspaceSymbolDto(data: IWorkspaceSymbolDto | IWorkspaceSymbolDto[] | undefined): search.IWorkspaceSymbol | search.IWorkspaceSymbol[] | undefined {136if (!data) {137return <undefined>data;138} else if (Array.isArray(data)) {139data.forEach(MainThreadLanguageFeatures._reviveWorkspaceSymbolDto);140return <search.IWorkspaceSymbol[]>data;141} else {142data.location = MainThreadLanguageFeatures._reviveLocationDto(data.location);143return <search.IWorkspaceSymbol>data;144}145}146147private static _reviveCodeActionDto(data: ReadonlyArray<ICodeActionDto>, uriIdentService: IUriIdentityService): languages.CodeAction[] {148data?.forEach(code => reviveWorkspaceEditDto(code.edit, uriIdentService));149return <languages.CodeAction[]>data;150}151152private static _reviveLinkDTO(data: ILinkDto): languages.ILink {153if (data.url && typeof data.url !== 'string') {154data.url = URI.revive(data.url);155}156return <languages.ILink>data;157}158159private static _reviveCallHierarchyItemDto(data: ICallHierarchyItemDto | undefined): callh.CallHierarchyItem {160if (data) {161data.uri = URI.revive(data.uri);162}163return data as callh.CallHierarchyItem;164}165166private static _reviveTypeHierarchyItemDto(data: ITypeHierarchyItemDto | undefined): typeh.TypeHierarchyItem {167if (data) {168data.uri = URI.revive(data.uri);169}170return data as typeh.TypeHierarchyItem;171}172173//#endregion174175// --- outline176177$registerDocumentSymbolProvider(handle: number, selector: IDocumentFilterDto[], displayName: string): void {178this._registrations.set(handle, this._languageFeaturesService.documentSymbolProvider.register(selector, {179displayName,180provideDocumentSymbols: (model: ITextModel, token: CancellationToken): Promise<languages.DocumentSymbol[] | undefined> => {181return this._proxy.$provideDocumentSymbols(handle, model.uri, token);182}183}));184}185186// --- code lens187188$registerCodeLensSupport(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {189190const provider: languages.CodeLensProvider = {191provideCodeLenses: async (model: ITextModel, token: CancellationToken): Promise<languages.CodeLensList | undefined> => {192const listDto = await this._proxy.$provideCodeLenses(handle, model.uri, token);193if (!listDto) {194return undefined;195}196return {197lenses: listDto.lenses,198dispose: () => listDto.cacheId && this._proxy.$releaseCodeLenses(handle, listDto.cacheId)199};200},201resolveCodeLens: async (model: ITextModel, codeLens: languages.CodeLens, token: CancellationToken): Promise<languages.CodeLens | undefined> => {202const result = await this._proxy.$resolveCodeLens(handle, codeLens, token);203if (!result || token.isCancellationRequested) {204return undefined;205}206207return {208...result,209range: model.validateRange(result.range),210};211}212};213214if (typeof eventHandle === 'number') {215const emitter = new Emitter<languages.CodeLensProvider>();216this._registrations.set(eventHandle, emitter);217provider.onDidChange = emitter.event;218}219220this._registrations.set(handle, this._languageFeaturesService.codeLensProvider.register(selector, provider));221}222223$emitCodeLensEvent(eventHandle: number, event?: any): void {224const obj = this._registrations.get(eventHandle);225if (obj instanceof Emitter) {226obj.fire(event);227}228}229230// --- declaration231232$registerDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void {233this._registrations.set(handle, this._languageFeaturesService.definitionProvider.register(selector, {234provideDefinition: (model, position, token): Promise<languages.LocationLink[]> => {235return this._proxy.$provideDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);236}237}));238}239240$registerDeclarationSupport(handle: number, selector: IDocumentFilterDto[]): void {241this._registrations.set(handle, this._languageFeaturesService.declarationProvider.register(selector, {242provideDeclaration: (model, position, token) => {243return this._proxy.$provideDeclaration(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);244}245}));246}247248$registerImplementationSupport(handle: number, selector: IDocumentFilterDto[]): void {249this._registrations.set(handle, this._languageFeaturesService.implementationProvider.register(selector, {250provideImplementation: (model, position, token): Promise<languages.LocationLink[]> => {251return this._proxy.$provideImplementation(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);252}253}));254}255256$registerTypeDefinitionSupport(handle: number, selector: IDocumentFilterDto[]): void {257this._registrations.set(handle, this._languageFeaturesService.typeDefinitionProvider.register(selector, {258provideTypeDefinition: (model, position, token): Promise<languages.LocationLink[]> => {259return this._proxy.$provideTypeDefinition(handle, model.uri, position, token).then(MainThreadLanguageFeatures._reviveLocationLinkDto);260}261}));262}263264// --- extra info265266$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void {267/*268const hoverFinalizationRegistry = new FinalizationRegistry((hoverId: number) => {269this._proxy.$releaseHover(handle, hoverId);270});271*/272this._registrations.set(handle, this._languageFeaturesService.hoverProvider.register(selector, {273provideHover: async (model: ITextModel, position: EditorPosition, token: CancellationToken, context?: languages.HoverContext<HoverWithId>): Promise<HoverWithId | undefined> => {274const serializedContext: languages.HoverContext<{ id: number }> = {275verbosityRequest: context?.verbosityRequest ? {276verbosityDelta: context.verbosityRequest.verbosityDelta,277previousHover: { id: context.verbosityRequest.previousHover.id }278} : undefined,279};280const hover = await this._proxy.$provideHover(handle, model.uri, position, serializedContext, token);281// hoverFinalizationRegistry.register(hover, hover.id);282return hover;283}284}));285}286287// --- debug hover288289$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void {290this._registrations.set(handle, this._languageFeaturesService.evaluatableExpressionProvider.register(selector, {291provideEvaluatableExpression: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<languages.EvaluatableExpression | undefined> => {292return this._proxy.$provideEvaluatableExpression(handle, model.uri, position, token);293}294}));295}296297// --- inline values298299$registerInlineValuesProvider(handle: number, selector: IDocumentFilterDto[], eventHandle: number | undefined): void {300const provider: languages.InlineValuesProvider = {301provideInlineValues: (model: ITextModel, viewPort: EditorRange, context: languages.InlineValueContext, token: CancellationToken): Promise<languages.InlineValue[] | undefined> => {302return this._proxy.$provideInlineValues(handle, model.uri, viewPort, context, token);303}304};305306if (typeof eventHandle === 'number') {307const emitter = new Emitter<void>();308this._registrations.set(eventHandle, emitter);309provider.onDidChangeInlineValues = emitter.event;310}311312this._registrations.set(handle, this._languageFeaturesService.inlineValuesProvider.register(selector, provider));313}314315$emitInlineValuesEvent(eventHandle: number, event?: any): void {316const obj = this._registrations.get(eventHandle);317if (obj instanceof Emitter) {318obj.fire(event);319}320}321322// --- occurrences323324$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void {325this._registrations.set(handle, this._languageFeaturesService.documentHighlightProvider.register(selector, {326provideDocumentHighlights: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<languages.DocumentHighlight[] | undefined> => {327return this._proxy.$provideDocumentHighlights(handle, model.uri, position, token);328}329}));330}331332$registerMultiDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void {333this._registrations.set(handle, this._languageFeaturesService.multiDocumentHighlightProvider.register(selector, {334selector: selector,335provideMultiDocumentHighlights: (model: ITextModel, position: EditorPosition, otherModels: ITextModel[], token: CancellationToken): Promise<Map<URI, languages.DocumentHighlight[]> | undefined> => {336return this._proxy.$provideMultiDocumentHighlights(handle, model.uri, position, otherModels.map(model => model.uri), token).then(dto => {337// dto should be non-null + non-undefined338// dto length of 0 is valid, just no highlights, pass this through.339if (dto === undefined || dto === null) {340return undefined;341}342const result = new ResourceMap<languages.DocumentHighlight[]>();343dto?.forEach(value => {344// check if the URI exists already, if so, combine the highlights, otherwise create a new entry345const uri = URI.revive(value.uri);346if (result.has(uri)) {347result.get(uri)!.push(...value.highlights);348} else {349result.set(uri, value.highlights);350}351});352return result;353});354}355}));356}357358// --- linked editing359360$registerLinkedEditingRangeProvider(handle: number, selector: IDocumentFilterDto[]): void {361this._registrations.set(handle, this._languageFeaturesService.linkedEditingRangeProvider.register(selector, {362provideLinkedEditingRanges: async (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<languages.LinkedEditingRanges | undefined> => {363const res = await this._proxy.$provideLinkedEditingRanges(handle, model.uri, position, token);364if (res) {365return {366ranges: res.ranges,367wordPattern: res.wordPattern ? MainThreadLanguageFeatures._reviveRegExp(res.wordPattern) : undefined368};369}370return undefined;371}372}));373}374375// --- references376377$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void {378this._registrations.set(handle, this._languageFeaturesService.referenceProvider.register(selector, {379provideReferences: (model: ITextModel, position: EditorPosition, context: languages.ReferenceContext, token: CancellationToken): Promise<languages.Location[]> => {380return this._proxy.$provideReferences(handle, model.uri, position, context, token).then(MainThreadLanguageFeatures._reviveLocationDto);381}382}));383}384385// --- code actions386387$registerCodeActionSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string, extensionId: string, supportsResolve: boolean): void {388const provider: languages.CodeActionProvider = {389provideCodeActions: async (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: languages.CodeActionContext, token: CancellationToken): Promise<languages.CodeActionList | undefined> => {390const listDto = await this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token);391if (!listDto) {392return undefined;393}394return {395actions: MainThreadLanguageFeatures._reviveCodeActionDto(listDto.actions, this._uriIdentService),396dispose: () => {397if (typeof listDto.cacheId === 'number') {398this._proxy.$releaseCodeActions(handle, listDto.cacheId);399}400}401};402},403providedCodeActionKinds: metadata.providedKinds,404documentation: metadata.documentation,405displayName,406extensionId,407};408409if (supportsResolve) {410provider.resolveCodeAction = async (codeAction: languages.CodeAction, token: CancellationToken): Promise<languages.CodeAction> => {411const resolved = await this._proxy.$resolveCodeAction(handle, (<ICodeActionDto>codeAction).cacheId!, token);412if (resolved.edit) {413codeAction.edit = reviveWorkspaceEditDto(resolved.edit, this._uriIdentService);414}415416if (resolved.command) {417codeAction.command = resolved.command;418}419420return codeAction;421};422}423424this._registrations.set(handle, this._languageFeaturesService.codeActionProvider.register(selector, provider));425}426427// --- copy paste action provider428429private readonly _pasteEditProviders = new Map<number, MainThreadPasteEditProvider>();430431$registerPasteEditProvider(handle: number, selector: IDocumentFilterDto[], metadata: IPasteEditProviderMetadataDto): void {432const provider = new MainThreadPasteEditProvider(handle, this._proxy, metadata, this._uriIdentService);433this._pasteEditProviders.set(handle, provider);434this._registrations.set(handle, combinedDisposable(435this._languageFeaturesService.documentPasteEditProvider.register(selector, provider),436toDisposable(() => this._pasteEditProviders.delete(handle)),437));438}439440$resolvePasteFileData(handle: number, requestId: number, dataId: string): Promise<VSBuffer> {441const provider = this._pasteEditProviders.get(handle);442if (!provider) {443throw new Error('Could not find provider');444}445return provider.resolveFileData(requestId, dataId);446}447448// --- formatting449450$registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void {451this._registrations.set(handle, this._languageFeaturesService.documentFormattingEditProvider.register(selector, {452extensionId,453displayName,454provideDocumentFormattingEdits: (model: ITextModel, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> => {455return this._proxy.$provideDocumentFormattingEdits(handle, model.uri, options, token);456}457}));458}459460$registerRangeFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string, supportsRanges: boolean): void {461this._registrations.set(handle, this._languageFeaturesService.documentRangeFormattingEditProvider.register(selector, {462extensionId,463displayName,464provideDocumentRangeFormattingEdits: (model: ITextModel, range: EditorRange, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> => {465return this._proxy.$provideDocumentRangeFormattingEdits(handle, model.uri, range, options, token);466},467provideDocumentRangesFormattingEdits: !supportsRanges468? undefined469: (model, ranges, options, token) => {470return this._proxy.$provideDocumentRangesFormattingEdits(handle, model.uri, ranges, options, token);471},472}));473}474475$registerOnTypeFormattingSupport(handle: number, selector: IDocumentFilterDto[], autoFormatTriggerCharacters: string[], extensionId: ExtensionIdentifier): void {476this._registrations.set(handle, this._languageFeaturesService.onTypeFormattingEditProvider.register(selector, {477extensionId,478autoFormatTriggerCharacters,479provideOnTypeFormattingEdits: (model: ITextModel, position: EditorPosition, ch: string, options: languages.FormattingOptions, token: CancellationToken): Promise<languages.TextEdit[] | undefined> => {480return this._proxy.$provideOnTypeFormattingEdits(handle, model.uri, position, ch, options, token);481}482}));483}484485// --- navigate type486487$registerNavigateTypeSupport(handle: number, supportsResolve: boolean): void {488let lastResultId: number | undefined;489490const provider: search.IWorkspaceSymbolProvider = {491provideWorkspaceSymbols: async (search: string, token: CancellationToken): Promise<search.IWorkspaceSymbol[]> => {492const result = await this._proxy.$provideWorkspaceSymbols(handle, search, token);493if (lastResultId !== undefined) {494this._proxy.$releaseWorkspaceSymbols(handle, lastResultId);495}496lastResultId = result.cacheId;497return MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(result.symbols);498}499};500if (supportsResolve) {501provider.resolveWorkspaceSymbol = async (item: search.IWorkspaceSymbol, token: CancellationToken): Promise<search.IWorkspaceSymbol | undefined> => {502const resolvedItem = await this._proxy.$resolveWorkspaceSymbol(handle, item, token);503return resolvedItem && MainThreadLanguageFeatures._reviveWorkspaceSymbolDto(resolvedItem);504};505}506this._registrations.set(handle, search.WorkspaceSymbolProviderRegistry.register(provider));507}508509// --- rename510511$registerRenameSupport(handle: number, selector: IDocumentFilterDto[], supportResolveLocation: boolean): void {512this._registrations.set(handle, this._languageFeaturesService.renameProvider.register(selector, {513provideRenameEdits: (model: ITextModel, position: EditorPosition, newName: string, token: CancellationToken) => {514return this._proxy.$provideRenameEdits(handle, model.uri, position, newName, token).then(data => reviveWorkspaceEditDto(data, this._uriIdentService));515},516resolveRenameLocation: supportResolveLocation517? (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<languages.RenameLocation | undefined> => this._proxy.$resolveRenameLocation(handle, model.uri, position, token)518: undefined519}));520}521522$registerNewSymbolNamesProvider(handle: number, selector: IDocumentFilterDto[]): void {523this._registrations.set(handle, this._languageFeaturesService.newSymbolNamesProvider.register(selector, {524supportsAutomaticNewSymbolNamesTriggerKind: this._proxy.$supportsAutomaticNewSymbolNamesTriggerKind(handle),525provideNewSymbolNames: (model: ITextModel, range: IRange, triggerKind: languages.NewSymbolNameTriggerKind, token: CancellationToken): Promise<languages.NewSymbolName[] | undefined> => {526return this._proxy.$provideNewSymbolNames(handle, model.uri, range, triggerKind, token);527}528} satisfies languages.NewSymbolNamesProvider));529}530531// --- semantic tokens532533$registerDocumentSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: languages.SemanticTokensLegend, eventHandle: number | undefined): void {534let event: Event<void> | undefined = undefined;535if (typeof eventHandle === 'number') {536const emitter = new Emitter<void>();537this._registrations.set(eventHandle, emitter);538event = emitter.event;539}540this._registrations.set(handle, this._languageFeaturesService.documentSemanticTokensProvider.register(selector, new MainThreadDocumentSemanticTokensProvider(this._proxy, handle, legend, event)));541}542543$emitDocumentSemanticTokensEvent(eventHandle: number): void {544const obj = this._registrations.get(eventHandle);545if (obj instanceof Emitter) {546obj.fire(undefined);547}548}549550$registerDocumentRangeSemanticTokensProvider(handle: number, selector: IDocumentFilterDto[], legend: languages.SemanticTokensLegend): void {551this._registrations.set(handle, this._languageFeaturesService.documentRangeSemanticTokensProvider.register(selector, new MainThreadDocumentRangeSemanticTokensProvider(this._proxy, handle, legend)));552}553554// --- suggest555556private static _inflateSuggestDto(defaultRange: IRange | { insert: IRange; replace: IRange }, data: ISuggestDataDto, extensionId: ExtensionIdentifier): languages.CompletionItem {557558const label = data[ISuggestDataDtoField.label];559const commandId = data[ISuggestDataDtoField.commandId];560const commandIdent = data[ISuggestDataDtoField.commandIdent];561const commitChars = data[ISuggestDataDtoField.commitCharacters];562563type IdentCommand = languages.Command & { $ident: string | undefined };564565let command: IdentCommand | undefined;566if (commandId) {567command = {568$ident: commandIdent,569id: commandId,570title: '',571arguments: commandIdent ? [commandIdent] : data[ISuggestDataDtoField.commandArguments], // Automatically fill in ident as first argument572};573}574575return {576label,577extensionId,578kind: data[ISuggestDataDtoField.kind] ?? languages.CompletionItemKind.Property,579tags: data[ISuggestDataDtoField.kindModifier],580detail: data[ISuggestDataDtoField.detail],581documentation: data[ISuggestDataDtoField.documentation],582sortText: data[ISuggestDataDtoField.sortText],583filterText: data[ISuggestDataDtoField.filterText],584preselect: data[ISuggestDataDtoField.preselect],585insertText: data[ISuggestDataDtoField.insertText] ?? (typeof label === 'string' ? label : label.label),586range: data[ISuggestDataDtoField.range] ?? defaultRange,587insertTextRules: data[ISuggestDataDtoField.insertTextRules],588commitCharacters: commitChars ? Array.from(commitChars) : undefined,589additionalTextEdits: data[ISuggestDataDtoField.additionalTextEdits],590command,591// not-standard592_id: data.x,593};594}595596$registerCompletionsProvider(handle: number, selector: IDocumentFilterDto[], triggerCharacters: string[], supportsResolveDetails: boolean, extensionId: ExtensionIdentifier): void {597const provider: languages.CompletionItemProvider = {598triggerCharacters,599_debugDisplayName: `${extensionId.value}(${triggerCharacters.join('')})`,600provideCompletionItems: async (model: ITextModel, position: EditorPosition, context: languages.CompletionContext, token: CancellationToken): Promise<languages.CompletionList | undefined> => {601const result = await this._proxy.$provideCompletionItems(handle, model.uri, position, context, token);602if (!result) {603return result;604}605return {606suggestions: result[ISuggestResultDtoField.completions].map(d => MainThreadLanguageFeatures._inflateSuggestDto(result[ISuggestResultDtoField.defaultRanges], d, extensionId)),607incomplete: result[ISuggestResultDtoField.isIncomplete] || false,608duration: result[ISuggestResultDtoField.duration],609dispose: () => {610if (typeof result.x === 'number') {611this._proxy.$releaseCompletionItems(handle, result.x);612}613}614};615}616};617if (supportsResolveDetails) {618provider.resolveCompletionItem = (suggestion, token) => {619return this._proxy.$resolveCompletionItem(handle, suggestion._id!, token).then(result => {620if (!result) {621return suggestion;622}623624const newSuggestion = MainThreadLanguageFeatures._inflateSuggestDto(suggestion.range, result, extensionId);625return mixin(suggestion, newSuggestion, true);626});627};628}629this._registrations.set(handle, this._languageFeaturesService.completionProvider.register(selector, provider));630}631632$registerInlineCompletionsSupport(handle: number, selector: IDocumentFilterDto[], supportsHandleEvents: boolean, extensionId: string, extensionVersion: string, groupId: string | undefined, yieldsToExtensionIds: string[], displayName: string | undefined, debounceDelayMs: number | undefined, excludesExtensionIds: string[], eventHandle: number | undefined): void {633const provider: languages.InlineCompletionsProvider<IdentifiableInlineCompletions> = {634provideInlineCompletions: async (model: ITextModel, position: EditorPosition, context: languages.InlineCompletionContext, token: CancellationToken): Promise<IdentifiableInlineCompletions | undefined> => {635const result = await this._proxy.$provideInlineCompletions(handle, model.uri, position, context, token);636return result;637},638handleItemDidShow: async (completions: IdentifiableInlineCompletions, item: IdentifiableInlineCompletion, updatedInsertText: string): Promise<void> => {639this._instantiationService.invokeFunction(accessor => {640const aiEditTelemetryService = accessor.getIfExists(IAiEditTelemetryService);641item.suggestionId = aiEditTelemetryService?.createSuggestionId({642applyCodeBlockSuggestionId: undefined,643editDeltaInfo: new EditDeltaInfo(1, 1, -1, -1), // TODO@hediet, fix this approximation.644feature: 'inlineSuggestion',645languageId: completions.languageId,646modeId: undefined,647modelId: undefined,648presentation: 'inlineSuggestion',649});650});651652if (supportsHandleEvents) {653await this._proxy.$handleInlineCompletionDidShow(handle, completions.pid, item.idx, updatedInsertText);654}655},656handlePartialAccept: async (completions, item, acceptedCharacters, info: languages.PartialAcceptInfo): Promise<void> => {657if (supportsHandleEvents) {658await this._proxy.$handleInlineCompletionPartialAccept(handle, completions.pid, item.idx, acceptedCharacters, info);659}660},661handleEndOfLifetime: async (completions, item, reason, lifetimeSummary) => {662663function mapReason<T1, T2>(reason: languages.InlineCompletionEndOfLifeReason<T1>, f: (reason: T1) => T2): languages.InlineCompletionEndOfLifeReason<T2> {664if (reason.kind === languages.InlineCompletionEndOfLifeReasonKind.Ignored) {665return {666...reason,667supersededBy: reason.supersededBy ? f(reason.supersededBy) : undefined,668};669}670return reason;671}672673if (supportsHandleEvents) {674await this._proxy.$handleInlineCompletionEndOfLifetime(handle, completions.pid, item.idx, mapReason(reason, i => ({ pid: completions.pid, idx: i.idx })));675}676677if (reason.kind === languages.InlineCompletionEndOfLifeReasonKind.Accepted) {678this._instantiationService.invokeFunction(accessor => {679const aiEditTelemetryService = accessor.getIfExists(IAiEditTelemetryService);680aiEditTelemetryService?.handleCodeAccepted({681suggestionId: item.suggestionId,682editDeltaInfo: EditDeltaInfo.tryCreate(683lifetimeSummary.lineCountModified,684lifetimeSummary.lineCountOriginal,685lifetimeSummary.characterCountModified,686lifetimeSummary.characterCountOriginal,687),688feature: 'inlineSuggestion',689languageId: completions.languageId,690modeId: undefined,691modelId: undefined,692presentation: 'inlineSuggestion',693acceptanceMethod: 'accept',694applyCodeBlockSuggestionId: undefined,695});696});697}698699const endOfLifeSummary: InlineCompletionEndOfLifeEvent = {700id: lifetimeSummary.requestUuid,701opportunityId: lifetimeSummary.requestUuid,702correlationId: lifetimeSummary.correlationId,703shown: lifetimeSummary.shown,704shownDuration: lifetimeSummary.shownDuration,705shownDurationUncollapsed: lifetimeSummary.shownDurationUncollapsed,706timeUntilShown: lifetimeSummary.timeUntilShown,707timeUntilProviderRequest: lifetimeSummary.timeUntilProviderRequest,708timeUntilProviderResponse: lifetimeSummary.timeUntilProviderResponse,709editorType: lifetimeSummary.editorType,710viewKind: lifetimeSummary.viewKind,711preceeded: lifetimeSummary.preceeded,712requestReason: lifetimeSummary.requestReason,713error: lifetimeSummary.error,714typingInterval: lifetimeSummary.typingInterval,715typingIntervalCharacterCount: lifetimeSummary.typingIntervalCharacterCount,716languageId: lifetimeSummary.languageId,717cursorColumnDistance: lifetimeSummary.cursorColumnDistance,718cursorLineDistance: lifetimeSummary.cursorLineDistance,719lineCountOriginal: lifetimeSummary.lineCountOriginal,720lineCountModified: lifetimeSummary.lineCountModified,721characterCountOriginal: lifetimeSummary.characterCountOriginal,722characterCountModified: lifetimeSummary.characterCountModified,723disjointReplacements: lifetimeSummary.disjointReplacements,724sameShapeReplacements: lifetimeSummary.sameShapeReplacements,725extensionId,726extensionVersion,727groupId,728partiallyAccepted: lifetimeSummary.partiallyAccepted,729partiallyAcceptedCountSinceOriginal: lifetimeSummary.partiallyAcceptedCountSinceOriginal,730partiallyAcceptedRatioSinceOriginal: lifetimeSummary.partiallyAcceptedRatioSinceOriginal,731partiallyAcceptedCharactersSinceOriginal: lifetimeSummary.partiallyAcceptedCharactersSinceOriginal,732superseded: reason.kind === InlineCompletionEndOfLifeReasonKind.Ignored && !!reason.supersededBy,733reason: reason.kind === InlineCompletionEndOfLifeReasonKind.Accepted ? 'accepted'734: reason.kind === InlineCompletionEndOfLifeReasonKind.Rejected ? 'rejected'735: 'ignored',736...forwardToChannelIf(isCopilotLikeExtension(extensionId)),737};738739const telemetryService = this._instantiationService.createInstance(DataChannelForwardingTelemetryService);740telemetryService.publicLog2<InlineCompletionEndOfLifeEvent, InlineCompletionsEndOfLifeClassification>('inlineCompletion.endOfLife', endOfLifeSummary);741},742disposeInlineCompletions: (completions: IdentifiableInlineCompletions, reason: languages.InlineCompletionsDisposeReason): void => {743this._proxy.$freeInlineCompletionsList(handle, completions.pid, reason);744},745handleRejection: async (completions, item): Promise<void> => {746if (supportsHandleEvents) {747await this._proxy.$handleInlineCompletionRejection(handle, completions.pid, item.idx);748}749},750groupId: groupId ?? extensionId,751providerId: new languages.ProviderId(extensionId, extensionVersion, groupId),752yieldsToGroupIds: yieldsToExtensionIds,753excludesGroupIds: excludesExtensionIds,754debounceDelayMs,755displayName,756toString() {757return `InlineCompletionsProvider(${extensionId})`;758},759};760if (typeof eventHandle === 'number') {761const emitter = new Emitter<void>();762this._registrations.set(eventHandle, emitter);763provider.onDidChangeInlineCompletions = emitter.event;764}765this._registrations.set(handle, this._languageFeaturesService.inlineCompletionsProvider.register(selector, provider));766}767768$emitInlineCompletionsChange(handle: number): void {769const obj = this._registrations.get(handle);770if (obj instanceof Emitter) {771obj.fire(undefined);772}773}774775// --- parameter hints776777$registerSignatureHelpProvider(handle: number, selector: IDocumentFilterDto[], metadata: ISignatureHelpProviderMetadataDto): void {778this._registrations.set(handle, this._languageFeaturesService.signatureHelpProvider.register(selector, {779780signatureHelpTriggerCharacters: metadata.triggerCharacters,781signatureHelpRetriggerCharacters: metadata.retriggerCharacters,782783provideSignatureHelp: async (model: ITextModel, position: EditorPosition, token: CancellationToken, context: languages.SignatureHelpContext): Promise<languages.SignatureHelpResult | undefined> => {784const result = await this._proxy.$provideSignatureHelp(handle, model.uri, position, context, token);785if (!result) {786return undefined;787}788return {789value: result,790dispose: () => {791this._proxy.$releaseSignatureHelp(handle, result.id);792}793};794}795}));796}797798// --- inline hints799800$registerInlayHintsProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean, eventHandle: number | undefined, displayName: string | undefined): void {801const provider: languages.InlayHintsProvider = {802displayName,803provideInlayHints: async (model: ITextModel, range: EditorRange, token: CancellationToken): Promise<languages.InlayHintList | undefined> => {804const result = await this._proxy.$provideInlayHints(handle, model.uri, range, token);805if (!result) {806return;807}808return {809hints: revive(result.hints),810dispose: () => {811if (result.cacheId) {812this._proxy.$releaseInlayHints(handle, result.cacheId);813}814}815};816}817};818if (supportsResolve) {819provider.resolveInlayHint = async (hint, token) => {820const dto: IInlayHintDto = hint;821if (!dto.cacheId) {822return hint;823}824const result = await this._proxy.$resolveInlayHint(handle, dto.cacheId, token);825if (token.isCancellationRequested) {826throw new CancellationError();827}828if (!result) {829return hint;830}831return {832...hint,833tooltip: result.tooltip,834label: revive<string | languages.InlayHintLabelPart[]>(result.label),835textEdits: result.textEdits836};837};838}839if (typeof eventHandle === 'number') {840const emitter = new Emitter<void>();841this._registrations.set(eventHandle, emitter);842provider.onDidChangeInlayHints = emitter.event;843}844845this._registrations.set(handle, this._languageFeaturesService.inlayHintsProvider.register(selector, provider));846}847848$emitInlayHintsEvent(eventHandle: number): void {849const obj = this._registrations.get(eventHandle);850if (obj instanceof Emitter) {851obj.fire(undefined);852}853}854855// --- links856857$registerDocumentLinkProvider(handle: number, selector: IDocumentFilterDto[], supportsResolve: boolean): void {858const provider: languages.LinkProvider = {859provideLinks: (model, token) => {860return this._proxy.$provideDocumentLinks(handle, model.uri, token).then(dto => {861if (!dto) {862return undefined;863}864return {865links: dto.links.map(MainThreadLanguageFeatures._reviveLinkDTO),866dispose: () => {867if (typeof dto.cacheId === 'number') {868this._proxy.$releaseDocumentLinks(handle, dto.cacheId);869}870}871};872});873}874};875if (supportsResolve) {876provider.resolveLink = (link, token) => {877const dto: ILinkDto = link;878if (!dto.cacheId) {879return link;880}881return this._proxy.$resolveDocumentLink(handle, dto.cacheId, token).then(obj => {882return obj && MainThreadLanguageFeatures._reviveLinkDTO(obj);883});884};885}886this._registrations.set(handle, this._languageFeaturesService.linkProvider.register(selector, provider));887}888889// --- colors890891$registerDocumentColorProvider(handle: number, selector: IDocumentFilterDto[]): void {892const proxy = this._proxy;893this._registrations.set(handle, this._languageFeaturesService.colorProvider.register(selector, {894provideDocumentColors: (model, token) => {895return proxy.$provideDocumentColors(handle, model.uri, token)896.then(documentColors => {897return documentColors.map(documentColor => {898const [red, green, blue, alpha] = documentColor.color;899const color = {900red: red,901green: green,902blue: blue,903alpha904};905906return {907color,908range: documentColor.range909};910});911});912},913914provideColorPresentations: (model, colorInfo, token) => {915return proxy.$provideColorPresentations(handle, model.uri, {916color: [colorInfo.color.red, colorInfo.color.green, colorInfo.color.blue, colorInfo.color.alpha],917range: colorInfo.range918}, token);919}920}));921}922923// --- folding924925$registerFoldingRangeProvider(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, eventHandle: number | undefined): void {926const provider: languages.FoldingRangeProvider = {927id: extensionId.value,928provideFoldingRanges: (model, context, token) => {929return this._proxy.$provideFoldingRanges(handle, model.uri, context, token);930}931};932933if (typeof eventHandle === 'number') {934const emitter = new Emitter<languages.FoldingRangeProvider>();935this._registrations.set(eventHandle, emitter);936provider.onDidChange = emitter.event;937}938939this._registrations.set(handle, this._languageFeaturesService.foldingRangeProvider.register(selector, provider));940}941942$emitFoldingRangeEvent(eventHandle: number, event?: any): void {943const obj = this._registrations.get(eventHandle);944if (obj instanceof Emitter) {945obj.fire(event);946}947}948949// -- smart select950951$registerSelectionRangeProvider(handle: number, selector: IDocumentFilterDto[]): void {952this._registrations.set(handle, this._languageFeaturesService.selectionRangeProvider.register(selector, {953provideSelectionRanges: (model, positions, token) => {954return this._proxy.$provideSelectionRanges(handle, model.uri, positions, token);955}956}));957}958959// --- call hierarchy960961$registerCallHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {962this._registrations.set(handle, callh.CallHierarchyProviderRegistry.register(selector, {963964prepareCallHierarchy: async (document, position, token) => {965const items = await this._proxy.$prepareCallHierarchy(handle, document.uri, position, token);966if (!items || items.length === 0) {967return undefined;968}969return {970dispose: () => {971for (const item of items) {972this._proxy.$releaseCallHierarchy(handle, item._sessionId);973}974},975roots: items.map(MainThreadLanguageFeatures._reviveCallHierarchyItemDto)976};977},978979provideOutgoingCalls: async (item, token) => {980const outgoing = await this._proxy.$provideCallHierarchyOutgoingCalls(handle, item._sessionId, item._itemId, token);981if (!outgoing) {982return outgoing;983}984outgoing.forEach(value => {985value.to = MainThreadLanguageFeatures._reviveCallHierarchyItemDto(value.to);986});987return <any>outgoing;988},989provideIncomingCalls: async (item, token) => {990const incoming = await this._proxy.$provideCallHierarchyIncomingCalls(handle, item._sessionId, item._itemId, token);991if (!incoming) {992return incoming;993}994incoming.forEach(value => {995value.from = MainThreadLanguageFeatures._reviveCallHierarchyItemDto(value.from);996});997return <any>incoming;998}999}));1000}10011002// --- configuration10031004private static _reviveRegExp(regExp: IRegExpDto): RegExp {1005return new RegExp(regExp.pattern, regExp.flags);1006}10071008private static _reviveIndentationRule(indentationRule: IIndentationRuleDto): IndentationRule {1009return {1010decreaseIndentPattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.decreaseIndentPattern),1011increaseIndentPattern: MainThreadLanguageFeatures._reviveRegExp(indentationRule.increaseIndentPattern),1012indentNextLinePattern: indentationRule.indentNextLinePattern ? MainThreadLanguageFeatures._reviveRegExp(indentationRule.indentNextLinePattern) : undefined,1013unIndentedLinePattern: indentationRule.unIndentedLinePattern ? MainThreadLanguageFeatures._reviveRegExp(indentationRule.unIndentedLinePattern) : undefined,1014};1015}10161017private static _reviveOnEnterRule(onEnterRule: IOnEnterRuleDto): OnEnterRule {1018return {1019beforeText: MainThreadLanguageFeatures._reviveRegExp(onEnterRule.beforeText),1020afterText: onEnterRule.afterText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.afterText) : undefined,1021previousLineText: onEnterRule.previousLineText ? MainThreadLanguageFeatures._reviveRegExp(onEnterRule.previousLineText) : undefined,1022action: onEnterRule.action1023};1024}10251026private static _reviveOnEnterRules(onEnterRules: IOnEnterRuleDto[]): OnEnterRule[] {1027return onEnterRules.map(MainThreadLanguageFeatures._reviveOnEnterRule);1028}10291030$setLanguageConfiguration(handle: number, languageId: string, _configuration: ILanguageConfigurationDto): void {10311032const configuration: LanguageConfiguration = {1033comments: _configuration.comments,1034brackets: _configuration.brackets,1035wordPattern: _configuration.wordPattern ? MainThreadLanguageFeatures._reviveRegExp(_configuration.wordPattern) : undefined,1036indentationRules: _configuration.indentationRules ? MainThreadLanguageFeatures._reviveIndentationRule(_configuration.indentationRules) : undefined,1037onEnterRules: _configuration.onEnterRules ? MainThreadLanguageFeatures._reviveOnEnterRules(_configuration.onEnterRules) : undefined,10381039autoClosingPairs: undefined,1040surroundingPairs: undefined,1041__electricCharacterSupport: undefined1042};10431044if (_configuration.autoClosingPairs) {1045configuration.autoClosingPairs = _configuration.autoClosingPairs;1046} else if (_configuration.__characterPairSupport) {1047// backwards compatibility1048configuration.autoClosingPairs = _configuration.__characterPairSupport.autoClosingPairs;1049}10501051if (_configuration.__electricCharacterSupport && _configuration.__electricCharacterSupport.docComment) {1052configuration.__electricCharacterSupport = {1053docComment: {1054open: _configuration.__electricCharacterSupport.docComment.open,1055close: _configuration.__electricCharacterSupport.docComment.close1056}1057};1058}10591060if (this._languageService.isRegisteredLanguageId(languageId)) {1061this._registrations.set(handle, this._languageConfigurationService.register(languageId, configuration, 100));1062}1063}10641065// --- type hierarchy10661067$registerTypeHierarchyProvider(handle: number, selector: IDocumentFilterDto[]): void {1068this._registrations.set(handle, typeh.TypeHierarchyProviderRegistry.register(selector, {10691070prepareTypeHierarchy: async (document, position, token) => {1071const items = await this._proxy.$prepareTypeHierarchy(handle, document.uri, position, token);1072if (!items) {1073return undefined;1074}1075return {1076dispose: () => {1077for (const item of items) {1078this._proxy.$releaseTypeHierarchy(handle, item._sessionId);1079}1080},1081roots: items.map(MainThreadLanguageFeatures._reviveTypeHierarchyItemDto)1082};1083},10841085provideSupertypes: async (item, token) => {1086const supertypes = await this._proxy.$provideTypeHierarchySupertypes(handle, item._sessionId, item._itemId, token);1087if (!supertypes) {1088return supertypes;1089}1090return supertypes.map(MainThreadLanguageFeatures._reviveTypeHierarchyItemDto);1091},1092provideSubtypes: async (item, token) => {1093const subtypes = await this._proxy.$provideTypeHierarchySubtypes(handle, item._sessionId, item._itemId, token);1094if (!subtypes) {1095return subtypes;1096}1097return subtypes.map(MainThreadLanguageFeatures._reviveTypeHierarchyItemDto);1098}1099}));1100}110111021103// --- document drop Edits11041105private readonly _documentOnDropEditProviders = new Map<number, MainThreadDocumentOnDropEditProvider>();11061107$registerDocumentOnDropEditProvider(handle: number, selector: IDocumentFilterDto[], metadata: IDocumentDropEditProviderMetadata): void {1108const provider = new MainThreadDocumentOnDropEditProvider(handle, this._proxy, metadata, this._uriIdentService);1109this._documentOnDropEditProviders.set(handle, provider);1110this._registrations.set(handle, combinedDisposable(1111this._languageFeaturesService.documentDropEditProvider.register(selector, provider),1112toDisposable(() => this._documentOnDropEditProviders.delete(handle)),1113));1114}11151116async $resolveDocumentOnDropFileData(handle: number, requestId: number, dataId: string): Promise<VSBuffer> {1117const provider = this._documentOnDropEditProviders.get(handle);1118if (!provider) {1119throw new Error('Could not find provider');1120}1121return provider.resolveDocumentOnDropFileData(requestId, dataId);1122}1123}11241125class MainThreadPasteEditProvider implements languages.DocumentPasteEditProvider {11261127private readonly dataTransfers = new DataTransferFileCache();11281129public readonly copyMimeTypes: readonly string[];1130public readonly pasteMimeTypes: readonly string[];1131public readonly providedPasteEditKinds: readonly HierarchicalKind[];11321133readonly prepareDocumentPaste?: languages.DocumentPasteEditProvider['prepareDocumentPaste'];1134readonly provideDocumentPasteEdits?: languages.DocumentPasteEditProvider['provideDocumentPasteEdits'];1135readonly resolveDocumentPasteEdit?: languages.DocumentPasteEditProvider['resolveDocumentPasteEdit'];11361137constructor(1138private readonly _handle: number,1139private readonly _proxy: ExtHostLanguageFeaturesShape,1140metadata: IPasteEditProviderMetadataDto,1141@IUriIdentityService private readonly _uriIdentService: IUriIdentityService1142) {1143this.copyMimeTypes = metadata.copyMimeTypes ?? [];1144this.pasteMimeTypes = metadata.pasteMimeTypes ?? [];1145this.providedPasteEditKinds = metadata.providedPasteEditKinds?.map(kind => new HierarchicalKind(kind)) ?? [];11461147if (metadata.supportsCopy) {1148this.prepareDocumentPaste = async (model: ITextModel, selections: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<IReadonlyVSDataTransfer | undefined> => {1149const dataTransferDto = await typeConvert.DataTransfer.fromList(dataTransfer);1150if (token.isCancellationRequested) {1151return undefined;1152}11531154const newDataTransfer = await this._proxy.$prepareDocumentPaste(_handle, model.uri, selections, dataTransferDto, token);1155if (!newDataTransfer) {1156return undefined;1157}11581159const dataTransferOut = new VSDataTransfer();1160for (const [type, item] of newDataTransfer.items) {1161dataTransferOut.replace(type, createStringDataTransferItem(item.asString, item.id));1162}1163return dataTransferOut;1164};1165}11661167if (metadata.supportsPaste) {1168this.provideDocumentPasteEdits = async (model: ITextModel, selections: Selection[], dataTransfer: IReadonlyVSDataTransfer, context: languages.DocumentPasteContext, token: CancellationToken) => {1169const request = this.dataTransfers.add(dataTransfer);1170try {1171const dataTransferDto = await typeConvert.DataTransfer.fromList(dataTransfer);1172if (token.isCancellationRequested) {1173return;1174}11751176const edits = await this._proxy.$providePasteEdits(this._handle, request.id, model.uri, selections, dataTransferDto, {1177only: context.only?.value,1178triggerKind: context.triggerKind,1179}, token);1180if (!edits) {1181return;1182}11831184return {1185edits: edits.map((edit): languages.DocumentPasteEdit => {1186return {1187...edit,1188kind: edit.kind ? new HierarchicalKind(edit.kind.value) : new HierarchicalKind(''),1189yieldTo: edit.yieldTo?.map(x => ({ kind: new HierarchicalKind(x) })),1190additionalEdit: edit.additionalEdit ? reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveFileData(request.id, dataId)) : undefined,1191};1192}),1193dispose: () => {1194this._proxy.$releasePasteEdits(this._handle, request.id);1195},1196};1197} finally {1198request.dispose();1199}1200};1201}1202if (metadata.supportsResolve) {1203this.resolveDocumentPasteEdit = async (edit: languages.DocumentPasteEdit, token: CancellationToken) => {1204const resolved = await this._proxy.$resolvePasteEdit(this._handle, (<IPasteEditDto>edit)._cacheId!, token);1205if (typeof resolved.insertText !== 'undefined') {1206edit.insertText = resolved.insertText;1207}12081209if (resolved.additionalEdit) {1210edit.additionalEdit = reviveWorkspaceEditDto(resolved.additionalEdit, this._uriIdentService);1211}1212return edit;1213};1214}1215}12161217resolveFileData(requestId: number, dataId: string): Promise<VSBuffer> {1218return this.dataTransfers.resolveFileData(requestId, dataId);1219}1220}12211222class MainThreadDocumentOnDropEditProvider implements languages.DocumentDropEditProvider {12231224private readonly dataTransfers = new DataTransferFileCache();12251226readonly dropMimeTypes?: readonly string[];12271228readonly providedDropEditKinds: readonly HierarchicalKind[] | undefined;12291230readonly resolveDocumentDropEdit?: languages.DocumentDropEditProvider['resolveDocumentDropEdit'];12311232constructor(1233private readonly _handle: number,1234private readonly _proxy: ExtHostLanguageFeaturesShape,1235metadata: IDocumentDropEditProviderMetadata | undefined,1236@IUriIdentityService private readonly _uriIdentService: IUriIdentityService1237) {1238this.dropMimeTypes = metadata?.dropMimeTypes ?? ['*/*'];1239this.providedDropEditKinds = metadata?.providedDropKinds?.map(kind => new HierarchicalKind(kind));12401241if (metadata?.supportsResolve) {1242this.resolveDocumentDropEdit = async (edit, token) => {1243const resolved = await this._proxy.$resolvePasteEdit(this._handle, (<IDocumentDropEditDto>edit)._cacheId!, token);1244if (resolved.additionalEdit) {1245edit.additionalEdit = reviveWorkspaceEditDto(resolved.additionalEdit, this._uriIdentService);1246}1247return edit;1248};1249}1250}12511252async provideDocumentDropEdits(model: ITextModel, position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise<languages.DocumentDropEditsSession | undefined> {1253const request = this.dataTransfers.add(dataTransfer);1254try {1255const dataTransferDto = await typeConvert.DataTransfer.fromList(dataTransfer);1256if (token.isCancellationRequested) {1257return;1258}12591260const edits = await this._proxy.$provideDocumentOnDropEdits(this._handle, request.id, model.uri, position, dataTransferDto, token);1261if (!edits) {1262return;1263}12641265return {1266edits: edits.map(edit => {1267return {1268...edit,1269yieldTo: edit.yieldTo?.map(x => ({ kind: new HierarchicalKind(x) })),1270kind: edit.kind ? new HierarchicalKind(edit.kind) : undefined,1271additionalEdit: reviveWorkspaceEditDto(edit.additionalEdit, this._uriIdentService, dataId => this.resolveDocumentOnDropFileData(request.id, dataId)),1272};1273}),1274dispose: () => {1275this._proxy.$releaseDocumentOnDropEdits(this._handle, request.id);1276},1277};1278} finally {1279request.dispose();1280}1281}12821283public resolveDocumentOnDropFileData(requestId: number, dataId: string): Promise<VSBuffer> {1284return this.dataTransfers.resolveFileData(requestId, dataId);1285}1286}12871288export class MainThreadDocumentSemanticTokensProvider implements languages.DocumentSemanticTokensProvider {12891290constructor(1291private readonly _proxy: ExtHostLanguageFeaturesShape,1292private readonly _handle: number,1293private readonly _legend: languages.SemanticTokensLegend,1294public readonly onDidChange: Event<void> | undefined,1295) {1296}12971298public releaseDocumentSemanticTokens(resultId: string | undefined): void {1299if (resultId) {1300this._proxy.$releaseDocumentSemanticTokens(this._handle, parseInt(resultId, 10));1301}1302}13031304public getLegend(): languages.SemanticTokensLegend {1305return this._legend;1306}13071308async provideDocumentSemanticTokens(model: ITextModel, lastResultId: string | null, token: CancellationToken): Promise<languages.SemanticTokens | languages.SemanticTokensEdits | null> {1309const nLastResultId = lastResultId ? parseInt(lastResultId, 10) : 0;1310const encodedDto = await this._proxy.$provideDocumentSemanticTokens(this._handle, model.uri, nLastResultId, token);1311if (!encodedDto) {1312return null;1313}1314if (token.isCancellationRequested) {1315return null;1316}1317const dto = decodeSemanticTokensDto(encodedDto);1318if (dto.type === 'full') {1319return {1320resultId: String(dto.id),1321data: dto.data1322};1323}1324return {1325resultId: String(dto.id),1326edits: dto.deltas1327};1328}1329}13301331export class MainThreadDocumentRangeSemanticTokensProvider implements languages.DocumentRangeSemanticTokensProvider {13321333constructor(1334private readonly _proxy: ExtHostLanguageFeaturesShape,1335private readonly _handle: number,1336private readonly _legend: languages.SemanticTokensLegend,1337) {1338}13391340public getLegend(): languages.SemanticTokensLegend {1341return this._legend;1342}13431344async provideDocumentRangeSemanticTokens(model: ITextModel, range: EditorRange, token: CancellationToken): Promise<languages.SemanticTokens | null> {1345const encodedDto = await this._proxy.$provideDocumentRangeSemanticTokens(this._handle, model.uri, range, token);1346if (!encodedDto) {1347return null;1348}1349if (token.isCancellationRequested) {1350return null;1351}1352const dto = decodeSemanticTokensDto(encodedDto);1353if (dto.type === 'full') {1354return {1355resultId: String(dto.id),1356data: dto.data1357};1358}1359throw new Error(`Unexpected`);1360}1361}13621363type InlineCompletionEndOfLifeEvent = {1364/**1365* @deprecated To be removed at one point in favor of opportunityId1366*/1367id: string;1368opportunityId: string;1369correlationId: string | undefined;1370extensionId: string;1371extensionVersion: string;1372groupId: string | undefined;1373shown: boolean;1374shownDuration: number;1375shownDurationUncollapsed: number;1376timeUntilShown: number | undefined;1377timeUntilProviderRequest: number;1378timeUntilProviderResponse: number;1379reason: 'accepted' | 'rejected' | 'ignored';1380partiallyAccepted: number;1381partiallyAcceptedCountSinceOriginal: number;1382partiallyAcceptedRatioSinceOriginal: number;1383partiallyAcceptedCharactersSinceOriginal: number;1384preceeded: boolean;1385requestReason: string;1386languageId: string;1387error: string | undefined;1388typingInterval: number;1389typingIntervalCharacterCount: number;1390superseded: boolean;1391editorType: string;1392viewKind: string | undefined;1393cursorColumnDistance: number | undefined;1394cursorLineDistance: number | undefined;1395lineCountOriginal: number | undefined;1396lineCountModified: number | undefined;1397characterCountOriginal: number | undefined;1398characterCountModified: number | undefined;1399disjointReplacements: number | undefined;1400sameShapeReplacements: boolean | undefined;1401};14021403type InlineCompletionsEndOfLifeClassification = {1404owner: 'benibenj';1405comment: 'Inline completions ended';1406id: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier for the inline completion request' };1407opportunityId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Unique identifier for an opportunity to show an inline completion or NES' };1408correlationId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The correlation identifier for the inline completion' };1409extensionId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier for the extension that contributed the inline completion' };1410extensionVersion: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The version of the extension that contributed the inline completion' };1411groupId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The group ID of the extension that contributed the inline completion' };1412shown: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the inline completion was shown to the user' };1413shownDuration: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The duration for which the inline completion was shown' };1414shownDurationUncollapsed: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The duration for which the inline completion was shown without collapsing' };1415timeUntilShown: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The time it took for the inline completion to be shown after the request' };1416timeUntilProviderRequest: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The time it took for the inline completion to be requested from the provider' };1417timeUntilProviderResponse: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The time it took for the inline completion to be shown after the request' };1418reason: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The reason for the inline completion ending' };1419partiallyAccepted: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'How often the inline completion was partially accepted by the user' };1420partiallyAcceptedCountSinceOriginal: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'How often the inline completion was partially accepted since the original request' };1421partiallyAcceptedRatioSinceOriginal: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The percentage of characters accepted since the original request' };1422partiallyAcceptedCharactersSinceOriginal: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The character count accepted since the original request' };1423preceeded: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the inline completion was preceeded by another one' };1424languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The language ID of the document where the inline completion was shown' };1425requestReason: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The reason for the inline completion request' };1426error: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The error message if the inline completion failed' };1427typingInterval: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The average typing interval of the user at the moment the inline completion was requested' };1428typingIntervalCharacterCount: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The character count involved in the typing interval calculation' };1429superseded: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether the inline completion was superseded by another one' };1430editorType: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The type of the editor where the inline completion was shown' };1431viewKind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The kind of the view where the inline completion was shown' };1432cursorColumnDistance: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The distance in columns from the cursor to the inline suggestion' };1433cursorLineDistance: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The distance in lines from the cursor to the inline suggestion' };1434lineCountOriginal: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The number of lines in the original text' };1435lineCountModified: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The number of lines in the modified text' };1436characterCountOriginal: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The number of characters in the original text' };1437characterCountModified: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The number of characters in the modified text' };1438disjointReplacements: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The number of inner replacements made by the inline completion' };1439sameShapeReplacements: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Whether all inner replacements are the same shape' };1440};144114421443