Path: blob/main/src/vs/workbench/contrib/debug/common/debugViewModel.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 { Emitter, Event } from '../../../../base/common/event.js';6import { IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';7import { CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED, CONTEXT_EXPRESSION_SELECTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG, CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_LOADED_SCRIPTS_SUPPORTED, CONTEXT_MULTI_SESSION_DEBUG, CONTEXT_RESTART_FRAME_SUPPORTED, CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED, CONTEXT_SET_EXPRESSION_SUPPORTED, CONTEXT_SET_VARIABLE_SUPPORTED, CONTEXT_STEP_BACK_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED, CONTEXT_TERMINATE_THREADS_SUPPORTED, IDebugSession, IExpression, IExpressionContainer, IStackFrame, IThread, IViewModel } from './debug.js';8import { isSessionAttach } from './debugUtils.js';910export class ViewModel implements IViewModel {1112firstSessionStart = true;1314private _focusedStackFrame: IStackFrame | undefined;15private _focusedSession: IDebugSession | undefined;16private _focusedThread: IThread | undefined;17private selectedExpression: { expression: IExpression; settingWatch: boolean } | undefined;18private readonly _onDidFocusSession = new Emitter<IDebugSession | undefined>();19private readonly _onDidFocusThread = new Emitter<{ thread: IThread | undefined; explicit: boolean; session: IDebugSession | undefined }>();20private readonly _onDidFocusStackFrame = new Emitter<{ stackFrame: IStackFrame | undefined; explicit: boolean; session: IDebugSession | undefined }>();21private readonly _onDidSelectExpression = new Emitter<{ expression: IExpression; settingWatch: boolean } | undefined>();22private readonly _onDidEvaluateLazyExpression = new Emitter<IExpressionContainer>();23private readonly _onWillUpdateViews = new Emitter<void>();24private readonly _onDidChangeVisualization = new Emitter<{ original: IExpression; replacement: IExpression }>();25private readonly visualized = new WeakMap<IExpression, IExpression>();26private readonly preferredVisualizers = new Map</** cache key */ string, /* tree ID */ string>();27private expressionSelectedContextKey!: IContextKey<boolean>;28private loadedScriptsSupportedContextKey!: IContextKey<boolean>;29private stepBackSupportedContextKey!: IContextKey<boolean>;30private focusedSessionIsAttach!: IContextKey<boolean>;31private focusedSessionIsNoDebug!: IContextKey<boolean>;32private restartFrameSupportedContextKey!: IContextKey<boolean>;33private stepIntoTargetsSupported!: IContextKey<boolean>;34private jumpToCursorSupported!: IContextKey<boolean>;35private setVariableSupported!: IContextKey<boolean>;36private setDataBreakpointAtByteSupported!: IContextKey<boolean>;37private setExpressionSupported!: IContextKey<boolean>;38private multiSessionDebug!: IContextKey<boolean>;39private terminateDebuggeeSupported!: IContextKey<boolean>;40private suspendDebuggeeSupported!: IContextKey<boolean>;41private terminateThreadsSupported!: IContextKey<boolean>;42private disassembleRequestSupported!: IContextKey<boolean>;43private focusedStackFrameHasInstructionPointerReference!: IContextKey<boolean>;4445constructor(private contextKeyService: IContextKeyService) {46contextKeyService.bufferChangeEvents(() => {47this.expressionSelectedContextKey = CONTEXT_EXPRESSION_SELECTED.bindTo(contextKeyService);48this.loadedScriptsSupportedContextKey = CONTEXT_LOADED_SCRIPTS_SUPPORTED.bindTo(contextKeyService);49this.stepBackSupportedContextKey = CONTEXT_STEP_BACK_SUPPORTED.bindTo(contextKeyService);50this.focusedSessionIsAttach = CONTEXT_FOCUSED_SESSION_IS_ATTACH.bindTo(contextKeyService);51this.focusedSessionIsNoDebug = CONTEXT_FOCUSED_SESSION_IS_NO_DEBUG.bindTo(contextKeyService);52this.restartFrameSupportedContextKey = CONTEXT_RESTART_FRAME_SUPPORTED.bindTo(contextKeyService);53this.stepIntoTargetsSupported = CONTEXT_STEP_INTO_TARGETS_SUPPORTED.bindTo(contextKeyService);54this.jumpToCursorSupported = CONTEXT_JUMP_TO_CURSOR_SUPPORTED.bindTo(contextKeyService);55this.setVariableSupported = CONTEXT_SET_VARIABLE_SUPPORTED.bindTo(contextKeyService);56this.setDataBreakpointAtByteSupported = CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED.bindTo(contextKeyService);57this.setExpressionSupported = CONTEXT_SET_EXPRESSION_SUPPORTED.bindTo(contextKeyService);58this.multiSessionDebug = CONTEXT_MULTI_SESSION_DEBUG.bindTo(contextKeyService);59this.terminateDebuggeeSupported = CONTEXT_TERMINATE_DEBUGGEE_SUPPORTED.bindTo(contextKeyService);60this.suspendDebuggeeSupported = CONTEXT_SUSPEND_DEBUGGEE_SUPPORTED.bindTo(contextKeyService);61this.terminateThreadsSupported = CONTEXT_TERMINATE_THREADS_SUPPORTED.bindTo(contextKeyService);62this.disassembleRequestSupported = CONTEXT_DISASSEMBLE_REQUEST_SUPPORTED.bindTo(contextKeyService);63this.focusedStackFrameHasInstructionPointerReference = CONTEXT_FOCUSED_STACK_FRAME_HAS_INSTRUCTION_POINTER_REFERENCE.bindTo(contextKeyService);64});65}6667getId(): string {68return 'root';69}7071get focusedSession(): IDebugSession | undefined {72return this._focusedSession;73}7475get focusedThread(): IThread | undefined {76return this._focusedThread;77}7879get focusedStackFrame(): IStackFrame | undefined {80return this._focusedStackFrame;81}8283setFocus(stackFrame: IStackFrame | undefined, thread: IThread | undefined, session: IDebugSession | undefined, explicit: boolean): void {84const shouldEmitForStackFrame = this._focusedStackFrame !== stackFrame;85const shouldEmitForSession = this._focusedSession !== session;86const shouldEmitForThread = this._focusedThread !== thread;878889this._focusedStackFrame = stackFrame;90this._focusedThread = thread;91this._focusedSession = session;9293this.contextKeyService.bufferChangeEvents(() => {94this.loadedScriptsSupportedContextKey.set(!!session?.capabilities.supportsLoadedSourcesRequest);95this.stepBackSupportedContextKey.set(!!session?.capabilities.supportsStepBack);96this.restartFrameSupportedContextKey.set(!!session?.capabilities.supportsRestartFrame);97this.stepIntoTargetsSupported.set(!!session?.capabilities.supportsStepInTargetsRequest);98this.jumpToCursorSupported.set(!!session?.capabilities.supportsGotoTargetsRequest);99this.setVariableSupported.set(!!session?.capabilities.supportsSetVariable);100this.setDataBreakpointAtByteSupported.set(!!session?.capabilities.supportsDataBreakpointBytes);101this.setExpressionSupported.set(!!session?.capabilities.supportsSetExpression);102this.terminateDebuggeeSupported.set(!!session?.capabilities.supportTerminateDebuggee);103this.suspendDebuggeeSupported.set(!!session?.capabilities.supportSuspendDebuggee);104this.terminateThreadsSupported.set(!!session?.capabilities.supportsTerminateThreadsRequest);105this.disassembleRequestSupported.set(!!session?.capabilities.supportsDisassembleRequest);106this.focusedStackFrameHasInstructionPointerReference.set(!!stackFrame?.instructionPointerReference);107const attach = !!session && isSessionAttach(session);108this.focusedSessionIsAttach.set(attach);109this.focusedSessionIsNoDebug.set(!!session && !!session.configuration.noDebug);110});111112if (shouldEmitForSession) {113this._onDidFocusSession.fire(session);114}115116// should not call onDidFocusThread if onDidFocusStackFrame is called.117if (shouldEmitForStackFrame) {118this._onDidFocusStackFrame.fire({ stackFrame, explicit, session });119} else if (shouldEmitForThread) {120this._onDidFocusThread.fire({ thread, explicit, session });121}122}123124get onDidFocusSession(): Event<IDebugSession | undefined> {125return this._onDidFocusSession.event;126}127128get onDidFocusThread(): Event<{ thread: IThread | undefined; explicit: boolean; session: IDebugSession | undefined }> {129return this._onDidFocusThread.event;130}131132get onDidFocusStackFrame(): Event<{ stackFrame: IStackFrame | undefined; explicit: boolean; session: IDebugSession | undefined }> {133return this._onDidFocusStackFrame.event;134}135136get onDidChangeVisualization() {137return this._onDidChangeVisualization.event;138}139140getSelectedExpression(): { expression: IExpression; settingWatch: boolean } | undefined {141return this.selectedExpression;142}143144setSelectedExpression(expression: IExpression | undefined, settingWatch: boolean) {145this.selectedExpression = expression ? { expression, settingWatch: settingWatch } : undefined;146this.expressionSelectedContextKey.set(!!expression);147this._onDidSelectExpression.fire(this.selectedExpression);148}149150get onDidSelectExpression(): Event<{ expression: IExpression; settingWatch: boolean } | undefined> {151return this._onDidSelectExpression.event;152}153154get onDidEvaluateLazyExpression(): Event<IExpressionContainer> {155return this._onDidEvaluateLazyExpression.event;156}157158updateViews(): void {159this._onWillUpdateViews.fire();160}161162get onWillUpdateViews(): Event<void> {163return this._onWillUpdateViews.event;164}165166isMultiSessionView(): boolean {167return !!this.multiSessionDebug.get();168}169170setMultiSessionView(isMultiSessionView: boolean): void {171this.multiSessionDebug.set(isMultiSessionView);172}173174setVisualizedExpression(original: IExpression, visualized: IExpression & { treeId: string } | undefined): void {175const current = this.visualized.get(original) || original;176const key = this.getPreferredVisualizedKey(original);177if (visualized) {178this.visualized.set(original, visualized);179this.preferredVisualizers.set(key, visualized.treeId);180} else {181this.visualized.delete(original);182this.preferredVisualizers.delete(key);183}184this._onDidChangeVisualization.fire({ original: current, replacement: visualized || original });185}186187getVisualizedExpression(expression: IExpression): IExpression | string | undefined {188return this.visualized.get(expression) || this.preferredVisualizers.get(this.getPreferredVisualizedKey(expression));189}190191async evaluateLazyExpression(expression: IExpressionContainer): Promise<void> {192await expression.evaluateLazy();193this._onDidEvaluateLazyExpression.fire(expression);194}195196private getPreferredVisualizedKey(expr: IExpression) {197return JSON.stringify([198expr.name,199expr.type,200!!expr.memoryReference,201].join('\0'));202}203}204205206