Path: blob/main/src/vs/workbench/contrib/debug/browser/debugCommands.ts
5237 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 { getWindowId } from '../../../../base/browser/dom.js';6import { List } from '../../../../base/browser/ui/list/listWidget.js';7import { mainWindow } from '../../../../base/browser/window.js';8import { KeyCode, KeyMod } from '../../../../base/common/keyCodes.js';9import { DisposableStore } from '../../../../base/common/lifecycle.js';10import { deepClone } from '../../../../base/common/objects.js';11import { isWeb, isWindows } from '../../../../base/common/platform.js';12import { ICodeEditor, isCodeEditor } from '../../../../editor/browser/editorBrowser.js';13import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';14import { EditorContextKeys } from '../../../../editor/common/editorContextKeys.js';15import { ITextResourcePropertiesService } from '../../../../editor/common/services/textResourceConfiguration.js';16import * as nls from '../../../../nls.js';17import { ILocalizedString } from '../../../../platform/action/common/action.js';18import { Action2, MenuId, MenuRegistry, registerAction2 } from '../../../../platform/actions/common/actions.js';19import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js';20import { CommandsRegistry, ICommandService } from '../../../../platform/commands/common/commands.js';21import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';22import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';23import { InputFocusedContext } from '../../../../platform/contextkey/common/contextkeys.js';24import { IExtensionHostDebugService } from '../../../../platform/debug/common/extensionHostDebug.js';25import { IEnvironmentService } from '../../../../platform/environment/common/environment.js';26import { KeybindingsRegistry, KeybindingWeight } from '../../../../platform/keybinding/common/keybindingsRegistry.js';27import { IListService } from '../../../../platform/list/browser/listService.js';28import { INotificationService } from '../../../../platform/notification/common/notification.js';29import { IQuickInputService, IQuickPickItem } from '../../../../platform/quickinput/common/quickInput.js';30import { ActiveEditorContext, PanelFocusContext, ResourceContextKey } from '../../../common/contextkeys.js';31import { ViewContainerLocation } from '../../../common/views.js';32import { IEditorService } from '../../../services/editor/common/editorService.js';33import { IPaneCompositePartService } from '../../../services/panecomposite/browser/panecomposite.js';34import { IViewsService } from '../../../services/views/common/viewsService.js';35import { ChatContextKeys } from '../../chat/common/actions/chatContextKeys.js';36import { IExtensionsWorkbenchService } from '../../extensions/common/extensions.js';37import { TEXT_FILE_EDITOR_ID } from '../../files/common/files.js';38import { CONTEXT_BREAKPOINT_INPUT_FOCUSED, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_DEBUG_STATE, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DISASSEMBLY_VIEW_FOCUS, CONTEXT_EXPRESSION_SELECTED, CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_REPL, CONTEXT_JUMP_TO_CURSOR_SUPPORTED, CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_VARIABLES_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, DataBreakpointSetType, EDITOR_CONTRIBUTION_ID, getStateLabel, IConfig, IDataBreakpointInfoResponse, IDebugConfiguration, IDebugEditorContribution, IDebugService, IDebugSession, IEnablement, IExceptionBreakpoint, isFrameDeemphasized, IStackFrame, IThread, REPL_VIEW_ID, State, VIEWLET_ID } from '../common/debug.js';39import { Breakpoint, DataBreakpoint, Expression, FunctionBreakpoint, Thread, Variable } from '../common/debugModel.js';40import { saveAllBeforeDebugStart, resolveChildSession } from '../common/debugUtils.js';41import { showLoadedScriptMenu } from '../common/loadedScriptsPicker.js';42import { openBreakpointSource } from './breakpointsView.js';43import { showDebugSessionMenu } from './debugSessionPicker.js';4445export const ADD_CONFIGURATION_ID = 'debug.addConfiguration';46export const COPY_ADDRESS_ID = 'editor.debug.action.copyAddress';47export const TOGGLE_BREAKPOINT_ID = 'editor.debug.action.toggleBreakpoint';48export const TOGGLE_INLINE_BREAKPOINT_ID = 'editor.debug.action.toggleInlineBreakpoint';49export const COPY_STACK_TRACE_ID = 'debug.copyStackTrace';50export const REVERSE_CONTINUE_ID = 'workbench.action.debug.reverseContinue';51export const STEP_BACK_ID = 'workbench.action.debug.stepBack';52export const RESTART_SESSION_ID = 'workbench.action.debug.restart';53export const TERMINATE_THREAD_ID = 'workbench.action.debug.terminateThread';54export const STEP_OVER_ID = 'workbench.action.debug.stepOver';55export const STEP_INTO_ID = 'workbench.action.debug.stepInto';56export const STEP_INTO_TARGET_ID = 'workbench.action.debug.stepIntoTarget';57export const STEP_OUT_ID = 'workbench.action.debug.stepOut';58export const PAUSE_ID = 'workbench.action.debug.pause';59export const DISCONNECT_ID = 'workbench.action.debug.disconnect';60export const DISCONNECT_AND_SUSPEND_ID = 'workbench.action.debug.disconnectAndSuspend';61export const STOP_ID = 'workbench.action.debug.stop';62export const RESTART_FRAME_ID = 'workbench.action.debug.restartFrame';63export const CONTINUE_ID = 'workbench.action.debug.continue';64export const FOCUS_REPL_ID = 'workbench.debug.action.focusRepl';65export const JUMP_TO_CURSOR_ID = 'debug.jumpToCursor';66export const FOCUS_SESSION_ID = 'workbench.action.debug.focusProcess';67export const SELECT_AND_START_ID = 'workbench.action.debug.selectandstart';68export const SELECT_DEBUG_CONSOLE_ID = 'workbench.action.debug.selectDebugConsole';69export const SELECT_DEBUG_SESSION_ID = 'workbench.action.debug.selectDebugSession';70export const DEBUG_CONFIGURE_COMMAND_ID = 'workbench.action.debug.configure';71export const DEBUG_START_COMMAND_ID = 'workbench.action.debug.start';72export const DEBUG_RUN_COMMAND_ID = 'workbench.action.debug.run';73export const EDIT_EXPRESSION_COMMAND_ID = 'debug.renameWatchExpression';74export const COPY_WATCH_EXPRESSION_COMMAND_ID = 'debug.copyWatchExpression';75export const SET_EXPRESSION_COMMAND_ID = 'debug.setWatchExpression';76export const REMOVE_EXPRESSION_COMMAND_ID = 'debug.removeWatchExpression';77export const NEXT_DEBUG_CONSOLE_ID = 'workbench.action.debug.nextConsole';78export const PREV_DEBUG_CONSOLE_ID = 'workbench.action.debug.prevConsole';79export const SHOW_LOADED_SCRIPTS_ID = 'workbench.action.debug.showLoadedScripts';80export const CALLSTACK_TOP_ID = 'workbench.action.debug.callStackTop';81export const CALLSTACK_BOTTOM_ID = 'workbench.action.debug.callStackBottom';82export const CALLSTACK_UP_ID = 'workbench.action.debug.callStackUp';83export const CALLSTACK_DOWN_ID = 'workbench.action.debug.callStackDown';84export const ADD_TO_WATCH_ID = 'debug.addToWatchExpressions';85export const COPY_EVALUATE_PATH_ID = 'debug.copyEvaluatePath';86export const COPY_VALUE_ID = 'workbench.debug.viewlet.action.copyValue';87export const BREAK_WHEN_VALUE_CHANGES_ID = 'debug.breakWhenValueChanges';88export const BREAK_WHEN_VALUE_IS_ACCESSED_ID = 'debug.breakWhenValueIsAccessed';89export const BREAK_WHEN_VALUE_IS_READ_ID = 'debug.breakWhenValueIsRead';90export const TOGGLE_EXCEPTION_BREAKPOINTS_ID = 'debug.toggleExceptionBreakpoints';91export const ATTACH_TO_CURRENT_CODE_RENDERER = 'debug.attachToCurrentCodeRenderer';9293export const DEBUG_COMMAND_CATEGORY: ILocalizedString = nls.localize2('debug', 'Debug');94export const RESTART_LABEL = nls.localize2('restartDebug', "Restart");95export const STEP_OVER_LABEL = nls.localize2('stepOverDebug', "Step Over");96export const STEP_INTO_LABEL = nls.localize2('stepIntoDebug', "Step Into");97export const STEP_INTO_TARGET_LABEL = nls.localize2('stepIntoTargetDebug', "Step Into Target");98export const STEP_OUT_LABEL = nls.localize2('stepOutDebug', "Step Out");99export const PAUSE_LABEL = nls.localize2('pauseDebug', "Pause");100export const DISCONNECT_LABEL = nls.localize2('disconnect', "Disconnect");101export const DISCONNECT_AND_SUSPEND_LABEL = nls.localize2('disconnectSuspend', "Disconnect and Suspend");102export const STOP_LABEL = nls.localize2('stop', "Stop");103export const CONTINUE_LABEL = nls.localize2('continueDebug', "Continue");104export const FOCUS_SESSION_LABEL = nls.localize2('focusSession', "Focus Session");105export const SELECT_AND_START_LABEL = nls.localize2('selectAndStartDebugging', "Select and Start Debugging");106export const DEBUG_CONFIGURE_LABEL = nls.localize('openLaunchJson', "Open '{0}'", 'launch.json');107export const DEBUG_START_LABEL = nls.localize2('startDebug', "Start Debugging");108export const DEBUG_RUN_LABEL = nls.localize2('startWithoutDebugging', "Start Without Debugging");109export const NEXT_DEBUG_CONSOLE_LABEL = nls.localize2('nextDebugConsole', "Focus Next Debug Console");110export const PREV_DEBUG_CONSOLE_LABEL = nls.localize2('prevDebugConsole', "Focus Previous Debug Console");111export const OPEN_LOADED_SCRIPTS_LABEL = nls.localize2('openLoadedScript', "Open Loaded Script...");112export const CALLSTACK_TOP_LABEL = nls.localize2('callStackTop', "Navigate to Top of Call Stack");113export const CALLSTACK_BOTTOM_LABEL = nls.localize2('callStackBottom', "Navigate to Bottom of Call Stack");114export const CALLSTACK_UP_LABEL = nls.localize2('callStackUp', "Navigate Up Call Stack");115export const CALLSTACK_DOWN_LABEL = nls.localize2('callStackDown', "Navigate Down Call Stack");116export const COPY_EVALUATE_PATH_LABEL = nls.localize2('copyAsExpression', "Copy as Expression");117export const COPY_VALUE_LABEL = nls.localize2('copyValue', "Copy Value");118export const COPY_ADDRESS_LABEL = nls.localize2('copyAddress', "Copy Address");119export const ADD_TO_WATCH_LABEL = nls.localize2('addToWatchExpressions', "Add to Watch");120121export const SELECT_DEBUG_CONSOLE_LABEL = nls.localize2('selectDebugConsole', "Select Debug Console");122export const SELECT_DEBUG_SESSION_LABEL = nls.localize2('selectDebugSession', "Select Debug Session");123124export const DEBUG_QUICK_ACCESS_PREFIX = 'debug ';125export const DEBUG_CONSOLE_QUICK_ACCESS_PREFIX = 'debug consoles ';126127let dataBreakpointInfoResponse: IDataBreakpointInfoResponse | undefined;128129export function setDataBreakpointInfoResponse(resp: IDataBreakpointInfoResponse | undefined) {130dataBreakpointInfoResponse = resp;131}132133interface CallStackContext {134sessionId: string;135threadId: string;136frameId: string;137}138139function isThreadContext(obj: any): obj is CallStackContext {140return obj && typeof obj.sessionId === 'string' && typeof obj.threadId === 'string';141}142143async function getThreadAndRun(accessor: ServicesAccessor, sessionAndThreadId: CallStackContext | unknown, run: (thread: IThread) => Promise<void>): Promise<void> {144const debugService = accessor.get(IDebugService);145let thread: IThread | undefined;146if (isThreadContext(sessionAndThreadId)) {147const session = debugService.getModel().getSession(sessionAndThreadId.sessionId);148if (session) {149thread = session.getAllThreads().find(t => t.getId() === sessionAndThreadId.threadId);150}151} else if (isSessionContext(sessionAndThreadId)) {152const session = debugService.getModel().getSession(sessionAndThreadId.sessionId);153if (session) {154const threads = session.getAllThreads();155thread = threads.length > 0 ? threads[0] : undefined;156}157}158159if (!thread) {160thread = debugService.getViewModel().focusedThread;161if (!thread) {162const focusedSession = debugService.getViewModel().focusedSession;163const threads = focusedSession ? focusedSession.getAllThreads() : undefined;164thread = threads && threads.length ? threads[0] : undefined;165}166}167168if (thread) {169await run(thread);170}171}172173function isStackFrameContext(obj: any): obj is CallStackContext {174return obj && typeof obj.sessionId === 'string' && typeof obj.threadId === 'string' && typeof obj.frameId === 'string';175}176177function getFrame(debugService: IDebugService, context: CallStackContext | unknown): IStackFrame | undefined {178if (isStackFrameContext(context)) {179const session = debugService.getModel().getSession(context.sessionId);180if (session) {181const thread = session.getAllThreads().find(t => t.getId() === context.threadId);182if (thread) {183return thread.getCallStack().find(sf => sf.getId() === context.frameId);184}185}186} else {187return debugService.getViewModel().focusedStackFrame;188}189190return undefined;191}192193function isSessionContext(obj: any): obj is CallStackContext {194return obj && typeof obj.sessionId === 'string';195}196197async function changeDebugConsoleFocus(accessor: ServicesAccessor, next: boolean) {198const debugService = accessor.get(IDebugService);199const viewsService = accessor.get(IViewsService);200const sessions = debugService.getModel().getSessions(true).filter(s => s.hasSeparateRepl());201let currSession = debugService.getViewModel().focusedSession;202203let nextIndex = 0;204if (sessions.length > 0 && currSession) {205while (currSession && !currSession.hasSeparateRepl()) {206currSession = currSession.parentSession;207}208209if (currSession) {210const currIndex = sessions.indexOf(currSession);211if (next) {212nextIndex = (currIndex === (sessions.length - 1) ? 0 : (currIndex + 1));213} else {214nextIndex = (currIndex === 0 ? (sessions.length - 1) : (currIndex - 1));215}216}217}218await debugService.focusStackFrame(undefined, undefined, sessions[nextIndex], { explicit: true });219220if (!viewsService.isViewVisible(REPL_VIEW_ID)) {221await viewsService.openView(REPL_VIEW_ID, true);222}223}224225async function navigateCallStack(debugService: IDebugService, down: boolean) {226const frame = debugService.getViewModel().focusedStackFrame;227if (frame) {228229let callStack = frame.thread.getCallStack();230let index = callStack.findIndex(elem => elem.frameId === frame.frameId);231let nextVisibleFrame;232if (down) {233if (index >= callStack.length - 1) {234if ((<Thread>frame.thread).reachedEndOfCallStack) {235goToTopOfCallStack(debugService);236return;237} else {238await debugService.getModel().fetchCallstack(frame.thread, 20);239callStack = frame.thread.getCallStack();240index = callStack.findIndex(elem => elem.frameId === frame.frameId);241}242}243nextVisibleFrame = findNextVisibleFrame(true, callStack, index);244} else {245if (index <= 0) {246goToBottomOfCallStack(debugService);247return;248}249nextVisibleFrame = findNextVisibleFrame(false, callStack, index);250}251252if (nextVisibleFrame) {253debugService.focusStackFrame(nextVisibleFrame, undefined, undefined, { preserveFocus: false });254}255}256}257258async function goToBottomOfCallStack(debugService: IDebugService) {259const thread = debugService.getViewModel().focusedThread;260if (thread) {261await debugService.getModel().fetchCallstack(thread);262const callStack = thread.getCallStack();263if (callStack.length > 0) {264const nextVisibleFrame = findNextVisibleFrame(false, callStack, 0); // must consider the next frame up first, which will be the last frame265if (nextVisibleFrame) {266debugService.focusStackFrame(nextVisibleFrame, undefined, undefined, { preserveFocus: false });267}268}269}270}271272function goToTopOfCallStack(debugService: IDebugService) {273const thread = debugService.getViewModel().focusedThread;274275if (thread) {276debugService.focusStackFrame(thread.getTopStackFrame(), undefined, undefined, { preserveFocus: false });277}278}279280/**281* Finds next frame that is not skipped by SkipFiles. Skips frame at index and starts searching at next.282* Must satisfy `0 <= startIndex <= callStack - 1`283* @param down specifies whether to search downwards if the current file is skipped.284* @param callStack the call stack to search285* @param startIndex the index to start the search at286*/287function findNextVisibleFrame(down: boolean, callStack: readonly IStackFrame[], startIndex: number) {288289if (startIndex >= callStack.length) {290startIndex = callStack.length - 1;291} else if (startIndex < 0) {292startIndex = 0;293}294295let index = startIndex;296297let currFrame;298do {299if (down) {300if (index === callStack.length - 1) {301index = 0;302} else {303index++;304}305} else {306if (index === 0) {307index = callStack.length - 1;308} else {309index--;310}311}312313currFrame = callStack[index];314if (!isFrameDeemphasized(currFrame)) {315return currFrame;316}317} while (index !== startIndex); // end loop when we've just checked the start index, since that should be the last one checked318319return undefined;320}321322// These commands are used in call stack context menu, call stack inline actions, command palette, debug toolbar, mac native touch bar323// When the command is exectued in the context of a thread(context menu on a thread, inline call stack action) we pass the thread id324// Otherwise when it is executed "globaly"(using the touch bar, debug toolbar, command palette) we do not pass any id and just take whatever is the focussed thread325// Same for stackFrame commands and session commands.326CommandsRegistry.registerCommand({327id: COPY_STACK_TRACE_ID,328handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {329const textResourcePropertiesService = accessor.get(ITextResourcePropertiesService);330const clipboardService = accessor.get(IClipboardService);331const debugService = accessor.get(IDebugService);332const frame = getFrame(debugService, context);333if (frame) {334const eol = textResourcePropertiesService.getEOL(frame.source.uri);335await clipboardService.writeText(frame.thread.getCallStack().map(sf => sf.toString()).join(eol));336}337}338});339340CommandsRegistry.registerCommand({341id: REVERSE_CONTINUE_ID,342handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {343await getThreadAndRun(accessor, context, thread => thread.reverseContinue());344}345});346347CommandsRegistry.registerCommand({348id: STEP_BACK_ID,349handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {350const contextKeyService = accessor.get(IContextKeyService);351if (CONTEXT_DISASSEMBLY_VIEW_FOCUS.getValue(contextKeyService)) {352await getThreadAndRun(accessor, context, (thread: IThread) => thread.stepBack('instruction'));353} else {354await getThreadAndRun(accessor, context, (thread: IThread) => thread.stepBack());355}356}357});358359CommandsRegistry.registerCommand({360id: TERMINATE_THREAD_ID,361handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {362await getThreadAndRun(accessor, context, thread => thread.terminate());363}364});365366CommandsRegistry.registerCommand({367id: JUMP_TO_CURSOR_ID,368handler: async (accessor: ServicesAccessor) => {369const debugService = accessor.get(IDebugService);370const stackFrame = debugService.getViewModel().focusedStackFrame;371const editorService = accessor.get(IEditorService);372const activeEditorControl = editorService.activeTextEditorControl;373const notificationService = accessor.get(INotificationService);374const quickInputService = accessor.get(IQuickInputService);375376if (stackFrame && isCodeEditor(activeEditorControl) && activeEditorControl.hasModel()) {377const position = activeEditorControl.getPosition();378const resource = activeEditorControl.getModel().uri;379const source = stackFrame.thread.session.getSourceForUri(resource);380if (source) {381const response = await stackFrame.thread.session.gotoTargets(source.raw, position.lineNumber, position.column);382const targets = response?.body.targets;383if (targets && targets.length) {384let id = targets[0].id;385if (targets.length > 1) {386const picks = targets.map(t => ({ label: t.label, _id: t.id }));387const pick = await quickInputService.pick(picks, { placeHolder: nls.localize('chooseLocation', "Choose the specific location") });388if (!pick) {389return;390}391392id = pick._id;393}394395return await stackFrame.thread.session.goto(stackFrame.thread.threadId, id).catch(e => notificationService.warn(e));396}397}398}399400return notificationService.warn(nls.localize('noExecutableCode', "No executable code is associated at the current cursor position."));401}402});403404405CommandsRegistry.registerCommand({406id: CALLSTACK_TOP_ID,407handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {408const debugService = accessor.get(IDebugService);409goToTopOfCallStack(debugService);410}411});412413CommandsRegistry.registerCommand({414id: CALLSTACK_BOTTOM_ID,415handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {416const debugService = accessor.get(IDebugService);417await goToBottomOfCallStack(debugService);418}419});420421CommandsRegistry.registerCommand({422id: CALLSTACK_UP_ID,423handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {424const debugService = accessor.get(IDebugService);425navigateCallStack(debugService, false);426}427});428429CommandsRegistry.registerCommand({430id: CALLSTACK_DOWN_ID,431handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {432const debugService = accessor.get(IDebugService);433navigateCallStack(debugService, true);434}435});436437MenuRegistry.appendMenuItem(MenuId.EditorContext, {438command: {439id: JUMP_TO_CURSOR_ID,440title: nls.localize('jumpToCursor', "Jump to Cursor"),441category: DEBUG_COMMAND_CATEGORY442},443when: ContextKeyExpr.and(CONTEXT_JUMP_TO_CURSOR_SUPPORTED, EditorContextKeys.editorTextFocus),444group: 'debug',445order: 3446});447448KeybindingsRegistry.registerCommandAndKeybindingRule({449id: NEXT_DEBUG_CONSOLE_ID,450weight: KeybindingWeight.WorkbenchContrib + 1,451when: CONTEXT_IN_DEBUG_REPL,452primary: KeyMod.CtrlCmd | KeyCode.PageDown,453mac: { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.BracketRight },454handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {455changeDebugConsoleFocus(accessor, true);456}457});458459KeybindingsRegistry.registerCommandAndKeybindingRule({460id: PREV_DEBUG_CONSOLE_ID,461weight: KeybindingWeight.WorkbenchContrib + 1,462when: CONTEXT_IN_DEBUG_REPL,463primary: KeyMod.CtrlCmd | KeyCode.PageUp,464mac: { primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.BracketLeft },465handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {466changeDebugConsoleFocus(accessor, false);467}468});469470KeybindingsRegistry.registerCommandAndKeybindingRule({471id: RESTART_SESSION_ID,472weight: KeybindingWeight.WorkbenchContrib,473primary: KeyMod.Shift | KeyMod.CtrlCmd | KeyCode.F5,474when: CONTEXT_IN_DEBUG_MODE,475handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {476const debugService = accessor.get(IDebugService);477const configurationService = accessor.get(IConfigurationService);478let session: IDebugSession | undefined;479if (isSessionContext(context)) {480session = debugService.getModel().getSession(context.sessionId);481} else {482session = debugService.getViewModel().focusedSession;483}484485if (!session) {486const { launch, name } = debugService.getConfigurationManager().selectedConfiguration;487await debugService.startDebugging(launch, name, { noDebug: false, startedByUser: true });488} else {489const showSubSessions = configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;490// Stop should be sent to the root parent session491while (!showSubSessions && session.lifecycleManagedByParent && session.parentSession) {492session = session.parentSession;493}494session.removeReplExpressions();495await debugService.restartSession(session);496}497}498});499500KeybindingsRegistry.registerCommandAndKeybindingRule({501id: STEP_OVER_ID,502weight: KeybindingWeight.WorkbenchContrib,503primary: KeyCode.F10,504when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),505handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {506const contextKeyService = accessor.get(IContextKeyService);507if (CONTEXT_DISASSEMBLY_VIEW_FOCUS.getValue(contextKeyService)) {508await getThreadAndRun(accessor, context, (thread: IThread) => thread.next('instruction'));509} else {510await getThreadAndRun(accessor, context, (thread: IThread) => thread.next());511}512}513});514515// Windows browsers use F11 for full screen, thus use alt+F11 as the default shortcut516const STEP_INTO_KEYBINDING = (isWeb && isWindows) ? (KeyMod.Alt | KeyCode.F11) : KeyCode.F11;517518KeybindingsRegistry.registerCommandAndKeybindingRule({519id: STEP_INTO_ID,520weight: KeybindingWeight.WorkbenchContrib + 10, // Have a stronger weight to have priority over full screen when debugging521primary: STEP_INTO_KEYBINDING,522// Use a more flexible when clause to not allow full screen command to take over when F11 pressed a lot of times523when: CONTEXT_DEBUG_STATE.notEqualsTo('inactive'),524handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {525const contextKeyService = accessor.get(IContextKeyService);526if (CONTEXT_DISASSEMBLY_VIEW_FOCUS.getValue(contextKeyService)) {527await getThreadAndRun(accessor, context, (thread: IThread) => thread.stepIn('instruction'));528} else {529await getThreadAndRun(accessor, context, (thread: IThread) => thread.stepIn());530}531}532});533534KeybindingsRegistry.registerCommandAndKeybindingRule({535id: STEP_OUT_ID,536weight: KeybindingWeight.WorkbenchContrib,537primary: KeyMod.Shift | KeyCode.F11,538when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),539handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {540const contextKeyService = accessor.get(IContextKeyService);541if (CONTEXT_DISASSEMBLY_VIEW_FOCUS.getValue(contextKeyService)) {542await getThreadAndRun(accessor, context, (thread: IThread) => thread.stepOut('instruction'));543} else {544await getThreadAndRun(accessor, context, (thread: IThread) => thread.stepOut());545}546}547});548549KeybindingsRegistry.registerCommandAndKeybindingRule({550id: PAUSE_ID,551weight: KeybindingWeight.WorkbenchContrib + 2, // take priority over focus next part while we are debugging552primary: KeyCode.F6,553when: CONTEXT_DEBUG_STATE.isEqualTo('running'),554handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {555await getThreadAndRun(accessor, context, thread => thread.pause());556}557});558559560KeybindingsRegistry.registerCommandAndKeybindingRule({561id: STEP_INTO_TARGET_ID,562primary: STEP_INTO_KEYBINDING | KeyMod.CtrlCmd,563when: ContextKeyExpr.and(CONTEXT_STEP_INTO_TARGETS_SUPPORTED, CONTEXT_IN_DEBUG_MODE, CONTEXT_DEBUG_STATE.isEqualTo('stopped')),564weight: KeybindingWeight.WorkbenchContrib,565handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {566const quickInputService = accessor.get(IQuickInputService);567const debugService = accessor.get(IDebugService);568const session = debugService.getViewModel().focusedSession;569const frame = debugService.getViewModel().focusedStackFrame;570if (!frame || !session) {571return;572}573574const editor = await accessor.get(IEditorService).openEditor({575resource: frame.source.uri,576options: { revealIfOpened: true }577});578579let codeEditor: ICodeEditor | undefined;580if (editor) {581const ctrl = editor?.getControl();582if (isCodeEditor(ctrl)) {583codeEditor = ctrl;584}585}586587interface ITargetItem extends IQuickPickItem {588target: DebugProtocol.StepInTarget;589}590591const disposables = new DisposableStore();592const qp = disposables.add(quickInputService.createQuickPick<ITargetItem>());593qp.busy = true;594qp.show();595596disposables.add(qp.onDidChangeActive(([item]) => {597if (codeEditor && item && item.target.line !== undefined) {598codeEditor.revealLineInCenterIfOutsideViewport(item.target.line);599codeEditor.setSelection({600startLineNumber: item.target.line,601startColumn: item.target.column || 1,602endLineNumber: item.target.endLine || item.target.line,603endColumn: item.target.endColumn || item.target.column || 1,604});605}606}));607608disposables.add(qp.onDidAccept(() => {609if (qp.activeItems.length) {610session.stepIn(frame.thread.threadId, qp.activeItems[0].target.id);611}612}));613614disposables.add(qp.onDidHide(() => disposables.dispose()));615616session.stepInTargets(frame.frameId).then(targets => {617qp.busy = false;618if (targets?.length) {619qp.items = targets?.map(target => ({ target, label: target.label }));620} else {621qp.placeholder = nls.localize('editor.debug.action.stepIntoTargets.none', "No step targets available");622}623});624}625});626627async function stopHandler(accessor: ServicesAccessor, _: unknown, context: CallStackContext | unknown, disconnect: boolean, suspend?: boolean): Promise<void> {628const debugService = accessor.get(IDebugService);629let session: IDebugSession | undefined;630if (isSessionContext(context)) {631session = debugService.getModel().getSession(context.sessionId);632} else {633session = debugService.getViewModel().focusedSession;634}635636const configurationService = accessor.get(IConfigurationService);637const showSubSessions = configurationService.getValue<IDebugConfiguration>('debug').showSubSessionsInToolBar;638// Stop should be sent to the root parent session639while (!showSubSessions && session && session.lifecycleManagedByParent && session.parentSession) {640session = session.parentSession;641}642643await debugService.stopSession(session, disconnect, suspend);644}645646KeybindingsRegistry.registerCommandAndKeybindingRule({647id: DISCONNECT_ID,648weight: KeybindingWeight.WorkbenchContrib,649primary: KeyMod.Shift | KeyCode.F5,650when: ContextKeyExpr.and(CONTEXT_FOCUSED_SESSION_IS_ATTACH, CONTEXT_IN_DEBUG_MODE),651handler: (accessor, _, context) => stopHandler(accessor, _, context, true)652});653654CommandsRegistry.registerCommand({655id: DISCONNECT_AND_SUSPEND_ID,656handler: (accessor, _, context) => stopHandler(accessor, _, context, true, true)657});658659KeybindingsRegistry.registerCommandAndKeybindingRule({660id: STOP_ID,661weight: KeybindingWeight.WorkbenchContrib,662primary: KeyMod.Shift | KeyCode.F5,663when: ContextKeyExpr.and(CONTEXT_FOCUSED_SESSION_IS_ATTACH.toNegated(), CONTEXT_IN_DEBUG_MODE),664handler: (accessor, _, context) => stopHandler(accessor, _, context, false)665});666667CommandsRegistry.registerCommand({668id: RESTART_FRAME_ID,669handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {670const debugService = accessor.get(IDebugService);671const notificationService = accessor.get(INotificationService);672const frame = getFrame(debugService, context);673if (frame) {674try {675await frame.restart();676} catch (e) {677notificationService.error(e);678}679}680}681});682683KeybindingsRegistry.registerCommandAndKeybindingRule({684id: CONTINUE_ID,685weight: KeybindingWeight.WorkbenchContrib + 10, // Use a stronger weight to get priority over start debugging F5 shortcut686primary: KeyCode.F5,687when: CONTEXT_DEBUG_STATE.isEqualTo('stopped'),688handler: async (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {689await getThreadAndRun(accessor, context, thread => thread.continue());690}691});692693CommandsRegistry.registerCommand({694id: SHOW_LOADED_SCRIPTS_ID,695handler: async (accessor) => {696await showLoadedScriptMenu(accessor);697}698});699700CommandsRegistry.registerCommand({701id: 'debug.startFromConfig',702handler: async (accessor, config: IConfig) => {703const debugService = accessor.get(IDebugService);704await debugService.startDebugging(undefined, config);705}706});707708CommandsRegistry.registerCommand({709id: FOCUS_SESSION_ID,710handler: async (accessor: ServicesAccessor, session: IDebugSession) => {711const debugService = accessor.get(IDebugService);712const editorService = accessor.get(IEditorService);713session = resolveChildSession(session, debugService.getModel().getSessions());714await debugService.focusStackFrame(undefined, undefined, session, { explicit: true });715const stackFrame = debugService.getViewModel().focusedStackFrame;716if (stackFrame) {717await stackFrame.openInEditor(editorService, true);718}719}720});721722CommandsRegistry.registerCommand({723id: SELECT_AND_START_ID,724handler: async (accessor: ServicesAccessor, debugType: string | unknown, debugStartOptions?: { noDebug?: boolean }) => {725const quickInputService = accessor.get(IQuickInputService);726const debugService = accessor.get(IDebugService);727728if (debugType) {729const configManager = debugService.getConfigurationManager();730const dynamicProviders = await configManager.getDynamicProviders();731for (const provider of dynamicProviders) {732if (provider.type === debugType) {733const pick = await provider.pick();734if (pick) {735await configManager.selectConfiguration(pick.launch, pick.config.name, pick.config, { type: provider.type });736debugService.startDebugging(pick.launch, pick.config, { noDebug: debugStartOptions?.noDebug, startedByUser: true });737738return;739}740}741}742}743744quickInputService.quickAccess.show(DEBUG_QUICK_ACCESS_PREFIX);745}746});747748CommandsRegistry.registerCommand({749id: SELECT_DEBUG_CONSOLE_ID,750handler: async (accessor: ServicesAccessor) => {751const quickInputService = accessor.get(IQuickInputService);752quickInputService.quickAccess.show(DEBUG_CONSOLE_QUICK_ACCESS_PREFIX);753}754});755756CommandsRegistry.registerCommand({757id: SELECT_DEBUG_SESSION_ID,758handler: async (accessor: ServicesAccessor) => {759showDebugSessionMenu(accessor, SELECT_AND_START_ID);760}761});762763KeybindingsRegistry.registerCommandAndKeybindingRule({764id: DEBUG_START_COMMAND_ID,765weight: KeybindingWeight.WorkbenchContrib,766primary: KeyCode.F5,767when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.isEqualTo('inactive')),768handler: async (accessor: ServicesAccessor, debugStartOptions?: { config?: Partial<IConfig>; noDebug?: boolean }) => {769const debugService = accessor.get(IDebugService);770await saveAllBeforeDebugStart(accessor.get(IConfigurationService), accessor.get(IEditorService));771const { launch, name, getConfig } = debugService.getConfigurationManager().selectedConfiguration;772const config = await getConfig();773const configOrName = config ? Object.assign(deepClone(config), debugStartOptions?.config) : name;774await debugService.startDebugging(launch, configOrName, { noDebug: debugStartOptions?.noDebug, startedByUser: true }, false);775}776});777778KeybindingsRegistry.registerCommandAndKeybindingRule({779id: DEBUG_RUN_COMMAND_ID,780weight: KeybindingWeight.WorkbenchContrib,781primary: KeyMod.CtrlCmd | KeyCode.F5,782mac: { primary: KeyMod.WinCtrl | KeyCode.F5 },783when: ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))),784handler: async (accessor: ServicesAccessor) => {785const commandService = accessor.get(ICommandService);786await commandService.executeCommand(DEBUG_START_COMMAND_ID, { noDebug: true });787}788});789790KeybindingsRegistry.registerCommandAndKeybindingRule({791id: 'debug.toggleBreakpoint',792weight: KeybindingWeight.WorkbenchContrib + 5,793when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_FOCUSED, InputFocusedContext.toNegated()),794primary: KeyCode.Space,795handler: (accessor) => {796const listService = accessor.get(IListService);797const debugService = accessor.get(IDebugService);798const list = listService.lastFocusedList;799if (list instanceof List) {800const focused = <IEnablement[]>list.getFocusedElements();801if (focused && focused.length) {802debugService.enableOrDisableBreakpoints(!focused[0].enabled, focused[0]);803}804}805}806});807808KeybindingsRegistry.registerCommandAndKeybindingRule({809id: 'debug.enableOrDisableBreakpoint',810weight: KeybindingWeight.WorkbenchContrib,811primary: undefined,812when: EditorContextKeys.editorTextFocus,813handler: (accessor) => {814const debugService = accessor.get(IDebugService);815const editorService = accessor.get(IEditorService);816const control = editorService.activeTextEditorControl;817if (isCodeEditor(control)) {818const model = control.getModel();819if (model) {820const position = control.getPosition();821if (position) {822const bps = debugService.getModel().getBreakpoints({ uri: model.uri, lineNumber: position.lineNumber });823if (bps.length) {824debugService.enableOrDisableBreakpoints(!bps[0].enabled, bps[0]);825}826}827}828}829}830});831832KeybindingsRegistry.registerCommandAndKeybindingRule({833id: EDIT_EXPRESSION_COMMAND_ID,834weight: KeybindingWeight.WorkbenchContrib + 5,835when: CONTEXT_WATCH_EXPRESSIONS_FOCUSED,836primary: KeyCode.F2,837mac: { primary: KeyCode.Enter },838handler: (accessor: ServicesAccessor, expression: Expression | unknown) => {839const debugService = accessor.get(IDebugService);840if (!(expression instanceof Expression)) {841const listService = accessor.get(IListService);842const focused = listService.lastFocusedList;843if (focused) {844const elements = focused.getFocus();845if (Array.isArray(elements) && elements[0] instanceof Expression) {846expression = elements[0];847}848}849}850851if (expression instanceof Expression) {852debugService.getViewModel().setSelectedExpression(expression, false);853}854}855});856857CommandsRegistry.registerCommand({858id: SET_EXPRESSION_COMMAND_ID,859handler: async (accessor: ServicesAccessor, expression: Expression | unknown) => {860const debugService = accessor.get(IDebugService);861if (expression instanceof Expression || expression instanceof Variable) {862debugService.getViewModel().setSelectedExpression(expression, true);863}864}865});866867KeybindingsRegistry.registerCommandAndKeybindingRule({868id: 'debug.setVariable',869weight: KeybindingWeight.WorkbenchContrib + 5,870when: CONTEXT_VARIABLES_FOCUSED,871primary: KeyCode.F2,872mac: { primary: KeyCode.Enter },873handler: (accessor) => {874const listService = accessor.get(IListService);875const debugService = accessor.get(IDebugService);876const focused = listService.lastFocusedList;877878if (focused) {879const elements = focused.getFocus();880if (Array.isArray(elements) && elements[0] instanceof Variable) {881debugService.getViewModel().setSelectedExpression(elements[0], false);882}883}884}885});886887KeybindingsRegistry.registerCommandAndKeybindingRule({888id: REMOVE_EXPRESSION_COMMAND_ID,889weight: KeybindingWeight.WorkbenchContrib,890when: ContextKeyExpr.and(CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_EXPRESSION_SELECTED.toNegated()),891primary: KeyCode.Delete,892mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },893handler: (accessor: ServicesAccessor, expression: Expression | unknown) => {894const debugService = accessor.get(IDebugService);895896if (expression instanceof Expression) {897debugService.removeWatchExpressions(expression.getId());898return;899}900901const listService = accessor.get(IListService);902const focused = listService.lastFocusedList;903if (focused) {904let elements = focused.getFocus();905if (Array.isArray(elements) && elements[0] instanceof Expression) {906const selection = focused.getSelection();907if (selection && selection.indexOf(elements[0]) >= 0) {908elements = selection;909}910elements.forEach((e: Expression) => debugService.removeWatchExpressions(e.getId()));911}912}913}914});915916CommandsRegistry.registerCommand({917id: BREAK_WHEN_VALUE_CHANGES_ID,918handler: async (accessor: ServicesAccessor) => {919const debugService = accessor.get(IDebugService);920if (dataBreakpointInfoResponse) {921await debugService.addDataBreakpoint({ description: dataBreakpointInfoResponse.description, src: { type: DataBreakpointSetType.Variable, dataId: dataBreakpointInfoResponse.dataId! }, canPersist: !!dataBreakpointInfoResponse.canPersist, accessTypes: dataBreakpointInfoResponse.accessTypes, accessType: 'write' });922}923}924});925926CommandsRegistry.registerCommand({927id: BREAK_WHEN_VALUE_IS_ACCESSED_ID,928handler: async (accessor: ServicesAccessor) => {929const debugService = accessor.get(IDebugService);930if (dataBreakpointInfoResponse) {931await debugService.addDataBreakpoint({ description: dataBreakpointInfoResponse.description, src: { type: DataBreakpointSetType.Variable, dataId: dataBreakpointInfoResponse.dataId! }, canPersist: !!dataBreakpointInfoResponse.canPersist, accessTypes: dataBreakpointInfoResponse.accessTypes, accessType: 'readWrite' });932}933}934});935936CommandsRegistry.registerCommand({937id: BREAK_WHEN_VALUE_IS_READ_ID,938handler: async (accessor: ServicesAccessor) => {939const debugService = accessor.get(IDebugService);940if (dataBreakpointInfoResponse) {941await debugService.addDataBreakpoint({ description: dataBreakpointInfoResponse.description, src: { type: DataBreakpointSetType.Variable, dataId: dataBreakpointInfoResponse.dataId! }, canPersist: !!dataBreakpointInfoResponse.canPersist, accessTypes: dataBreakpointInfoResponse.accessTypes, accessType: 'read' });942}943}944});945946KeybindingsRegistry.registerCommandAndKeybindingRule({947id: 'debug.removeBreakpoint',948weight: KeybindingWeight.WorkbenchContrib,949when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_BREAKPOINT_INPUT_FOCUSED.toNegated()),950primary: KeyCode.Delete,951mac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },952handler: (accessor) => {953const listService = accessor.get(IListService);954const debugService = accessor.get(IDebugService);955const list = listService.lastFocusedList;956957if (list instanceof List) {958const focused = list.getFocusedElements();959const element = focused.length ? focused[0] : undefined;960if (element instanceof Breakpoint) {961debugService.removeBreakpoints(element.getId());962} else if (element instanceof FunctionBreakpoint) {963debugService.removeFunctionBreakpoints(element.getId());964} else if (element instanceof DataBreakpoint) {965debugService.removeDataBreakpoints(element.getId());966}967}968}969});970971KeybindingsRegistry.registerCommandAndKeybindingRule({972id: 'debug.installAdditionalDebuggers',973weight: KeybindingWeight.WorkbenchContrib,974when: undefined,975primary: undefined,976handler: async (accessor, query: string) => {977const extensionsWorkbenchService = accessor.get(IExtensionsWorkbenchService);978let searchFor = `@category:debuggers`;979if (typeof query === 'string') {980searchFor += ` ${query}`;981}982return extensionsWorkbenchService.openSearch(searchFor);983}984});985986registerAction2(class AddConfigurationAction extends Action2 {987constructor() {988super({989id: ADD_CONFIGURATION_ID,990title: nls.localize2('addConfiguration', "Add Configuration..."),991category: DEBUG_COMMAND_CATEGORY,992f1: true,993menu: {994id: MenuId.EditorContent,995when: ContextKeyExpr.and(996ContextKeyExpr.regex(ResourceContextKey.Path.key, /\.vscode[/\\]launch\.json$/),997ActiveEditorContext.isEqualTo(TEXT_FILE_EDITOR_ID))998}999});1000}10011002async run(accessor: ServicesAccessor, launchUri: string): Promise<void> {1003const manager = accessor.get(IDebugService).getConfigurationManager();10041005const launch = manager.getLaunches().find(l => l.uri.toString() === launchUri) || manager.selectedConfiguration.launch;1006if (launch) {1007const { editor, created } = await launch.openConfigFile({ preserveFocus: false });1008if (editor && !created) {1009const codeEditor = <ICodeEditor>editor.getControl();1010if (codeEditor) {1011await codeEditor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID)?.addLaunchConfiguration();1012}1013}1014}1015}1016});10171018const inlineBreakpointHandler = (accessor: ServicesAccessor) => {1019const debugService = accessor.get(IDebugService);1020const editorService = accessor.get(IEditorService);1021const control = editorService.activeTextEditorControl;1022if (isCodeEditor(control)) {1023const position = control.getPosition();1024if (position && control.hasModel() && debugService.canSetBreakpointsIn(control.getModel())) {1025const modelUri = control.getModel().uri;1026const breakpointAlreadySet = debugService.getModel().getBreakpoints({ lineNumber: position.lineNumber, uri: modelUri })1027.some(bp => (bp.sessionAgnosticData.column === position.column || (!bp.column && position.column <= 1)));10281029if (!breakpointAlreadySet) {1030debugService.addBreakpoints(modelUri, [{ lineNumber: position.lineNumber, column: position.column > 1 ? position.column : undefined }]);1031}1032}1033}1034};10351036KeybindingsRegistry.registerCommandAndKeybindingRule({1037weight: KeybindingWeight.WorkbenchContrib,1038primary: KeyMod.Shift | KeyCode.F9,1039when: EditorContextKeys.editorTextFocus,1040id: TOGGLE_INLINE_BREAKPOINT_ID,1041handler: inlineBreakpointHandler1042});10431044MenuRegistry.appendMenuItem(MenuId.EditorContext, {1045command: {1046id: TOGGLE_INLINE_BREAKPOINT_ID,1047title: nls.localize('addInlineBreakpoint', "Add Inline Breakpoint"),1048category: DEBUG_COMMAND_CATEGORY1049},1050when: ContextKeyExpr.and(1051CONTEXT_IN_DEBUG_MODE,1052PanelFocusContext.toNegated(),1053EditorContextKeys.editorTextFocus,1054ChatContextKeys.inChatSession.toNegated()),1055group: 'debug',1056order: 11057});10581059KeybindingsRegistry.registerCommandAndKeybindingRule({1060id: 'debug.openBreakpointToSide',1061weight: KeybindingWeight.WorkbenchContrib,1062when: CONTEXT_BREAKPOINTS_FOCUSED,1063primary: KeyMod.CtrlCmd | KeyCode.Enter,1064secondary: [KeyMod.Alt | KeyCode.Enter],1065handler: (accessor) => {1066const listService = accessor.get(IListService);1067const list = listService.lastFocusedList;1068if (list instanceof List) {1069const focus = list.getFocusedElements();1070if (focus.length && focus[0] instanceof Breakpoint) {1071return openBreakpointSource(focus[0], true, false, true, accessor.get(IDebugService), accessor.get(IEditorService));1072}1073}10741075return undefined;1076}1077});10781079registerAction2(class ToggleExceptionBreakpointsAction extends Action2 {1080constructor() {1081super({1082id: TOGGLE_EXCEPTION_BREAKPOINTS_ID,1083title: nls.localize2('toggleExceptionBreakpoints', "Toggle Exception Breakpoints"),1084category: DEBUG_COMMAND_CATEGORY,1085f1: true,1086precondition: CONTEXT_DEBUGGERS_AVAILABLE1087});1088}10891090async run(accessor: ServicesAccessor): Promise<void> {1091const debugService = accessor.get(IDebugService);1092const quickInputService = accessor.get(IQuickInputService);10931094// Get the focused session or the first available session1095const debugModel = debugService.getModel();1096const session = debugService.getViewModel().focusedSession || debugModel.getSessions()[0];1097const exceptionBreakpoints = session ? debugModel.getExceptionBreakpointsForSession(session.getId()) : debugModel.getExceptionBreakpoints();1098if (exceptionBreakpoints.length === 0) {1099return;1100}11011102// If only one exception breakpoint type, toggle it directly1103if (exceptionBreakpoints.length === 1) {1104const breakpoint = exceptionBreakpoints[0];1105await debugService.enableOrDisableBreakpoints(!breakpoint.enabled, breakpoint);1106return;1107}11081109// Multiple exception breakpoint types - show quickpick for selection1110interface IExceptionBreakpointItem extends IQuickPickItem {1111breakpoint: IExceptionBreakpoint;1112}11131114const disposables = new DisposableStore();1115const quickPick = disposables.add(quickInputService.createQuickPick<IExceptionBreakpointItem>());1116quickPick.placeholder = nls.localize('selectExceptionBreakpointsPlaceholder', "Pick enabled exception breakpoints");1117quickPick.canSelectMany = true;1118quickPick.matchOnDescription = true;1119quickPick.matchOnDetail = true;11201121// Create quickpick items from exception breakpoints1122quickPick.items = exceptionBreakpoints.map(bp => ({1123label: bp.label,1124description: bp.description,1125picked: bp.enabled,1126breakpoint: bp1127}));11281129quickPick.selectedItems = quickPick.items.filter(item => item.picked);11301131disposables.add(quickPick.onDidAccept(() => {1132const selectedItems = quickPick.selectedItems;1133const toEnable: IExceptionBreakpoint[] = [];1134const toDisable: IExceptionBreakpoint[] = [];11351136// Determine which breakpoints need to be toggled1137for (const bp of exceptionBreakpoints) {1138const isSelected = selectedItems.some(item => item.breakpoint === bp);1139if (isSelected && !bp.enabled) {1140toEnable.push(bp);1141} else if (!isSelected && bp.enabled) {1142toDisable.push(bp);1143}1144}11451146// Toggle the breakpoints1147const promises: Promise<void>[] = [];1148for (const bp of toEnable) {1149promises.push(debugService.enableOrDisableBreakpoints(true, bp));1150}1151for (const bp of toDisable) {1152promises.push(debugService.enableOrDisableBreakpoints(false, bp));1153}11541155Promise.all(promises).then(() => disposables.dispose());1156}));11571158disposables.add(quickPick.onDidHide(() => disposables.dispose()));1159quickPick.show();1160}1161});11621163// When there are no debug extensions, open the debug viewlet when F5 is pressed so the user can read the limitations1164KeybindingsRegistry.registerCommandAndKeybindingRule({1165id: 'debug.openView',1166weight: KeybindingWeight.WorkbenchContrib,1167when: CONTEXT_DEBUGGERS_AVAILABLE.toNegated(),1168primary: KeyCode.F5,1169secondary: [KeyMod.CtrlCmd | KeyCode.F5],1170handler: async (accessor) => {1171const paneCompositeService = accessor.get(IPaneCompositePartService);1172await paneCompositeService.openPaneComposite(VIEWLET_ID, ViewContainerLocation.Sidebar, true);1173}1174});11751176registerAction2(class extends Action2 {1177constructor() {1178super({1179id: ATTACH_TO_CURRENT_CODE_RENDERER,1180title: nls.localize2('attachToCurrentCodeRenderer', "Attach to Current Code Renderer"),1181});1182}11831184override async run(accessor: ServicesAccessor): Promise<any> {1185const env = accessor.get(IEnvironmentService);1186if (!env.isExtensionDevelopment && !env.extensionTestsLocationURI) {1187throw new Error('Refusing to attach to renderer outside of development context');1188}11891190const windowId = getWindowId(mainWindow);1191const extDebugService = accessor.get(IExtensionHostDebugService);1192const result = await extDebugService.attachToCurrentWindowRenderer(windowId);11931194return result;1195}1196});119711981199