Path: blob/main/src/vs/workbench/api/common/extHostDebugService.ts
5221 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 type * as vscode from 'vscode';6import { coalesce } from '../../../base/common/arrays.js';7import { asPromise } from '../../../base/common/async.js';8import { CancellationToken } from '../../../base/common/cancellation.js';9import { Emitter, Event } from '../../../base/common/event.js';10import { Disposable as DisposableCls, toDisposable } from '../../../base/common/lifecycle.js';11import { ThemeIcon as ThemeIconUtils } from '../../../base/common/themables.js';12import { URI, UriComponents } from '../../../base/common/uri.js';13import { ExtensionIdentifier, IExtensionDescription } from '../../../platform/extensions/common/extensions.js';14import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';15import { ISignService } from '../../../platform/sign/common/sign.js';16import { IWorkspaceFolderData } from '../../../platform/workspace/common/workspace.js';17import { AbstractDebugAdapter } from '../../contrib/debug/common/abstractDebugAdapter.js';18import { DebugVisualizationType, IAdapterDescriptor, IConfig, IDebugAdapter, IDebugAdapterExecutable, IDebugAdapterImpl, IDebugAdapterNamedPipeServer, IDebugAdapterServer, IDebuggerContribution, IDebugVisualization, IDebugVisualizationContext, IDebugVisualizationTreeItem, MainThreadDebugVisualization } from '../../contrib/debug/common/debug.js';19import { convertToDAPaths, convertToVSCPaths, isDebuggerMainContribution } from '../../contrib/debug/common/debugUtils.js';20import { ExtensionDescriptionRegistry } from '../../services/extensions/common/extensionDescriptionRegistry.js';21import { Dto } from '../../services/extensions/common/proxyIdentifier.js';22import { DebugSessionUUID, ExtHostDebugServiceShape, IBreakpointsDeltaDto, IDebugSessionDto, IFunctionBreakpointDto, ISourceMultiBreakpointDto, IStackFrameFocusDto, IThreadFocusDto, MainContext, MainThreadDebugServiceShape, MainThreadTelemetryShape } from './extHost.protocol.js';23import { IExtHostCommands } from './extHostCommands.js';24import { IExtHostConfiguration } from './extHostConfiguration.js';25import { IExtHostEditorTabs } from './extHostEditorTabs.js';26import { IExtHostExtensionService } from './extHostExtensionService.js';27import { IExtHostRpcService } from './extHostRpcService.js';28import { IExtHostTesting } from './extHostTesting.js';29import * as Convert from './extHostTypeConverters.js';30import { Breakpoint, DataBreakpoint, DebugAdapterExecutable, DebugAdapterInlineImplementation, DebugAdapterNamedPipeServer, DebugAdapterServer, DebugConsoleMode, DebugStackFrame, DebugThread, Disposable, FunctionBreakpoint, Location, Position, setBreakpointId, SourceBreakpoint, ThemeIcon } from './extHostTypes.js';31import { IExtHostVariableResolverProvider } from './extHostVariableResolverService.js';32import { IExtHostWorkspace } from './extHostWorkspace.js';3334export const IExtHostDebugService = createDecorator<IExtHostDebugService>('IExtHostDebugService');3536export interface IExtHostDebugService extends ExtHostDebugServiceShape {3738readonly _serviceBrand: undefined;3940readonly onDidStartDebugSession: Event<vscode.DebugSession>;41readonly onDidTerminateDebugSession: Event<vscode.DebugSession>;42readonly onDidChangeActiveDebugSession: Event<vscode.DebugSession | undefined>;43activeDebugSession: vscode.DebugSession | undefined;44activeDebugConsole: vscode.DebugConsole;45readonly onDidReceiveDebugSessionCustomEvent: Event<vscode.DebugSessionCustomEvent>;46readonly onDidChangeBreakpoints: Event<vscode.BreakpointsChangeEvent>;47breakpoints: vscode.Breakpoint[];48readonly onDidChangeActiveStackItem: Event<vscode.DebugThread | vscode.DebugStackFrame | undefined>;49activeStackItem: vscode.DebugThread | vscode.DebugStackFrame | undefined;5051addBreakpoints(breakpoints0: readonly vscode.Breakpoint[]): Promise<void>;52removeBreakpoints(breakpoints0: readonly vscode.Breakpoint[]): Promise<void>;53startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean>;54stopDebugging(session?: vscode.DebugSession): Promise<void>;55registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable;56registerDebugAdapterDescriptorFactory(extension: IExtensionDescription, type: string, factory: vscode.DebugAdapterDescriptorFactory): vscode.Disposable;57registerDebugAdapterTrackerFactory(type: string, factory: vscode.DebugAdapterTrackerFactory): vscode.Disposable;58registerDebugVisualizationProvider<T extends vscode.DebugVisualization>(extension: IExtensionDescription, id: string, provider: vscode.DebugVisualizationProvider<T>): vscode.Disposable;59registerDebugVisualizationTree<T extends vscode.DebugTreeItem>(extension: IExtensionDescription, id: string, provider: vscode.DebugVisualizationTree<T>): vscode.Disposable;60asDebugSourceUri(source: vscode.DebugProtocolSource, session?: vscode.DebugSession): vscode.Uri;61}6263export abstract class ExtHostDebugServiceBase extends DisposableCls implements IExtHostDebugService, ExtHostDebugServiceShape {6465declare readonly _serviceBrand: undefined;6667private _configProviderHandleCounter: number;68private _configProviders: ConfigProviderTuple[];6970private _adapterFactoryHandleCounter: number;71private _adapterFactories: DescriptorFactoryTuple[];7273private _trackerFactoryHandleCounter: number;74private _trackerFactories: TrackerFactoryTuple[];7576private _debugServiceProxy: MainThreadDebugServiceShape;77private _debugSessions: Map<DebugSessionUUID, ExtHostDebugSession> = new Map<DebugSessionUUID, ExtHostDebugSession>();7879private readonly _onDidStartDebugSession: Emitter<vscode.DebugSession>;80get onDidStartDebugSession(): Event<vscode.DebugSession> { return this._onDidStartDebugSession.event; }8182private readonly _onDidTerminateDebugSession: Emitter<vscode.DebugSession>;83get onDidTerminateDebugSession(): Event<vscode.DebugSession> { return this._onDidTerminateDebugSession.event; }8485private readonly _onDidChangeActiveDebugSession: Emitter<vscode.DebugSession | undefined>;86get onDidChangeActiveDebugSession(): Event<vscode.DebugSession | undefined> { return this._onDidChangeActiveDebugSession.event; }8788private _activeDebugSession: ExtHostDebugSession | undefined;89get activeDebugSession(): vscode.DebugSession | undefined { return this._activeDebugSession?.api; }9091private readonly _onDidReceiveDebugSessionCustomEvent: Emitter<vscode.DebugSessionCustomEvent>;92get onDidReceiveDebugSessionCustomEvent(): Event<vscode.DebugSessionCustomEvent> { return this._onDidReceiveDebugSessionCustomEvent.event; }9394private _activeDebugConsole: ExtHostDebugConsole;95get activeDebugConsole(): vscode.DebugConsole { return this._activeDebugConsole.value; }9697private _breakpoints: Map<string, vscode.Breakpoint>;9899private readonly _onDidChangeBreakpoints: Emitter<vscode.BreakpointsChangeEvent>;100101private _activeStackItem: vscode.DebugThread | vscode.DebugStackFrame | undefined;102private readonly _onDidChangeActiveStackItem: Emitter<vscode.DebugThread | vscode.DebugStackFrame | undefined>;103104private _debugAdapters: Map<number, IDebugAdapter>;105private _debugAdaptersTrackers: Map<number, vscode.DebugAdapterTracker>;106107private _debugVisualizationTreeItemIdsCounter = 0;108private readonly _debugVisualizationProviders = new Map<string, vscode.DebugVisualizationProvider>();109private readonly _debugVisualizationTrees = new Map<string, vscode.DebugVisualizationTree>();110private readonly _debugVisualizationTreeItemIds = new WeakMap<vscode.DebugTreeItem, number>();111private readonly _debugVisualizationElements = new Map<number, { provider: string; item: vscode.DebugTreeItem; children?: number[] }>();112113private _signService: ISignService | undefined;114115private readonly _visualizers = new Map<number, { v: vscode.DebugVisualization; provider: vscode.DebugVisualizationProvider; extensionId: string }>();116private _visualizerIdCounter = 0;117118private _telemetryProxy: MainThreadTelemetryShape;119120constructor(121@IExtHostRpcService extHostRpcService: IExtHostRpcService,122@IExtHostWorkspace protected readonly _workspaceService: IExtHostWorkspace,123@IExtHostExtensionService private readonly _extensionService: IExtHostExtensionService,124@IExtHostConfiguration protected readonly _configurationService: IExtHostConfiguration,125@IExtHostEditorTabs protected readonly _editorTabs: IExtHostEditorTabs,126@IExtHostVariableResolverProvider private readonly _variableResolver: IExtHostVariableResolverProvider,127@IExtHostCommands private readonly _commands: IExtHostCommands,128@IExtHostTesting private readonly _testing: IExtHostTesting,129) {130super();131132this._configProviderHandleCounter = 0;133this._configProviders = [];134135this._adapterFactoryHandleCounter = 0;136this._adapterFactories = [];137138this._trackerFactoryHandleCounter = 0;139this._trackerFactories = [];140141this._debugAdapters = new Map();142this._debugAdaptersTrackers = new Map();143144this._onDidStartDebugSession = this._register(new Emitter<vscode.DebugSession>());145this._onDidTerminateDebugSession = this._register(new Emitter<vscode.DebugSession>());146this._onDidChangeActiveDebugSession = this._register(new Emitter<vscode.DebugSession | undefined>());147this._onDidReceiveDebugSessionCustomEvent = this._register(new Emitter<vscode.DebugSessionCustomEvent>());148149this._debugServiceProxy = extHostRpcService.getProxy(MainContext.MainThreadDebugService);150151this._onDidChangeBreakpoints = this._register(new Emitter<vscode.BreakpointsChangeEvent>());152153this._onDidChangeActiveStackItem = this._register(new Emitter<vscode.DebugThread | vscode.DebugStackFrame | undefined>());154155this._activeDebugConsole = new ExtHostDebugConsole(this._debugServiceProxy);156157this._breakpoints = new Map<string, vscode.Breakpoint>();158159this._extensionService.getExtensionRegistry().then((extensionRegistry: ExtensionDescriptionRegistry) => {160this._register(extensionRegistry.onDidChange(_ => {161this.registerAllDebugTypes(extensionRegistry);162}));163this.registerAllDebugTypes(extensionRegistry);164});165166this._telemetryProxy = extHostRpcService.getProxy(MainContext.MainThreadTelemetry);167}168169public async $getVisualizerTreeItem(treeId: string, element: IDebugVisualizationContext): Promise<IDebugVisualizationTreeItem | undefined> {170const context = this.hydrateVisualizationContext(element);171if (!context) {172return undefined;173}174175const item = await this._debugVisualizationTrees.get(treeId)?.getTreeItem?.(context);176return item ? this.convertVisualizerTreeItem(treeId, item) : undefined;177}178179public registerDebugVisualizationTree<T extends vscode.DebugTreeItem>(manifest: IExtensionDescription, id: string, provider: vscode.DebugVisualizationTree<T>): vscode.Disposable {180const extensionId = ExtensionIdentifier.toKey(manifest.identifier);181const key = this.extensionVisKey(extensionId, id);182if (this._debugVisualizationProviders.has(key)) {183throw new Error(`A debug visualization provider with id '${id}' is already registered`);184}185186this._debugVisualizationTrees.set(key, provider);187this._debugServiceProxy.$registerDebugVisualizerTree(key, !!provider.editItem);188return toDisposable(() => {189this._debugServiceProxy.$unregisterDebugVisualizerTree(key);190this._debugVisualizationTrees.delete(id);191});192}193194public async $getVisualizerTreeItemChildren(treeId: string, element: number): Promise<IDebugVisualizationTreeItem[]> {195const item = this._debugVisualizationElements.get(element)?.item;196if (!item) {197return [];198}199200const children = await this._debugVisualizationTrees.get(treeId)?.getChildren?.(item);201return children?.map(i => this.convertVisualizerTreeItem(treeId, i)) || [];202}203204public async $editVisualizerTreeItem(element: number, value: string): Promise<IDebugVisualizationTreeItem | undefined> {205const e = this._debugVisualizationElements.get(element);206if (!e) { return undefined; }207208const r = await this._debugVisualizationTrees.get(e.provider)?.editItem?.(e.item, value);209return this.convertVisualizerTreeItem(e.provider, r || e.item);210}211212public $disposeVisualizedTree(element: number): void {213const root = this._debugVisualizationElements.get(element);214if (!root) {215return;216}217218const queue = [root.children];219for (const children of queue) {220if (children) {221for (const child of children) {222queue.push(this._debugVisualizationElements.get(child)?.children);223this._debugVisualizationElements.delete(child);224}225}226}227}228229private convertVisualizerTreeItem(treeId: string, item: vscode.DebugTreeItem): IDebugVisualizationTreeItem {230let id = this._debugVisualizationTreeItemIds.get(item);231if (!id) {232id = this._debugVisualizationTreeItemIdsCounter++;233this._debugVisualizationTreeItemIds.set(item, id);234this._debugVisualizationElements.set(id, { provider: treeId, item });235}236237return Convert.DebugTreeItem.from(item, id);238}239240public asDebugSourceUri(src: vscode.DebugProtocolSource, session?: vscode.DebugSession): URI {241242// eslint-disable-next-line local/code-no-any-casts243const source = <any>src;244245if (typeof source.sourceReference === 'number' && source.sourceReference > 0) {246// src can be retrieved via DAP's "source" request247248let debug = `debug:${encodeURIComponent(source.path || '')}`;249let sep = '?';250251if (session) {252debug += `${sep}session=${encodeURIComponent(session.id)}`;253sep = '&';254}255256debug += `${sep}ref=${source.sourceReference}`;257258return URI.parse(debug);259} else if (source.path) {260// src is just a local file path261return URI.file(source.path);262} else {263throw new Error(`cannot create uri from DAP 'source' object; properties 'path' and 'sourceReference' are both missing.`);264}265}266267private registerAllDebugTypes(extensionRegistry: ExtensionDescriptionRegistry) {268269const debugTypes: string[] = [];270271for (const ed of extensionRegistry.getAllExtensionDescriptions()) {272if (ed.contributes) {273const debuggers = <IDebuggerContribution[]>ed.contributes['debuggers'];274if (debuggers && debuggers.length > 0) {275for (const dbg of debuggers) {276if (isDebuggerMainContribution(dbg)) {277debugTypes.push(dbg.type);278}279}280}281}282}283284this._debugServiceProxy.$registerDebugTypes(debugTypes);285}286287// extension debug API288289290get activeStackItem(): vscode.DebugThread | vscode.DebugStackFrame | undefined {291return this._activeStackItem;292}293294get onDidChangeActiveStackItem(): Event<vscode.DebugThread | vscode.DebugStackFrame | undefined> {295return this._onDidChangeActiveStackItem.event;296}297298get onDidChangeBreakpoints(): Event<vscode.BreakpointsChangeEvent> {299return this._onDidChangeBreakpoints.event;300}301302get breakpoints(): vscode.Breakpoint[] {303const result: vscode.Breakpoint[] = [];304this._breakpoints.forEach(bp => result.push(bp));305return result;306}307308public async $resolveDebugVisualizer(id: number, token: CancellationToken): Promise<MainThreadDebugVisualization> {309const visualizer = this._visualizers.get(id);310if (!visualizer) {311throw new Error(`No debug visualizer found with id '${id}'`);312}313314let { v, provider, extensionId } = visualizer;315if (!v.visualization) {316v = await provider.resolveDebugVisualization?.(v, token) || v;317visualizer.v = v;318}319320if (!v.visualization) {321throw new Error(`No visualization returned from resolveDebugVisualization in '${provider}'`);322}323324return this.serializeVisualization(extensionId, v.visualization)!;325}326327public async $executeDebugVisualizerCommand(id: number): Promise<void> {328const visualizer = this._visualizers.get(id);329if (!visualizer) {330throw new Error(`No debug visualizer found with id '${id}'`);331}332333const command = visualizer.v.visualization;334if (command && 'command' in command) {335this._commands.executeCommand(command.command, ...(command.arguments || []));336}337}338339private hydrateVisualizationContext(context: IDebugVisualizationContext): vscode.DebugVisualizationContext | undefined {340const session = this._debugSessions.get(context.sessionId);341return session && {342session: session.api,343variable: context.variable,344containerId: context.containerId,345frameId: context.frameId,346threadId: context.threadId,347};348}349350public async $provideDebugVisualizers(extensionId: string, id: string, context: IDebugVisualizationContext, token: CancellationToken): Promise<IDebugVisualization.Serialized[]> {351const contextHydrated = this.hydrateVisualizationContext(context);352const key = this.extensionVisKey(extensionId, id);353const provider = this._debugVisualizationProviders.get(key);354if (!contextHydrated || !provider) {355return []; // probably ended in the meantime356}357358const visualizations = await provider.provideDebugVisualization(contextHydrated, token);359360if (!visualizations) {361return [];362}363364return visualizations.map(v => {365const id = ++this._visualizerIdCounter;366this._visualizers.set(id, { v, provider, extensionId });367const icon = v.iconPath ? this.getIconPathOrClass(v.iconPath) : undefined;368return {369id,370name: v.name,371iconClass: icon?.iconClass,372iconPath: icon?.iconPath,373visualization: this.serializeVisualization(extensionId, v.visualization),374};375});376}377378public $disposeDebugVisualizers(ids: number[]): void {379for (const id of ids) {380this._visualizers.delete(id);381}382}383384public registerDebugVisualizationProvider<T extends vscode.DebugVisualization>(manifest: IExtensionDescription, id: string, provider: vscode.DebugVisualizationProvider<T>): vscode.Disposable {385if (!manifest.contributes?.debugVisualizers?.some(r => r.id === id)) {386throw new Error(`Extensions may only call registerDebugVisualizationProvider() for renderers they contribute (got ${id})`);387}388389const extensionId = ExtensionIdentifier.toKey(manifest.identifier);390const key = this.extensionVisKey(extensionId, id);391if (this._debugVisualizationProviders.has(key)) {392throw new Error(`A debug visualization provider with id '${id}' is already registered`);393}394395this._debugVisualizationProviders.set(key, provider);396this._debugServiceProxy.$registerDebugVisualizer(extensionId, id);397return toDisposable(() => {398this._debugServiceProxy.$unregisterDebugVisualizer(extensionId, id);399this._debugVisualizationProviders.delete(id);400});401}402403public addBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void> {404// filter only new breakpoints405const breakpoints = breakpoints0.filter(bp => {406const id = bp.id;407if (!this._breakpoints.has(id)) {408this._breakpoints.set(id, bp);409return true;410}411return false;412});413414// send notification for added breakpoints415this.fireBreakpointChanges(breakpoints, [], []);416417// convert added breakpoints to DTOs418const dtos: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto> = [];419const map = new Map<string, ISourceMultiBreakpointDto>();420for (const bp of breakpoints) {421if (bp instanceof SourceBreakpoint) {422let dto = map.get(bp.location.uri.toString());423if (!dto) {424dto = {425type: 'sourceMulti',426uri: bp.location.uri,427lines: []428} satisfies ISourceMultiBreakpointDto;429map.set(bp.location.uri.toString(), dto);430dtos.push(dto);431}432dto.lines.push({433id: bp.id,434enabled: bp.enabled,435condition: bp.condition,436hitCondition: bp.hitCondition,437logMessage: bp.logMessage,438line: bp.location.range.start.line,439character: bp.location.range.start.character,440mode: bp.mode,441});442} else if (bp instanceof FunctionBreakpoint) {443dtos.push({444type: 'function',445id: bp.id,446enabled: bp.enabled,447hitCondition: bp.hitCondition,448logMessage: bp.logMessage,449condition: bp.condition,450functionName: bp.functionName,451mode: bp.mode,452});453}454}455456// send DTOs to VS Code457return this._debugServiceProxy.$registerBreakpoints(dtos);458}459460public removeBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void> {461// remove from array462const breakpoints = breakpoints0.filter(b => this._breakpoints.delete(b.id));463464// send notification465this.fireBreakpointChanges([], breakpoints, []);466467// unregister with VS Code468const ids = breakpoints.filter(bp => bp instanceof SourceBreakpoint).map(bp => bp.id);469const fids = breakpoints.filter(bp => bp instanceof FunctionBreakpoint).map(bp => bp.id);470const dids = breakpoints.filter(bp => bp instanceof DataBreakpoint).map(bp => bp.id);471return this._debugServiceProxy.$unregisterBreakpoints(ids, fids, dids);472}473474public startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean> {475const testRunMeta = options.testRun && this._testing.getMetadataForRun(options.testRun);476477return this._debugServiceProxy.$startDebugging(folder ? folder.uri : undefined, nameOrConfig, {478parentSessionID: options.parentSession ? options.parentSession.id : undefined,479lifecycleManagedByParent: options.lifecycleManagedByParent,480repl: options.consoleMode === DebugConsoleMode.MergeWithParent ? 'mergeWithParent' : 'separate',481noDebug: options.noDebug,482compact: options.compact,483suppressSaveBeforeStart: options.suppressSaveBeforeStart,484testRun: testRunMeta && {485runId: testRunMeta.runId,486taskId: testRunMeta.taskId,487},488489// Check debugUI for back-compat, #147264490// eslint-disable-next-line local/code-no-any-casts491suppressDebugStatusbar: options.suppressDebugStatusbar ?? (options as any).debugUI?.simple,492// eslint-disable-next-line local/code-no-any-casts493suppressDebugToolbar: options.suppressDebugToolbar ?? (options as any).debugUI?.simple,494// eslint-disable-next-line local/code-no-any-casts495suppressDebugView: options.suppressDebugView ?? (options as any).debugUI?.simple,496});497}498499public stopDebugging(session?: vscode.DebugSession): Promise<void> {500return this._debugServiceProxy.$stopDebugging(session ? session.id : undefined);501}502503public registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable {504505if (!provider) {506return new Disposable(() => { });507}508509const handle = this._configProviderHandleCounter++;510this._configProviders.push({ type, handle, provider });511512this._debugServiceProxy.$registerDebugConfigurationProvider(type, trigger,513!!provider.provideDebugConfigurations,514!!provider.resolveDebugConfiguration,515!!provider.resolveDebugConfigurationWithSubstitutedVariables,516handle);517518return new Disposable(() => {519this._configProviders = this._configProviders.filter(p => p.provider !== provider); // remove520this._debugServiceProxy.$unregisterDebugConfigurationProvider(handle);521});522}523524public registerDebugAdapterDescriptorFactory(extension: IExtensionDescription, type: string, factory: vscode.DebugAdapterDescriptorFactory): vscode.Disposable {525526if (!factory) {527return new Disposable(() => { });528}529530// a DebugAdapterDescriptorFactory can only be registered in the extension that contributes the debugger531if (!this.definesDebugType(extension, type)) {532throw new Error(`a DebugAdapterDescriptorFactory can only be registered from the extension that defines the '${type}' debugger.`);533}534535// make sure that only one factory for this type is registered536if (this.getAdapterDescriptorFactoryByType(type)) {537throw new Error(`a DebugAdapterDescriptorFactory can only be registered once per a type.`);538}539540const handle = this._adapterFactoryHandleCounter++;541this._adapterFactories.push({ type, handle, factory });542543this._debugServiceProxy.$registerDebugAdapterDescriptorFactory(type, handle);544545return new Disposable(() => {546this._adapterFactories = this._adapterFactories.filter(p => p.factory !== factory); // remove547this._debugServiceProxy.$unregisterDebugAdapterDescriptorFactory(handle);548});549}550551public registerDebugAdapterTrackerFactory(type: string, factory: vscode.DebugAdapterTrackerFactory): vscode.Disposable {552553if (!factory) {554return new Disposable(() => { });555}556557const handle = this._trackerFactoryHandleCounter++;558this._trackerFactories.push({ type, handle, factory });559560return new Disposable(() => {561this._trackerFactories = this._trackerFactories.filter(p => p.factory !== factory); // remove562});563}564565// RPC methods (ExtHostDebugServiceShape)566567public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, sessionId: string): Promise<number | undefined> {568return Promise.resolve(undefined);569}570571public async $substituteVariables(folderUri: UriComponents | undefined, config: IConfig): Promise<IConfig> {572let ws: IWorkspaceFolderData | undefined;573const folder = await this.getFolder(folderUri);574if (folder) {575ws = {576uri: folder.uri,577name: folder.name,578index: folder.index,579};580}581const variableResolver = await this._variableResolver.getResolver();582return variableResolver.resolveAsync(ws, config);583}584585protected createDebugAdapter(adapter: vscode.DebugAdapterDescriptor, session: ExtHostDebugSession): AbstractDebugAdapter | undefined {586if (adapter instanceof DebugAdapterInlineImplementation) {587return new DirectDebugAdapter(adapter.implementation);588}589return undefined;590}591592protected createSignService(): ISignService | undefined {593return undefined;594}595596public async $startDASession(debugAdapterHandle: number, sessionDto: IDebugSessionDto): Promise<void> {597const mythis = this;598599const session = await this.getSession(sessionDto);600601return this.getAdapterDescriptor(this.getAdapterDescriptorFactoryByType(session.type), session).then(daDescriptor => {602603if (!daDescriptor) {604throw new Error(`Couldn't find a debug adapter descriptor for debug type '${session.type}' (extension might have failed to activate)`);605}606607const da = this.createDebugAdapter(daDescriptor, session);608if (!da) {609throw new Error(`Couldn't create a debug adapter for type '${session.type}'.`);610}611612const debugAdapter = da;613614this._debugAdapters.set(debugAdapterHandle, debugAdapter);615616return this.getDebugAdapterTrackers(session).then(tracker => {617618if (tracker) {619this._debugAdaptersTrackers.set(debugAdapterHandle, tracker);620}621622debugAdapter.onMessage(async message => {623624if (message.type === 'request' && (<DebugProtocol.Request>message).command === 'handshake') {625626const request = <DebugProtocol.Request>message;627628const response: DebugProtocol.Response = {629type: 'response',630seq: 0,631command: request.command,632request_seq: request.seq,633success: true634};635636if (!this._signService) {637this._signService = this.createSignService();638}639640try {641if (this._signService) {642const signature = await this._signService.sign(request.arguments.value);643response.body = {644signature: signature645};646debugAdapter.sendResponse(response);647} else {648throw new Error('no signer');649}650} catch (e) {651response.success = false;652response.message = e.message;653debugAdapter.sendResponse(response);654}655} else {656if (tracker && tracker.onDidSendMessage) {657tracker.onDidSendMessage(message);658}659660// DA -> VS Code661try {662// Try to catch details for #233167663message = convertToVSCPaths(message, true);664} catch (e) {665// eslint-disable-next-line local/code-no-any-casts666const type = message.type + '_' + ((message as any).command ?? (message as any).event ?? '');667this._telemetryProxy.$publicLog2<DebugProtocolMessageErrorEvent, DebugProtocolMessageErrorClassification>('debugProtocolMessageError', { type, from: session.type });668throw e;669}670671mythis._debugServiceProxy.$acceptDAMessage(debugAdapterHandle, message);672}673});674debugAdapter.onError(err => {675if (tracker && tracker.onError) {676tracker.onError(err);677}678this._debugServiceProxy.$acceptDAError(debugAdapterHandle, err.name, err.message, err.stack);679});680debugAdapter.onExit((code: number | null) => {681if (tracker && tracker.onExit) {682tracker.onExit(code ?? undefined, undefined);683}684this._debugServiceProxy.$acceptDAExit(debugAdapterHandle, code ?? undefined, undefined);685});686687if (tracker && tracker.onWillStartSession) {688tracker.onWillStartSession();689}690691return debugAdapter.startSession();692});693});694}695696public $sendDAMessage(debugAdapterHandle: number, message: DebugProtocol.ProtocolMessage): void {697698// VS Code -> DA699message = convertToDAPaths(message, false);700701const tracker = this._debugAdaptersTrackers.get(debugAdapterHandle); // TODO@AW: same handle?702if (tracker && tracker.onWillReceiveMessage) {703tracker.onWillReceiveMessage(message);704}705706const da = this._debugAdapters.get(debugAdapterHandle);707da?.sendMessage(message);708}709710public $stopDASession(debugAdapterHandle: number): Promise<void> {711712const tracker = this._debugAdaptersTrackers.get(debugAdapterHandle);713this._debugAdaptersTrackers.delete(debugAdapterHandle);714if (tracker && tracker.onWillStopSession) {715tracker.onWillStopSession();716}717718const da = this._debugAdapters.get(debugAdapterHandle);719this._debugAdapters.delete(debugAdapterHandle);720if (da) {721return da.stopSession();722} else {723return Promise.resolve(void 0);724}725}726727public $acceptBreakpointsDelta(delta: IBreakpointsDeltaDto): void {728729const a: vscode.Breakpoint[] = [];730const r: vscode.Breakpoint[] = [];731const c: vscode.Breakpoint[] = [];732733if (delta.added) {734for (const bpd of delta.added) {735const id = bpd.id;736if (id && !this._breakpoints.has(id)) {737let bp: Breakpoint;738if (bpd.type === 'function') {739bp = new FunctionBreakpoint(bpd.functionName, bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage, bpd.mode);740} else if (bpd.type === 'data') {741bp = new DataBreakpoint(bpd.label, bpd.dataId, bpd.canPersist, bpd.enabled, bpd.hitCondition, bpd.condition, bpd.logMessage, bpd.mode);742} else {743const uri = URI.revive(bpd.uri);744bp = new SourceBreakpoint(new Location(uri, new Position(bpd.line, bpd.character)), bpd.enabled, bpd.condition, bpd.hitCondition, bpd.logMessage, bpd.mode);745}746setBreakpointId(bp, id);747this._breakpoints.set(id, bp);748a.push(bp);749}750}751}752753if (delta.removed) {754for (const id of delta.removed) {755const bp = this._breakpoints.get(id);756if (bp) {757this._breakpoints.delete(id);758r.push(bp);759}760}761}762763if (delta.changed) {764for (const bpd of delta.changed) {765if (bpd.id) {766const bp = this._breakpoints.get(bpd.id);767if (bp) {768if (bp instanceof FunctionBreakpoint && bpd.type === 'function') {769// eslint-disable-next-line local/code-no-any-casts770const fbp = <any>bp;771fbp.enabled = bpd.enabled;772fbp.condition = bpd.condition;773fbp.hitCondition = bpd.hitCondition;774fbp.logMessage = bpd.logMessage;775fbp.functionName = bpd.functionName;776} else if (bp instanceof SourceBreakpoint && bpd.type === 'source') {777// eslint-disable-next-line local/code-no-any-casts778const sbp = <any>bp;779sbp.enabled = bpd.enabled;780sbp.condition = bpd.condition;781sbp.hitCondition = bpd.hitCondition;782sbp.logMessage = bpd.logMessage;783sbp.location = new Location(URI.revive(bpd.uri), new Position(bpd.line, bpd.character));784}785c.push(bp);786}787}788}789}790791this.fireBreakpointChanges(a, r, c);792}793794public async $acceptStackFrameFocus(focusDto: IThreadFocusDto | IStackFrameFocusDto | undefined): Promise<void> {795let focus: vscode.DebugThread | vscode.DebugStackFrame | undefined;796if (focusDto) {797const session = await this.getSession(focusDto.sessionId);798if (focusDto.kind === 'thread') {799focus = new DebugThread(session.api, focusDto.threadId);800} else {801focus = new DebugStackFrame(session.api, focusDto.threadId, focusDto.frameId);802}803}804805this._activeStackItem = focus;806this._onDidChangeActiveStackItem.fire(this._activeStackItem);807}808809public $provideDebugConfigurations(configProviderHandle: number, folderUri: UriComponents | undefined, token: CancellationToken): Promise<vscode.DebugConfiguration[]> {810return asPromise(async () => {811const provider = this.getConfigProviderByHandle(configProviderHandle);812if (!provider) {813throw new Error('no DebugConfigurationProvider found');814}815if (!provider.provideDebugConfigurations) {816throw new Error('DebugConfigurationProvider has no method provideDebugConfigurations');817}818const folder = await this.getFolder(folderUri);819return provider.provideDebugConfigurations(folder, token);820}).then(debugConfigurations => {821if (!debugConfigurations) {822throw new Error('nothing returned from DebugConfigurationProvider.provideDebugConfigurations');823}824return debugConfigurations;825});826}827828public $resolveDebugConfiguration(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration, token: CancellationToken): Promise<vscode.DebugConfiguration | null | undefined> {829return asPromise(async () => {830const provider = this.getConfigProviderByHandle(configProviderHandle);831if (!provider) {832throw new Error('no DebugConfigurationProvider found');833}834if (!provider.resolveDebugConfiguration) {835throw new Error('DebugConfigurationProvider has no method resolveDebugConfiguration');836}837const folder = await this.getFolder(folderUri);838return provider.resolveDebugConfiguration(folder, debugConfiguration, token);839});840}841842public $resolveDebugConfigurationWithSubstitutedVariables(configProviderHandle: number, folderUri: UriComponents | undefined, debugConfiguration: vscode.DebugConfiguration, token: CancellationToken): Promise<vscode.DebugConfiguration | null | undefined> {843return asPromise(async () => {844const provider = this.getConfigProviderByHandle(configProviderHandle);845if (!provider) {846throw new Error('no DebugConfigurationProvider found');847}848if (!provider.resolveDebugConfigurationWithSubstitutedVariables) {849throw new Error('DebugConfigurationProvider has no method resolveDebugConfigurationWithSubstitutedVariables');850}851const folder = await this.getFolder(folderUri);852return provider.resolveDebugConfigurationWithSubstitutedVariables(folder, debugConfiguration, token);853});854}855856public async $provideDebugAdapter(adapterFactoryHandle: number, sessionDto: IDebugSessionDto): Promise<Dto<IAdapterDescriptor>> {857const adapterDescriptorFactory = this.getAdapterDescriptorFactoryByHandle(adapterFactoryHandle);858if (!adapterDescriptorFactory) {859return Promise.reject(new Error('no adapter descriptor factory found for handle'));860}861const session = await this.getSession(sessionDto);862return this.getAdapterDescriptor(adapterDescriptorFactory, session).then(adapterDescriptor => {863if (!adapterDescriptor) {864throw new Error(`Couldn't find a debug adapter descriptor for debug type '${session.type}'`);865}866return this.convertToDto(adapterDescriptor);867});868}869870public async $acceptDebugSessionStarted(sessionDto: IDebugSessionDto): Promise<void> {871const session = await this.getSession(sessionDto);872this._onDidStartDebugSession.fire(session.api);873}874875public async $acceptDebugSessionTerminated(sessionDto: IDebugSessionDto): Promise<void> {876const session = await this.getSession(sessionDto);877if (session) {878this._onDidTerminateDebugSession.fire(session.api);879this._debugSessions.delete(session.id);880}881}882883public async $acceptDebugSessionActiveChanged(sessionDto: IDebugSessionDto | undefined): Promise<void> {884this._activeDebugSession = sessionDto ? await this.getSession(sessionDto) : undefined;885this._onDidChangeActiveDebugSession.fire(this._activeDebugSession?.api);886}887888public async $acceptDebugSessionNameChanged(sessionDto: IDebugSessionDto, name: string): Promise<void> {889const session = await this.getSession(sessionDto);890session?._acceptNameChanged(name);891}892893public async $acceptDebugSessionCustomEvent(sessionDto: IDebugSessionDto, event: any): Promise<void> {894const session = await this.getSession(sessionDto);895const ee: vscode.DebugSessionCustomEvent = {896session: session.api,897event: event.event,898body: event.body899};900this._onDidReceiveDebugSessionCustomEvent.fire(ee);901}902903// private & dto helpers904905private convertToDto(x: vscode.DebugAdapterDescriptor): Dto<IAdapterDescriptor> {906if (x instanceof DebugAdapterExecutable) {907return this.convertExecutableToDto(x);908} else if (x instanceof DebugAdapterServer) {909return this.convertServerToDto(x);910} else if (x instanceof DebugAdapterNamedPipeServer) {911return this.convertPipeServerToDto(x);912} else if (x instanceof DebugAdapterInlineImplementation) {913return this.convertImplementationToDto(x);914} else {915throw new Error('convertToDto unexpected type');916}917}918919protected convertExecutableToDto(x: DebugAdapterExecutable): IDebugAdapterExecutable {920return {921type: 'executable',922command: x.command,923args: x.args,924options: x.options925};926}927928protected convertServerToDto(x: DebugAdapterServer): IDebugAdapterServer {929return {930type: 'server',931port: x.port,932host: x.host933};934}935936protected convertPipeServerToDto(x: DebugAdapterNamedPipeServer): IDebugAdapterNamedPipeServer {937return {938type: 'pipeServer',939path: x.path940};941}942943protected convertImplementationToDto(x: DebugAdapterInlineImplementation): IDebugAdapterImpl {944return {945type: 'implementation',946};947}948949private getAdapterDescriptorFactoryByType(type: string): vscode.DebugAdapterDescriptorFactory | undefined {950const results = this._adapterFactories.filter(p => p.type === type);951if (results.length > 0) {952return results[0].factory;953}954return undefined;955}956957private getAdapterDescriptorFactoryByHandle(handle: number): vscode.DebugAdapterDescriptorFactory | undefined {958const results = this._adapterFactories.filter(p => p.handle === handle);959if (results.length > 0) {960return results[0].factory;961}962return undefined;963}964965private getConfigProviderByHandle(handle: number): vscode.DebugConfigurationProvider | undefined {966const results = this._configProviders.filter(p => p.handle === handle);967if (results.length > 0) {968return results[0].provider;969}970return undefined;971}972973private definesDebugType(ed: IExtensionDescription, type: string) {974if (ed.contributes) {975const debuggers = ed.contributes['debuggers'];976if (debuggers && debuggers.length > 0) {977for (const dbg of debuggers) {978// only debugger contributions with a "label" are considered a "defining" debugger contribution979if (dbg.label && dbg.type) {980if (dbg.type === type) {981return true;982}983}984}985}986}987return false;988}989990private getDebugAdapterTrackers(session: ExtHostDebugSession): Promise<vscode.DebugAdapterTracker | undefined> {991992const config = session.configuration;993const type = config.type;994995const promises = this._trackerFactories996.filter(tuple => tuple.type === type || tuple.type === '*')997.map(tuple => asPromise<vscode.ProviderResult<vscode.DebugAdapterTracker>>(() => tuple.factory.createDebugAdapterTracker(session.api)).then(p => p, err => null));998999return Promise.race([1000Promise.all(promises).then(result => {1001const trackers = coalesce(result); // filter null1002if (trackers.length > 0) {1003return new MultiTracker(trackers);1004}1005return undefined;1006}),1007new Promise<undefined>(resolve => setTimeout(() => resolve(undefined), 1000)),1008]).catch(err => {1009// ignore errors1010return undefined;1011});1012}10131014private async getAdapterDescriptor(adapterDescriptorFactory: vscode.DebugAdapterDescriptorFactory | undefined, session: ExtHostDebugSession): Promise<vscode.DebugAdapterDescriptor | undefined> {10151016// a "debugServer" attribute in the launch config takes precedence1017const serverPort = session.configuration.debugServer;1018if (typeof serverPort === 'number') {1019return Promise.resolve(new DebugAdapterServer(serverPort));1020}10211022if (adapterDescriptorFactory) {1023const extensionRegistry = await this._extensionService.getExtensionRegistry();1024return asPromise(() => adapterDescriptorFactory.createDebugAdapterDescriptor(session.api, this.daExecutableFromPackage(session, extensionRegistry))).then(daDescriptor => {1025if (daDescriptor) {1026return daDescriptor;1027}1028return undefined;1029});1030}10311032// fallback: use executable information from package.json1033const extensionRegistry = await this._extensionService.getExtensionRegistry();1034return Promise.resolve(this.daExecutableFromPackage(session, extensionRegistry));1035}10361037protected daExecutableFromPackage(session: ExtHostDebugSession, extensionRegistry: ExtensionDescriptionRegistry): DebugAdapterExecutable | undefined {1038return undefined;1039}10401041private fireBreakpointChanges(added: vscode.Breakpoint[], removed: vscode.Breakpoint[], changed: vscode.Breakpoint[]) {1042if (added.length > 0 || removed.length > 0 || changed.length > 0) {1043this._onDidChangeBreakpoints.fire(Object.freeze({1044added,1045removed,1046changed,1047}));1048}1049}10501051private async getSession(dto: IDebugSessionDto): Promise<ExtHostDebugSession> {1052if (dto) {1053if (typeof dto === 'string') {1054const ds = this._debugSessions.get(dto);1055if (ds) {1056return ds;1057}1058} else {1059let ds = this._debugSessions.get(dto.id);1060if (!ds) {1061const folder = await this.getFolder(dto.folderUri);1062const parent = dto.parent ? this._debugSessions.get(dto.parent) : undefined;1063ds = new ExtHostDebugSession(this._debugServiceProxy, dto.id, dto.type, dto.name, folder, dto.configuration, parent?.api);1064this._debugSessions.set(ds.id, ds);1065this._debugServiceProxy.$sessionCached(ds.id);1066}1067return ds;1068}1069}1070throw new Error('cannot find session');1071}10721073private getFolder(_folderUri: UriComponents | undefined): Promise<vscode.WorkspaceFolder | undefined> {1074if (_folderUri) {1075const folderURI = URI.revive(_folderUri);1076return this._workspaceService.resolveWorkspaceFolder(folderURI);1077}1078return Promise.resolve(undefined);1079}10801081private extensionVisKey(extensionId: string, id: string) {1082return `${extensionId}\0${id}`;1083}10841085private serializeVisualization(extensionId: string, viz: vscode.DebugVisualization['visualization']): MainThreadDebugVisualization | undefined {1086if (!viz) {1087return undefined;1088}10891090if ('title' in viz && 'command' in viz) {1091return { type: DebugVisualizationType.Command };1092}10931094if ('treeId' in viz) {1095return { type: DebugVisualizationType.Tree, id: `${extensionId}\0${viz.treeId}` };1096}10971098throw new Error('Unsupported debug visualization type');1099}11001101private getIconPathOrClass(icon: vscode.DebugVisualization['iconPath']) {1102const iconPathOrIconClass = this.getIconUris(icon);1103let iconPath: { dark: URI; light?: URI | undefined } | undefined;1104let iconClass: string | undefined;1105if ('id' in iconPathOrIconClass) {1106iconClass = ThemeIconUtils.asClassName(iconPathOrIconClass);1107} else {1108iconPath = iconPathOrIconClass;1109}11101111return {1112iconPath,1113iconClass1114};1115}11161117private getIconUris(iconPath: vscode.DebugVisualization['iconPath']): { dark: URI; light?: URI } | { id: string } {1118if (iconPath instanceof ThemeIcon) {1119return { id: iconPath.id };1120}1121const dark = typeof iconPath === 'object' && 'dark' in iconPath ? iconPath.dark : iconPath;1122const light = typeof iconPath === 'object' && 'light' in iconPath ? iconPath.light : iconPath;1123return {1124dark: (typeof dark === 'string' ? URI.file(dark) : dark) as URI,1125light: (typeof light === 'string' ? URI.file(light) : light) as URI,1126};1127}1128}11291130export class ExtHostDebugSession {1131private apiSession?: vscode.DebugSession;1132constructor(1133private _debugServiceProxy: MainThreadDebugServiceShape,1134private _id: DebugSessionUUID,1135private _type: string,1136private _name: string,1137private _workspaceFolder: vscode.WorkspaceFolder | undefined,1138private _configuration: vscode.DebugConfiguration,1139private _parentSession: vscode.DebugSession | undefined) {1140}11411142public get api(): vscode.DebugSession {1143const that = this;1144return this.apiSession ??= Object.freeze({1145id: that._id,1146type: that._type,1147get name() {1148return that._name;1149},1150set name(name: string) {1151that._name = name;1152that._debugServiceProxy.$setDebugSessionName(that._id, name);1153},1154parentSession: that._parentSession,1155workspaceFolder: that._workspaceFolder,1156configuration: that._configuration,1157customRequest(command: string, args: any): Promise<any> {1158return that._debugServiceProxy.$customDebugAdapterRequest(that._id, command, args);1159},1160getDebugProtocolBreakpoint(breakpoint: vscode.Breakpoint): Promise<vscode.DebugProtocolBreakpoint | undefined> {1161return that._debugServiceProxy.$getDebugProtocolBreakpoint(that._id, breakpoint.id);1162}1163});1164}11651166public get id(): string {1167return this._id;1168}11691170public get type(): string {1171return this._type;1172}11731174_acceptNameChanged(name: string) {1175this._name = name;1176}11771178public get configuration(): vscode.DebugConfiguration {1179return this._configuration;1180}1181}11821183export class ExtHostDebugConsole {11841185readonly value: vscode.DebugConsole;11861187constructor(proxy: MainThreadDebugServiceShape) {11881189this.value = Object.freeze({1190append(value: string): void {1191proxy.$appendDebugConsole(value);1192},1193appendLine(value: string): void {1194this.append(value + '\n');1195}1196});1197}1198}11991200interface ConfigProviderTuple {1201type: string;1202handle: number;1203provider: vscode.DebugConfigurationProvider;1204}12051206interface DescriptorFactoryTuple {1207type: string;1208handle: number;1209factory: vscode.DebugAdapterDescriptorFactory;1210}12111212interface TrackerFactoryTuple {1213type: string;1214handle: number;1215factory: vscode.DebugAdapterTrackerFactory;1216}12171218class MultiTracker implements vscode.DebugAdapterTracker {12191220constructor(private trackers: vscode.DebugAdapterTracker[]) {1221}12221223onWillStartSession(): void {1224this.trackers.forEach(t => t.onWillStartSession ? t.onWillStartSession() : undefined);1225}12261227onWillReceiveMessage(message: any): void {1228this.trackers.forEach(t => t.onWillReceiveMessage ? t.onWillReceiveMessage(message) : undefined);1229}12301231onDidSendMessage(message: any): void {1232this.trackers.forEach(t => t.onDidSendMessage ? t.onDidSendMessage(message) : undefined);1233}12341235onWillStopSession(): void {1236this.trackers.forEach(t => t.onWillStopSession ? t.onWillStopSession() : undefined);1237}12381239onError(error: Error): void {1240this.trackers.forEach(t => t.onError ? t.onError(error) : undefined);1241}12421243onExit(code: number, signal: string): void {1244this.trackers.forEach(t => t.onExit ? t.onExit(code, signal) : undefined);1245}1246}12471248/*1249* Call directly into a debug adapter implementation1250*/1251class DirectDebugAdapter extends AbstractDebugAdapter {12521253constructor(private implementation: vscode.DebugAdapter) {1254super();12551256implementation.onDidSendMessage((message: vscode.DebugProtocolMessage) => {1257this.acceptMessage(message as DebugProtocol.ProtocolMessage);1258});1259}12601261startSession(): Promise<void> {1262return Promise.resolve(undefined);1263}12641265sendMessage(message: DebugProtocol.ProtocolMessage): void {1266this.implementation.handleMessage(message);1267}12681269stopSession(): Promise<void> {1270this.implementation.dispose();1271return Promise.resolve(undefined);1272}1273}127412751276export class WorkerExtHostDebugService extends ExtHostDebugServiceBase {1277constructor(1278@IExtHostRpcService extHostRpcService: IExtHostRpcService,1279@IExtHostWorkspace workspaceService: IExtHostWorkspace,1280@IExtHostExtensionService extensionService: IExtHostExtensionService,1281@IExtHostConfiguration configurationService: IExtHostConfiguration,1282@IExtHostEditorTabs editorTabs: IExtHostEditorTabs,1283@IExtHostVariableResolverProvider variableResolver: IExtHostVariableResolverProvider,1284@IExtHostCommands commands: IExtHostCommands,1285@IExtHostTesting testing: IExtHostTesting,1286) {1287super(extHostRpcService, workspaceService, extensionService, configurationService, editorTabs, variableResolver, commands, testing);1288}1289}12901291// Collecting info for #233167 specifically1292type DebugProtocolMessageErrorClassification = {1293from: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The type of the debug adapter that the event is from.' };1294type: { classification: 'SystemMetaData'; purpose: 'PerformanceAndHealth'; comment: 'The type of the event that was malformed.' };1295owner: 'roblourens';1296comment: 'Sent to collect details about misbehaving debug extensions.';1297};12981299type DebugProtocolMessageErrorEvent = {1300from: string;1301type: string;1302};130313041305