1509 lines
74 KiB
TypeScript
1509 lines
74 KiB
TypeScript
// *****************************************************************************
|
|
// Copyright (C) 2018 TypeFox and others.
|
|
//
|
|
// This program and the accompanying materials are made available under the
|
|
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
// http://www.eclipse.org/legal/epl-2.0.
|
|
//
|
|
// This Source Code may also be made available under the following Secondary
|
|
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
// with the GNU Classpath Exception which is available at
|
|
// https://www.gnu.org/software/classpath/license.html.
|
|
//
|
|
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
// *****************************************************************************
|
|
|
|
import {
|
|
AbstractViewContribution, KeybindingRegistry, Widget, CompositeTreeNode, LabelProvider, codicon, OnWillStopAction, FrontendApplicationContribution, ConfirmDialog, Dialog
|
|
} from '@theia/core/lib/browser';
|
|
import { TreeElementNode } from '@theia/core/lib/browser/source-tree';
|
|
import { injectable, inject } from '@theia/core/shared/inversify';
|
|
import * as monaco from '@theia/monaco-editor-core';
|
|
import { MenuModelRegistry, CommandRegistry, Command, URI, Event, MessageService, CancellationError } from '@theia/core/lib/common';
|
|
import { waitForEvent } from '@theia/core/lib/common/promise-util';
|
|
import { EDITOR_CONTEXT_MENU, EDITOR_LINENUMBER_CONTEXT_MENU, EditorManager } from '@theia/editor/lib/browser';
|
|
import { DebugSessionManager } from './debug-session-manager';
|
|
import { DebugWidget } from './view/debug-widget';
|
|
import { FunctionBreakpoint, SourceBreakpoint } from './breakpoint/breakpoint-marker';
|
|
import { BreakpointManager } from './breakpoint/breakpoint-manager';
|
|
import { DebugConfigurationManager } from './debug-configuration-manager';
|
|
import { DebugState, DebugSession } from './debug-session';
|
|
import { DebugBreakpointsWidget } from './view/debug-breakpoints-widget';
|
|
import { DebugSourceBreakpoint } from './model/debug-source-breakpoint';
|
|
import { DebugThreadsWidget } from './view/debug-threads-widget';
|
|
import { DebugThread } from './model/debug-thread';
|
|
import { DebugStackFramesWidget } from './view/debug-stack-frames-widget';
|
|
import { DebugStackFrame } from './model/debug-stack-frame';
|
|
import { DebugVariablesWidget } from './view/debug-variables-widget';
|
|
import { DebugVariable } from './console/debug-console-items';
|
|
import { DebugSessionWidget } from './view/debug-session-widget';
|
|
import { DebugEditorModel } from './editor/debug-editor-model';
|
|
import { DebugEditorService } from './editor/debug-editor-service';
|
|
import { DebugConsoleContribution } from './console/debug-console-contribution';
|
|
import { DebugService } from '../common/debug-service';
|
|
import { DebugSchemaUpdater } from './debug-schema-updater';
|
|
import { DebugPreferences } from '../common/debug-preferences';
|
|
import { TabBarToolbarContribution, TabBarToolbarRegistry } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
|
|
import { DebugWatchWidget } from './view/debug-watch-widget';
|
|
import { DebugWatchExpression } from './view/debug-watch-expression';
|
|
import { DebugWatchManager } from './debug-watch-manager';
|
|
import { DebugSessionOptions } from './debug-session-options';
|
|
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
|
|
import { ColorRegistry } from '@theia/core/lib/browser/color-registry';
|
|
import { DebugFunctionBreakpoint } from './model/debug-function-breakpoint';
|
|
import { DebugBreakpoint } from './model/debug-breakpoint';
|
|
import { nls } from '@theia/core/lib/common/nls';
|
|
import { DebugInstructionBreakpoint } from './model/debug-instruction-breakpoint';
|
|
import { DebugConfiguration } from '../common/debug-configuration';
|
|
import { DebugExceptionBreakpoint } from './view/debug-exception-breakpoint';
|
|
import { DebugToolBar } from './view/debug-toolbar-widget';
|
|
import { ConsoleWidget } from '@theia/console/lib/browser/console-widget';
|
|
import { ConsoleContentWidget } from '@theia/console/lib/browser/console-content-widget';
|
|
import { ConsoleContextMenu } from '@theia/console/lib/browser/console-contribution';
|
|
import { DebugHoverWidget } from './editor/debug-hover-widget';
|
|
import { DebugExpressionProvider } from './editor/debug-expression-provider';
|
|
import { AddOrEditDataBreakpointAddress } from './breakpoint/debug-data-breakpoint-actions';
|
|
import {
|
|
DebugMenus, DebugCommands, DebugThreadContextCommands, DebugSessionContextCommands,
|
|
DebugEditorContextCommands, DebugBreakpointWidgetCommands, nlsEnableBreakpoint, nlsDisableBreakpoint
|
|
} from './debug-commands';
|
|
|
|
@injectable()
|
|
export class DebugFrontendApplicationContribution extends AbstractViewContribution<DebugWidget>
|
|
implements TabBarToolbarContribution, ColorContribution, FrontendApplicationContribution {
|
|
|
|
@inject(DebugService)
|
|
protected readonly debug: DebugService;
|
|
|
|
@inject(DebugSessionManager)
|
|
protected readonly manager: DebugSessionManager;
|
|
|
|
@inject(DebugConfigurationManager)
|
|
protected readonly configurations: DebugConfigurationManager;
|
|
|
|
@inject(BreakpointManager)
|
|
protected readonly breakpointManager: BreakpointManager;
|
|
|
|
@inject(DebugEditorService)
|
|
protected readonly editors: DebugEditorService;
|
|
|
|
@inject(DebugConsoleContribution)
|
|
protected readonly console: DebugConsoleContribution;
|
|
|
|
@inject(DebugSchemaUpdater)
|
|
protected readonly schemaUpdater: DebugSchemaUpdater;
|
|
|
|
@inject(DebugPreferences)
|
|
protected readonly preference: DebugPreferences;
|
|
|
|
@inject(DebugWatchManager)
|
|
protected readonly watchManager: DebugWatchManager;
|
|
|
|
@inject(DebugExpressionProvider)
|
|
protected readonly expressionProvider: DebugExpressionProvider;
|
|
|
|
@inject(LabelProvider)
|
|
protected readonly labelProvider: LabelProvider;
|
|
|
|
@inject(EditorManager)
|
|
protected readonly editorManager: EditorManager;
|
|
|
|
@inject(MessageService)
|
|
protected readonly messageService: MessageService;
|
|
|
|
@inject(AddOrEditDataBreakpointAddress)
|
|
protected readonly AddOrEditDataBreakpointAddress: AddOrEditDataBreakpointAddress;
|
|
|
|
constructor() {
|
|
super({
|
|
widgetId: DebugWidget.ID,
|
|
widgetName: DebugWidget.LABEL,
|
|
defaultWidgetOptions: {
|
|
area: 'left',
|
|
rank: 400
|
|
},
|
|
toggleCommandId: 'debug:toggle',
|
|
toggleKeybinding: 'ctrlcmd+shift+d'
|
|
});
|
|
}
|
|
|
|
async initializeLayout(): Promise<void> {
|
|
await this.openView();
|
|
}
|
|
|
|
protected firstSessionStart = true;
|
|
async onStart(): Promise<void> {
|
|
this.manager.onDidCreateDebugSession(session => this.openSession(session, { reveal: false }));
|
|
this.manager.onDidStartDebugSession(session => {
|
|
const { noDebug } = session.configuration;
|
|
const openDebug = session.configuration.openDebug || this.preference['debug.openDebug'];
|
|
const internalConsoleOptions = session.configuration.internalConsoleOptions || this.preference['debug.internalConsoleOptions'];
|
|
if (internalConsoleOptions === 'openOnSessionStart' ||
|
|
(internalConsoleOptions === 'openOnFirstSessionStart' && this.firstSessionStart)) {
|
|
this.console.openView({
|
|
reveal: true,
|
|
activate: false,
|
|
});
|
|
}
|
|
const shouldOpenDebug = openDebug === 'openOnSessionStart' || (openDebug === 'openOnFirstSessionStart' && this.firstSessionStart);
|
|
// Do not open debug view when suppressed via configuration
|
|
if (!noDebug && !this.getOption(session, 'suppressDebugView') && shouldOpenDebug) {
|
|
this.openSession(session);
|
|
}
|
|
this.firstSessionStart = false;
|
|
});
|
|
this.manager.onDidStopDebugSession(session => {
|
|
const { openDebug } = session.configuration;
|
|
if (!this.getOption(session, 'suppressDebugView') && openDebug === 'openOnDebugBreak') {
|
|
this.openSession(session);
|
|
}
|
|
});
|
|
|
|
this.updateStatusBar();
|
|
this.manager.onDidChange(() => this.updateStatusBar());
|
|
|
|
this.schemaUpdater.update();
|
|
this.configurations.load();
|
|
this.breakpointManager.load();
|
|
this.watchManager.load();
|
|
}
|
|
|
|
onStop(): void {
|
|
this.configurations.save();
|
|
this.breakpointManager.save();
|
|
this.watchManager.save();
|
|
}
|
|
|
|
onWillStop(): OnWillStopAction | undefined {
|
|
if (this.preference['debug.confirmOnExit'] === 'always' && this.manager.currentSession) {
|
|
return {
|
|
reason: 'active-debug-sessions',
|
|
action: async () => {
|
|
if (this.manager.currentSession) {
|
|
const msg = this.manager.sessions.length === 1
|
|
? nls.localizeByDefault('There is an active debug session, are you sure you want to stop it?')
|
|
: nls.localizeByDefault('There are active debug sessions, are you sure you want to stop them?');
|
|
const safeToExit = await new ConfirmDialog({
|
|
title: '',
|
|
msg,
|
|
ok: nls.localizeByDefault('Stop Debugging'),
|
|
cancel: Dialog.CANCEL,
|
|
}).open();
|
|
return safeToExit === true;
|
|
}
|
|
return true;
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
override registerMenus(menus: MenuModelRegistry): void {
|
|
super.registerMenus(menus);
|
|
const registerMenuActions = (menuPath: string[], ...commands: (Command & { order?: string, when?: string })[]) => {
|
|
for (const [index, command] of commands.entries()) {
|
|
const label = command.label;
|
|
const debug = `${DebugCommands.DEBUG_CATEGORY}:`;
|
|
menus.registerMenuAction(menuPath, {
|
|
commandId: command.id,
|
|
label: label && label.startsWith(debug) && label.slice(debug.length).trimStart() || label,
|
|
icon: command.iconClass,
|
|
when: command.when,
|
|
order: command.order || String.fromCharCode('a'.charCodeAt(0) + index)
|
|
});
|
|
}
|
|
};
|
|
|
|
menus.registerSubmenu(DebugMenus.DEBUG, nls.localizeByDefault('Run'));
|
|
registerMenuActions(DebugMenus.DEBUG_CONTROLS,
|
|
DebugCommands.START,
|
|
DebugCommands.START_NO_DEBUG,
|
|
DebugCommands.STOP,
|
|
DebugCommands.RESTART
|
|
);
|
|
registerMenuActions(DebugMenus.DEBUG_CONFIGURATION,
|
|
DebugCommands.OPEN_CONFIGURATIONS,
|
|
DebugCommands.ADD_CONFIGURATION
|
|
);
|
|
registerMenuActions(DebugMenus.DEBUG_THREADS,
|
|
DebugCommands.CONTINUE,
|
|
DebugCommands.STEP_OVER,
|
|
DebugCommands.STEP_INTO,
|
|
DebugCommands.STEP_OUT,
|
|
DebugCommands.PAUSE
|
|
);
|
|
registerMenuActions(DebugMenus.DEBUG_SESSIONS,
|
|
DebugCommands.CONTINUE_ALL,
|
|
DebugCommands.PAUSE_ALL
|
|
);
|
|
registerMenuActions(DebugMenus.DEBUG_BREAKPOINT,
|
|
DebugCommands.TOGGLE_BREAKPOINT
|
|
);
|
|
menus.registerSubmenu(DebugMenus.DEBUG_NEW_BREAKPOINT, nls.localizeByDefault('New Breakpoint'));
|
|
registerMenuActions(DebugMenus.DEBUG_NEW_BREAKPOINT,
|
|
DebugCommands.ADD_CONDITIONAL_BREAKPOINT,
|
|
DebugCommands.INLINE_BREAKPOINT,
|
|
DebugCommands.ADD_FUNCTION_BREAKPOINT,
|
|
DebugCommands.ADD_LOGPOINT,
|
|
DebugCommands.ADD_DATA_BREAKPOINT
|
|
);
|
|
registerMenuActions(DebugMenus.DEBUG_BREAKPOINTS,
|
|
DebugCommands.ENABLE_ALL_BREAKPOINTS,
|
|
DebugCommands.DISABLE_ALL_BREAKPOINTS,
|
|
DebugCommands.REMOVE_ALL_BREAKPOINTS
|
|
);
|
|
|
|
registerMenuActions(DebugThreadsWidget.CONTROL_MENU,
|
|
{ ...DebugCommands.PAUSE, ...DebugThreadContextCommands.PAUSE },
|
|
{ ...DebugCommands.CONTINUE, ...DebugThreadContextCommands.CONTINUE },
|
|
{ ...DebugCommands.STEP_OVER, ...DebugThreadContextCommands.STEP_OVER },
|
|
{ ...DebugCommands.STEP_INTO, ...DebugThreadContextCommands.STEP_INTO },
|
|
{ ...DebugCommands.STEP_OUT, ...DebugThreadContextCommands.STEP_OUT },
|
|
{ ...DebugCommands.PAUSE_ALL, ...DebugSessionContextCommands.PAUSE_ALL },
|
|
{ ...DebugCommands.CONTINUE_ALL, ...DebugSessionContextCommands.CONTINUE_ALL }
|
|
);
|
|
registerMenuActions(DebugThreadsWidget.TERMINATE_MENU,
|
|
{ ...DebugCommands.RESTART, ...DebugSessionContextCommands.RESTART },
|
|
{ ...DebugCommands.STOP, ...DebugSessionContextCommands.STOP },
|
|
{ ...DebugThreadContextCommands.TERMINATE, label: nls.localizeByDefault('Terminate Thread') }
|
|
);
|
|
registerMenuActions(DebugThreadsWidget.OPEN_MENU, { ...DebugSessionContextCommands.REVEAL, label: nls.localize('theia/debug/reveal', 'Reveal') });
|
|
|
|
registerMenuActions(DebugStackFramesWidget.CONTEXT_MENU,
|
|
DebugCommands.RESTART_FRAME,
|
|
DebugCommands.COPY_CALL_STACK
|
|
);
|
|
|
|
registerMenuActions(ConsoleContextMenu.CLIPBOARD,
|
|
{ ...DebugCommands.COPY_VARIABLE_VALUE, order: 'a1a' },
|
|
{ ...DebugCommands.COPY_VARIABLE_AS_EXPRESSION, order: 'a1b' }
|
|
);
|
|
registerMenuActions(DebugVariablesWidget.EDIT_MENU,
|
|
DebugCommands.SET_VARIABLE_VALUE,
|
|
DebugCommands.COPY_VARIABLE_VALUE,
|
|
DebugCommands.COPY_VARIABLE_AS_EXPRESSION
|
|
);
|
|
registerMenuActions(DebugVariablesWidget.WATCH_MENU,
|
|
DebugCommands.WATCH_VARIABLE
|
|
);
|
|
registerMenuActions(DebugHoverWidget.EDIT_MENU,
|
|
DebugCommands.COPY_VARIABLE_VALUE,
|
|
DebugCommands.COPY_VARIABLE_AS_EXPRESSION
|
|
);
|
|
registerMenuActions(DebugHoverWidget.WATCH_MENU,
|
|
DebugCommands.WATCH_VARIABLE
|
|
);
|
|
|
|
registerMenuActions(DebugWatchWidget.EDIT_MENU,
|
|
DebugCommands.EDIT_WATCH_EXPRESSION,
|
|
DebugCommands.COPY_WATCH_EXPRESSION_VALUE
|
|
);
|
|
registerMenuActions(DebugWatchWidget.REMOVE_MENU,
|
|
DebugCommands.REMOVE_WATCH_EXPRESSION,
|
|
DebugCommands.REMOVE_ALL_WATCH_EXPRESSIONS
|
|
);
|
|
|
|
registerMenuActions(DebugBreakpointsWidget.EDIT_MENU,
|
|
DebugCommands.EDIT_BREAKPOINT,
|
|
{ ...DebugCommands.ADD_DATA_BREAKPOINT, label: nls.localizeByDefault('Edit Address...'), originalLabel: 'Edit Address...' },
|
|
DebugCommands.EDIT_LOGPOINT,
|
|
DebugCommands.EDIT_BREAKPOINT_CONDITION
|
|
);
|
|
registerMenuActions(DebugBreakpointsWidget.REMOVE_MENU,
|
|
DebugCommands.REMOVE_BREAKPOINT,
|
|
DebugCommands.REMOVE_LOGPOINT,
|
|
DebugCommands.REMOVE_SELECTED_BREAKPOINTS,
|
|
DebugCommands.REMOVE_ALL_BREAKPOINTS
|
|
);
|
|
registerMenuActions(DebugBreakpointsWidget.ENABLE_MENU,
|
|
DebugCommands.ENABLE_SELECTED_BREAKPOINTS,
|
|
DebugCommands.DISABLE_SELECTED_BREAKPOINTS,
|
|
DebugCommands.ENABLE_ALL_BREAKPOINTS,
|
|
DebugCommands.DISABLE_ALL_BREAKPOINTS
|
|
);
|
|
|
|
const DEBUG_EDITOR_CONTEXT_MENU_GROUP = [...EDITOR_CONTEXT_MENU, '2_debug'];
|
|
registerMenuActions(DEBUG_EDITOR_CONTEXT_MENU_GROUP,
|
|
DebugCommands.EVALUATE_IN_DEBUG_CONSOLE,
|
|
DebugCommands.ADD_TO_WATCH,
|
|
DebugCommands.JUMP_TO_CURSOR,
|
|
DebugCommands.RUN_TO_CURSOR,
|
|
DebugCommands.RUN_TO_LINE
|
|
);
|
|
|
|
registerMenuActions([...DebugEditorModel.CONTEXT_MENU, '1_breakpoint'],
|
|
{ ...DebugEditorContextCommands.ADD_BREAKPOINT, label: nls.localizeByDefault('Add Breakpoint') },
|
|
{ ...DebugEditorContextCommands.ADD_CONDITIONAL_BREAKPOINT, label: DebugCommands.ADD_CONDITIONAL_BREAKPOINT.label },
|
|
{ ...DebugEditorContextCommands.ADD_LOGPOINT, label: DebugCommands.ADD_LOGPOINT.label },
|
|
{ ...DebugEditorContextCommands.REMOVE_BREAKPOINT, label: DebugCommands.REMOVE_BREAKPOINT.label },
|
|
{ ...DebugEditorContextCommands.EDIT_BREAKPOINT, label: DebugCommands.EDIT_BREAKPOINT.label },
|
|
{ ...DebugEditorContextCommands.ENABLE_BREAKPOINT, label: nlsEnableBreakpoint('Breakpoint') },
|
|
{ ...DebugEditorContextCommands.DISABLE_BREAKPOINT, label: nlsDisableBreakpoint('Breakpoint') },
|
|
{ ...DebugEditorContextCommands.REMOVE_LOGPOINT, label: DebugCommands.REMOVE_LOGPOINT.label },
|
|
{ ...DebugEditorContextCommands.EDIT_LOGPOINT, label: DebugCommands.EDIT_LOGPOINT.label },
|
|
{ ...DebugEditorContextCommands.ENABLE_LOGPOINT, label: nlsEnableBreakpoint('Logpoint') },
|
|
{ ...DebugEditorContextCommands.DISABLE_LOGPOINT, label: nlsDisableBreakpoint('Logpoint') }
|
|
);
|
|
registerMenuActions([...DebugEditorModel.CONTEXT_MENU, '2_control'],
|
|
{ ...DebugEditorContextCommands.JUMP_TO_CURSOR, label: nls.localizeByDefault('Jump to Cursor') },
|
|
{ ...DebugEditorContextCommands.RUN_TO_LINE, label: DebugCommands.RUN_TO_LINE.label }
|
|
);
|
|
menus.linkCompoundMenuNode({ newParentPath: EDITOR_LINENUMBER_CONTEXT_MENU, submenuPath: DebugEditorModel.CONTEXT_MENU });
|
|
|
|
menus.registerSubmenu(DebugToolBar.MENU, nls.localize('theia/debug/debugToolbarMenu', 'Debug Toolbar Menu'));
|
|
registerMenuActions(DebugToolBar.CONTROLS,
|
|
{ ...DebugCommands.CONTINUE, when: 'debugState == stopped' },
|
|
{ ...DebugCommands.PAUSE, when: 'debugState != stopped' },
|
|
DebugCommands.STEP_OVER,
|
|
DebugCommands.STEP_INTO,
|
|
DebugCommands.STEP_OUT,
|
|
DebugCommands.RESTART,
|
|
DebugCommands.STOP
|
|
);
|
|
}
|
|
|
|
override registerCommands(registry: CommandRegistry): void {
|
|
super.registerCommands(registry);
|
|
registry.registerCommand(DebugCommands.START, {
|
|
execute: (config?: DebugSessionOptions) => {
|
|
const validConfig = DebugSessionOptions.is(config) ? config : undefined;
|
|
return this.start(false, validConfig);
|
|
}
|
|
});
|
|
registry.registerCommand(DebugCommands.START_NO_DEBUG, {
|
|
execute: (config?: DebugSessionOptions) => {
|
|
const validConfig = DebugSessionOptions.is(config) ? config : undefined;
|
|
return this.start(true, validConfig);
|
|
}
|
|
});
|
|
registry.registerCommand(DebugCommands.STOP, {
|
|
execute: () => this.manager.terminateSession(),
|
|
isEnabled: () => this.manager.state !== DebugState.Inactive
|
|
});
|
|
registry.registerCommand(DebugCommands.RESTART, {
|
|
execute: () => this.manager.restartSession(),
|
|
isEnabled: () => this.manager.state !== DebugState.Inactive
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.OPEN_CONFIGURATIONS, {
|
|
execute: () => this.configurations.openConfiguration()
|
|
});
|
|
registry.registerCommand(DebugCommands.ADD_CONFIGURATION, {
|
|
execute: () => this.configurations.addConfiguration()
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.STEP_OVER, {
|
|
execute: () => this.manager.currentThread && this.manager.currentThread.stepOver(),
|
|
isEnabled: () => this.manager.state === DebugState.Stopped
|
|
});
|
|
registry.registerCommand(DebugCommands.STEP_INTO, {
|
|
execute: () => this.manager.currentThread && this.manager.currentThread.stepIn(),
|
|
isEnabled: () => this.manager.state === DebugState.Stopped
|
|
});
|
|
registry.registerCommand(DebugCommands.STEP_OUT, {
|
|
execute: () => this.manager.currentThread && this.manager.currentThread.stepOut(),
|
|
isEnabled: () => this.manager.state === DebugState.Stopped
|
|
});
|
|
registry.registerCommand(DebugCommands.CONTINUE, {
|
|
execute: () => {
|
|
if (this.manager.state === DebugState.Stopped && this.manager.currentThread) {
|
|
this.manager.currentThread.continue();
|
|
}
|
|
},
|
|
// When there is a debug session, F5 should always be captured by this command
|
|
isEnabled: () => this.manager.state !== DebugState.Inactive
|
|
});
|
|
registry.registerCommand(DebugCommands.PAUSE, {
|
|
execute: () => this.manager.currentThread && this.manager.currentThread.pause(),
|
|
isEnabled: () => this.manager.state === DebugState.Running
|
|
});
|
|
registry.registerCommand(DebugCommands.PAUSE_ALL, {
|
|
execute: () => this.manager.currentSession && this.manager.currentSession.pauseAll(),
|
|
isEnabled: () => !!this.manager.currentSession && !!this.manager.currentSession.runningThreads.next().value
|
|
});
|
|
registry.registerCommand(DebugCommands.CONTINUE_ALL, {
|
|
execute: () => this.manager.currentSession && this.manager.currentSession.continueAll(),
|
|
isEnabled: () => !!this.manager.currentSession && !!this.manager.currentSession.stoppedThreads.next().value
|
|
});
|
|
|
|
registry.registerCommand(DebugThreadContextCommands.STEP_OVER, {
|
|
execute: () => this.selectedThread && this.selectedThread.stepOver(),
|
|
isEnabled: () => !!this.selectedThread && this.selectedThread.stopped,
|
|
isVisible: () => !!this.selectedThread
|
|
});
|
|
registry.registerCommand(DebugThreadContextCommands.STEP_INTO, {
|
|
execute: () => this.selectedThread && this.selectedThread.stepIn(),
|
|
isEnabled: () => !!this.selectedThread && this.selectedThread.stopped,
|
|
isVisible: () => !!this.selectedThread
|
|
});
|
|
registry.registerCommand(DebugThreadContextCommands.STEP_OUT, {
|
|
execute: () => this.selectedThread && this.selectedThread.stepOut(),
|
|
isEnabled: () => !!this.selectedThread && this.selectedThread.stopped,
|
|
isVisible: () => !!this.selectedThread
|
|
});
|
|
registry.registerCommand(DebugThreadContextCommands.CONTINUE, {
|
|
execute: () => this.selectedThread && this.selectedThread.continue(),
|
|
isEnabled: () => !!this.selectedThread && this.selectedThread.stopped,
|
|
isVisible: () => !!this.selectedThread && this.selectedThread.stopped,
|
|
});
|
|
registry.registerCommand(DebugThreadContextCommands.PAUSE, {
|
|
execute: () => this.selectedThread && this.selectedThread.pause(),
|
|
isEnabled: () => !!this.selectedThread && !this.selectedThread.stopped,
|
|
isVisible: () => !!this.selectedThread && !this.selectedThread.stopped,
|
|
});
|
|
registry.registerCommand(DebugThreadContextCommands.TERMINATE, {
|
|
execute: () => this.selectedThread && this.selectedThread.terminate(),
|
|
isEnabled: () => !!this.selectedThread && this.selectedThread.supportsTerminate,
|
|
isVisible: () => !!this.selectedThread && this.selectedThread.supportsTerminate
|
|
});
|
|
|
|
registry.registerCommand(DebugSessionContextCommands.STOP, {
|
|
execute: () => this.selectedSession && this.manager.terminateSession(this.selectedSession),
|
|
isEnabled: () => !!this.selectedSession && this.selectedSession.state !== DebugState.Inactive,
|
|
isVisible: () => !this.selectedThread
|
|
});
|
|
registry.registerCommand(DebugSessionContextCommands.RESTART, {
|
|
execute: () => this.selectedSession && this.manager.restartSession(this.selectedSession),
|
|
isEnabled: () => !!this.selectedSession && this.selectedSession.state !== DebugState.Inactive,
|
|
isVisible: () => !this.selectedThread
|
|
});
|
|
registry.registerCommand(DebugSessionContextCommands.CONTINUE_ALL, {
|
|
execute: () => this.selectedSession && this.selectedSession.continueAll(),
|
|
isEnabled: () => !!this.selectedSession && !!this.selectedSession.stoppedThreads.next().value,
|
|
isVisible: () => !this.selectedThread
|
|
});
|
|
registry.registerCommand(DebugSessionContextCommands.PAUSE_ALL, {
|
|
execute: () => this.selectedSession && this.selectedSession.pauseAll(),
|
|
isEnabled: () => !!this.selectedSession && !!this.selectedSession.runningThreads.next().value,
|
|
isVisible: () => !this.selectedThread
|
|
});
|
|
registry.registerCommand(DebugSessionContextCommands.REVEAL, {
|
|
execute: () => this.selectedSession && this.revealSession(this.selectedSession),
|
|
isEnabled: () => Boolean(this.selectedSession),
|
|
isVisible: () => !this.selectedThread && Boolean(this.selectedSession)
|
|
});
|
|
registry.registerCommand(DebugCommands.TOGGLE_BREAKPOINT, {
|
|
execute: () => this.editors.toggleBreakpoint(),
|
|
isEnabled: () => !!this.editors.model
|
|
});
|
|
registry.registerCommand(DebugCommands.INLINE_BREAKPOINT, {
|
|
execute: () => this.editors.addInlineBreakpoint(),
|
|
isEnabled: () => !!this.editors.model && !this.editors.getInlineBreakpoint()
|
|
});
|
|
registry.registerCommand(DebugCommands.ADD_CONDITIONAL_BREAKPOINT, {
|
|
execute: () => this.editors.addBreakpoint('condition'),
|
|
isEnabled: () => !!this.editors.model && !this.editors.anyBreakpoint()
|
|
});
|
|
registry.registerCommand(DebugCommands.ADD_LOGPOINT, {
|
|
execute: () => this.editors.addBreakpoint('logMessage'),
|
|
isEnabled: () => !!this.editors.model && !this.editors.anyBreakpoint()
|
|
});
|
|
registry.registerCommand(DebugCommands.ADD_FUNCTION_BREAKPOINT, {
|
|
execute: async () => {
|
|
const { labelProvider, breakpointManager, editorManager } = this;
|
|
const options = { labelProvider, breakpoints: breakpointManager, editorManager };
|
|
await new DebugFunctionBreakpoint(FunctionBreakpoint.create({ name: '' }), options).open();
|
|
},
|
|
isEnabled: widget => !(widget instanceof Widget) || widget instanceof DebugBreakpointsWidget,
|
|
isVisible: widget => !(widget instanceof Widget) || widget instanceof DebugBreakpointsWidget
|
|
});
|
|
registry.registerCommand(DebugCommands.ADD_DATA_BREAKPOINT, this.AddOrEditDataBreakpointAddress);
|
|
registry.registerCommand(DebugCommands.ENABLE_ALL_BREAKPOINTS, {
|
|
execute: () => this.breakpointManager.enableAllBreakpoints(true),
|
|
isEnabled: () => this.breakpointManager.hasBreakpoints()
|
|
});
|
|
registry.registerCommand(DebugCommands.ENABLE_SELECTED_BREAKPOINTS, {
|
|
execute: () => this.selectedBreakpoints.forEach(breakpoint => breakpoint.setEnabled(true)),
|
|
isVisible: () => this.selectedBreakpoints.some(breakpoint => !breakpoint.enabled),
|
|
isEnabled: () => this.selectedBreakpoints.some(breakpoint => !breakpoint.enabled)
|
|
});
|
|
registry.registerCommand(DebugCommands.DISABLE_ALL_BREAKPOINTS, {
|
|
execute: () => this.breakpointManager.enableAllBreakpoints(false),
|
|
isEnabled: () => this.breakpointManager.hasBreakpoints()
|
|
});
|
|
registry.registerCommand(DebugCommands.DISABLE_SELECTED_BREAKPOINTS, {
|
|
execute: () => this.selectedBreakpoints.forEach(breakpoint => breakpoint.setEnabled(false)),
|
|
isVisible: () => this.selectedBreakpoints.some(breakpoint => breakpoint.enabled),
|
|
isEnabled: () => this.selectedBreakpoints.some(breakpoint => breakpoint.enabled)
|
|
});
|
|
registry.registerCommand(DebugCommands.EDIT_BREAKPOINT, {
|
|
execute: async () => {
|
|
const { selectedBreakpoint, selectedFunctionBreakpoint, selectedLogpoint } = this;
|
|
if (selectedBreakpoint) {
|
|
await this.editors.editBreakpoint(selectedBreakpoint);
|
|
} else if (selectedFunctionBreakpoint) {
|
|
await selectedFunctionBreakpoint.open();
|
|
} else if (selectedLogpoint) {
|
|
await this.editors.editBreakpoint(selectedLogpoint);
|
|
}
|
|
},
|
|
isEnabled: () => this.selectedBreakpoints.length === 1 && (!!this.selectedBreakpoint || !!this.selectedFunctionBreakpoint || !!this.selectedLogpoint),
|
|
isVisible: () => this.selectedBreakpoints.length === 1 && (!!this.selectedBreakpoint || !!this.selectedFunctionBreakpoint || !!this.selectedLogpoint)
|
|
});
|
|
registry.registerCommand(DebugCommands.EDIT_LOGPOINT, {
|
|
execute: async () => {
|
|
const { selectedLogpoint } = this;
|
|
if (selectedLogpoint) {
|
|
await this.editors.editBreakpoint(selectedLogpoint);
|
|
}
|
|
},
|
|
isEnabled: () => this.selectedBreakpoints.length === 1 && !!this.selectedLogpoint,
|
|
isVisible: () => this.selectedBreakpoints.length === 1 && !!this.selectedLogpoint
|
|
});
|
|
registry.registerCommand(DebugCommands.EDIT_BREAKPOINT_CONDITION, {
|
|
execute: async () => {
|
|
const { selectedExceptionBreakpoint } = this;
|
|
if (selectedExceptionBreakpoint) {
|
|
await selectedExceptionBreakpoint.editCondition();
|
|
}
|
|
},
|
|
isEnabled: () => !!this.selectedExceptionBreakpoint?.data.raw.supportsCondition,
|
|
isVisible: () => !!this.selectedExceptionBreakpoint?.data.raw.supportsCondition
|
|
});
|
|
registry.registerCommand(DebugCommands.REMOVE_BREAKPOINT, {
|
|
execute: () => {
|
|
const selectedBreakpoint = this.selectedSettableBreakpoint;
|
|
if (selectedBreakpoint) {
|
|
selectedBreakpoint.remove();
|
|
}
|
|
},
|
|
isEnabled: () => this.selectedBreakpoints.length === 1 && Boolean(this.selectedSettableBreakpoint),
|
|
isVisible: () => this.selectedBreakpoints.length === 1 && Boolean(this.selectedSettableBreakpoint),
|
|
});
|
|
registry.registerCommand(DebugCommands.REMOVE_LOGPOINT, {
|
|
execute: () => {
|
|
const { selectedLogpoint } = this;
|
|
if (selectedLogpoint) {
|
|
selectedLogpoint.remove();
|
|
}
|
|
},
|
|
isEnabled: () => this.selectedBreakpoints.length === 1 && !!this.selectedLogpoint,
|
|
isVisible: () => this.selectedBreakpoints.length === 1 && !!this.selectedLogpoint
|
|
});
|
|
registry.registerCommand(DebugCommands.REMOVE_ALL_BREAKPOINTS, {
|
|
execute: () => this.breakpointManager.removeBreakpoints(),
|
|
isEnabled: () => this.breakpointManager.hasBreakpoints(),
|
|
isVisible: widget => !(widget instanceof Widget) || (widget instanceof DebugBreakpointsWidget)
|
|
});
|
|
registry.registerCommand(DebugCommands.REMOVE_SELECTED_BREAKPOINTS, {
|
|
execute: () => this.selectedBreakpoints.forEach(breakpoint => breakpoint.remove()),
|
|
isEnabled: () => this.selectedBreakpoints.length > 1,
|
|
isVisible: widget => (!(widget instanceof Widget) || (widget instanceof DebugBreakpointsWidget)) && this.selectedBreakpoints.length > 1
|
|
});
|
|
registry.registerCommand(DebugCommands.TOGGLE_BREAKPOINTS_ENABLED, {
|
|
execute: () => this.breakpointManager.breakpointsEnabled = !this.breakpointManager.breakpointsEnabled,
|
|
isVisible: arg => arg instanceof DebugBreakpointsWidget
|
|
});
|
|
registry.registerCommand(DebugCommands.SHOW_HOVER, {
|
|
execute: () => this.editors.showHover(),
|
|
isEnabled: () => this.editors.canShowHover()
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.EVALUATE_IN_DEBUG_CONSOLE, {
|
|
execute: async () => {
|
|
const { model } = this.editors;
|
|
if (model) {
|
|
const { editor } = model;
|
|
const { selection, document } = editor;
|
|
const value = document.getText(selection) || document.getLineContent(selection.start.line + 1).trim();
|
|
const consoleWidget = await this.console.openView({ reveal: true, activate: false });
|
|
await consoleWidget.execute(value);
|
|
}
|
|
},
|
|
isEnabled: () => !!this.editors.model && !!this.manager.currentFrame,
|
|
isVisible: () => !!this.editors.model && !!this.manager.currentFrame
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.ADD_TO_WATCH, {
|
|
execute: async () => {
|
|
const { model } = this.editors;
|
|
if (model) {
|
|
const { editor } = model;
|
|
const selection = editor.getControl().getSelection();
|
|
if (selection) {
|
|
const expression = editor.getControl().getModel()?.getValueInRange(selection) ||
|
|
(await this.expressionProvider.getEvaluatableExpression(editor, selection))?.matchingExpression;
|
|
if (expression) {
|
|
this.watchManager.addWatchExpression(expression);
|
|
const watchWidget = this.widgetManager.tryGetWidget(DebugWatchWidget.FACTORY_ID);
|
|
if (watchWidget) {
|
|
await this.shell.activateWidget(watchWidget.id);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
isEnabled: () => !!this.editors.model && this.manager.inDebugMode,
|
|
isVisible: () => !!this.editors.model && this.manager.inDebugMode
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.JUMP_TO_CURSOR, {
|
|
execute: () => {
|
|
const model = this.editors.model;
|
|
if (model && this.manager.currentThread) {
|
|
this.manager.currentThread.jumpToCursor(
|
|
model.editor.getResourceUri(),
|
|
model.position
|
|
);
|
|
}
|
|
},
|
|
isEnabled: () => !!this.manager.currentThread && this.manager.currentThread.supportsGoto,
|
|
isVisible: () => !!this.manager.currentThread && this.manager.currentThread.supportsGoto
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.RUN_TO_CURSOR, {
|
|
execute: async () => {
|
|
const { model } = this.editors;
|
|
if (model) {
|
|
const { editor, position } = model;
|
|
await this.runTo(editor.getResourceUri(), position.lineNumber, position.column);
|
|
}
|
|
},
|
|
isEnabled: () => !!this.editors.model && !!this.manager.currentThread?.stopped,
|
|
isVisible: () => !!this.editors.model && !!this.manager.currentThread?.stopped
|
|
});
|
|
registry.registerCommand(DebugCommands.RUN_TO_LINE, {
|
|
execute: async () => {
|
|
const { model } = this.editors;
|
|
if (model) {
|
|
const { editor, position } = model;
|
|
await this.runTo(editor.getResourceUri(), position.lineNumber);
|
|
}
|
|
},
|
|
isEnabled: () => !!this.editors.model && !!this.manager.currentThread?.stopped,
|
|
isVisible: () => !!this.editors.model && !!this.manager.currentThread?.stopped
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.RESTART_FRAME, {
|
|
execute: () => this.selectedFrame && this.selectedFrame.restart(),
|
|
isEnabled: () => !!this.selectedFrame
|
|
});
|
|
registry.registerCommand(DebugCommands.COPY_CALL_STACK, {
|
|
execute: () => {
|
|
const { frames } = this;
|
|
const selection = document.getSelection();
|
|
if (frames && selection) {
|
|
selection.selectAllChildren(frames.node);
|
|
document.execCommand('copy');
|
|
}
|
|
},
|
|
isEnabled: () => document.queryCommandSupported('copy'),
|
|
isVisible: () => document.queryCommandSupported('copy')
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.SET_VARIABLE_VALUE, {
|
|
execute: () => this.selectedVariable && this.selectedVariable.open(),
|
|
isEnabled: () => !!this.selectedVariable && this.selectedVariable.supportSetVariable && !this.selectedVariable.readOnly,
|
|
isVisible: () => !!this.selectedVariable && this.selectedVariable.supportSetVariable
|
|
});
|
|
registry.registerCommand(DebugCommands.COPY_VARIABLE_VALUE, {
|
|
execute: () => this.selectedVariable && this.selectedVariable.copyValue(),
|
|
isEnabled: () => !!this.selectedVariable && this.selectedVariable.supportCopyValue,
|
|
isVisible: () => !!this.selectedVariable && this.selectedVariable.supportCopyValue
|
|
});
|
|
registry.registerCommand(DebugCommands.COPY_VARIABLE_AS_EXPRESSION, {
|
|
execute: () => this.selectedVariable && this.selectedVariable.copyAsExpression(),
|
|
isEnabled: () => !!this.selectedVariable && this.selectedVariable.supportCopyAsExpression,
|
|
isVisible: () => !!this.selectedVariable && this.selectedVariable.supportCopyAsExpression
|
|
});
|
|
registry.registerCommand(DebugCommands.WATCH_VARIABLE, {
|
|
execute: () => {
|
|
const evaluateName = this.selectedVariable?.evaluateName;
|
|
if (evaluateName) {
|
|
this.watchManager.addWatchExpression(evaluateName);
|
|
}
|
|
},
|
|
isEnabled: () => !!this.selectedVariable?.evaluateName,
|
|
isVisible: () => !!this.selectedVariable?.evaluateName,
|
|
});
|
|
|
|
// Debug context menu commands
|
|
registry.registerCommand(DebugEditorContextCommands.ADD_BREAKPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.toggleBreakpoint(this.asPosition(position)),
|
|
isEnabled: position => this.isPosition(position) && !this.editors.anyBreakpoint(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !this.editors.anyBreakpoint(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.ADD_CONDITIONAL_BREAKPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.addBreakpoint('condition', this.asPosition(position)),
|
|
isEnabled: position => this.isPosition(position) && !this.editors.anyBreakpoint(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !this.editors.anyBreakpoint(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.ADD_LOGPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.addBreakpoint('logMessage', this.asPosition(position)),
|
|
isEnabled: position => this.isPosition(position) && !this.editors.anyBreakpoint(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !this.editors.anyBreakpoint(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.REMOVE_BREAKPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.toggleBreakpoint(this.asPosition(position)),
|
|
isEnabled: position => this.isPosition(position) && !!this.editors.getBreakpoint(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !!this.editors.getBreakpoint(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.EDIT_BREAKPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.editBreakpoint(this.asPosition(position)),
|
|
isEnabled: position => this.isPosition(position) && !!this.editors.getBreakpoint(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !!this.editors.getBreakpoint(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.ENABLE_BREAKPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.setBreakpointEnabled(this.asPosition(position), true),
|
|
isEnabled: position => this.isPosition(position) && this.editors.getBreakpointEnabled(this.asPosition(position)) === false,
|
|
isVisible: position => this.isPosition(position) && this.editors.getBreakpointEnabled(this.asPosition(position)) === false
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.DISABLE_BREAKPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.setBreakpointEnabled(this.asPosition(position), false),
|
|
isEnabled: position => this.isPosition(position) && !!this.editors.getBreakpointEnabled(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !!this.editors.getBreakpointEnabled(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.REMOVE_LOGPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.toggleBreakpoint(this.asPosition(position)),
|
|
isEnabled: position => this.isPosition(position) && !!this.editors.getLogpoint(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !!this.editors.getLogpoint(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.EDIT_LOGPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.editBreakpoint(this.asPosition(position)),
|
|
isEnabled: position => this.isPosition(position) && !!this.editors.getLogpoint(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !!this.editors.getLogpoint(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.ENABLE_LOGPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.setBreakpointEnabled(this.asPosition(position), true),
|
|
isEnabled: position => this.isPosition(position) && this.editors.getLogpointEnabled(this.asPosition(position)) === false,
|
|
isVisible: position => this.isPosition(position) && this.editors.getLogpointEnabled(this.asPosition(position)) === false
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.DISABLE_LOGPOINT, {
|
|
execute: position => this.isPosition(position) && this.editors.setBreakpointEnabled(this.asPosition(position), false),
|
|
isEnabled: position => this.isPosition(position) && !!this.editors.getLogpointEnabled(this.asPosition(position)),
|
|
isVisible: position => this.isPosition(position) && !!this.editors.getLogpointEnabled(this.asPosition(position))
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.JUMP_TO_CURSOR, {
|
|
execute: position => {
|
|
if (this.isPosition(position) && this.editors.currentUri && this.manager.currentThread) {
|
|
this.manager.currentThread.jumpToCursor(this.editors.currentUri, this.asPosition(position));
|
|
}
|
|
},
|
|
isEnabled: () => !!this.manager.currentThread && this.manager.currentThread.supportsGoto,
|
|
isVisible: () => !!this.manager.currentThread && this.manager.currentThread.supportsGoto
|
|
});
|
|
registry.registerCommand(DebugEditorContextCommands.RUN_TO_LINE, {
|
|
execute: async position => {
|
|
if (this.isPosition(position)) {
|
|
const { currentUri } = this.editors;
|
|
if (currentUri) {
|
|
await this.runTo(currentUri, position.lineNumber);
|
|
}
|
|
}
|
|
},
|
|
isEnabled: position => this.isPosition(position) && !!this.editors.currentUri && !!this.manager.currentThread?.stopped,
|
|
isVisible: position => this.isPosition(position) && !!this.editors.currentUri && !!this.manager.currentThread?.stopped
|
|
});
|
|
|
|
registry.registerCommand(DebugBreakpointWidgetCommands.ACCEPT, {
|
|
execute: () => this.editors.acceptBreakpoint()
|
|
});
|
|
registry.registerCommand(DebugBreakpointWidgetCommands.CLOSE, {
|
|
execute: () => this.editors.closeBreakpoint()
|
|
});
|
|
|
|
registry.registerCommand(DebugCommands.ADD_WATCH_EXPRESSION, {
|
|
execute: widget => {
|
|
if (widget instanceof Widget) {
|
|
if (widget instanceof DebugWatchWidget) {
|
|
widget.viewModel.addWatchExpression();
|
|
}
|
|
} else if (this.watch) {
|
|
this.watch.viewModel.addWatchExpression();
|
|
}
|
|
},
|
|
isEnabled: widget => widget instanceof Widget ? widget instanceof DebugWatchWidget : !!this.watch,
|
|
isVisible: widget => widget instanceof Widget ? widget instanceof DebugWatchWidget : !!this.watch
|
|
});
|
|
registry.registerCommand(DebugCommands.EDIT_WATCH_EXPRESSION, {
|
|
execute: () => {
|
|
const { watchExpression } = this;
|
|
if (watchExpression) {
|
|
watchExpression.open();
|
|
}
|
|
},
|
|
isEnabled: () => !!this.watchExpression,
|
|
isVisible: () => !!this.watchExpression
|
|
});
|
|
registry.registerCommand(DebugCommands.COPY_WATCH_EXPRESSION_VALUE, {
|
|
execute: () => this.watchExpression && this.watchExpression.copyValue(),
|
|
isEnabled: () => !!this.watchExpression && this.watchExpression.supportCopyValue,
|
|
isVisible: () => !!this.watchExpression && this.watchExpression.supportCopyValue
|
|
});
|
|
registry.registerCommand(DebugCommands.COLLAPSE_ALL_WATCH_EXPRESSIONS, {
|
|
execute: widget => {
|
|
if (widget instanceof DebugWatchWidget) {
|
|
const root = widget.model.root;
|
|
widget.model.collapseAll(CompositeTreeNode.is(root) ? root : undefined);
|
|
}
|
|
},
|
|
isEnabled: widget => widget instanceof DebugWatchWidget,
|
|
isVisible: widget => widget instanceof DebugWatchWidget
|
|
});
|
|
registry.registerCommand(DebugCommands.REMOVE_WATCH_EXPRESSION, {
|
|
execute: () => {
|
|
const { watch, watchExpression } = this;
|
|
if (watch && watchExpression) {
|
|
watch.viewModel.removeWatchExpression(watchExpression);
|
|
}
|
|
},
|
|
isEnabled: () => !!this.watchExpression,
|
|
isVisible: () => !!this.watchExpression
|
|
});
|
|
registry.registerCommand(DebugCommands.REMOVE_ALL_WATCH_EXPRESSIONS, {
|
|
execute: widget => {
|
|
if (widget instanceof Widget) {
|
|
if (widget instanceof DebugWatchWidget) {
|
|
widget.viewModel.removeWatchExpressions();
|
|
}
|
|
} else if (this.watch) {
|
|
this.watch.viewModel.removeWatchExpressions();
|
|
}
|
|
},
|
|
isEnabled: widget => widget instanceof Widget ? widget instanceof DebugWatchWidget : !!this.watch,
|
|
isVisible: widget => widget instanceof Widget ? widget instanceof DebugWatchWidget : !!this.watch
|
|
});
|
|
}
|
|
|
|
override registerKeybindings(keybindings: KeybindingRegistry): void {
|
|
super.registerKeybindings(keybindings);
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.START.id,
|
|
keybinding: 'f5',
|
|
when: '!inDebugMode'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.START_NO_DEBUG.id,
|
|
keybinding: 'ctrl+f5',
|
|
when: '!inDebugMode'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.STOP.id,
|
|
keybinding: 'shift+f5',
|
|
when: 'inDebugMode'
|
|
});
|
|
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.RESTART.id,
|
|
keybinding: 'shift+ctrlcmd+f5',
|
|
when: 'inDebugMode'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.STEP_OVER.id,
|
|
keybinding: 'f10',
|
|
when: 'inDebugMode'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.STEP_INTO.id,
|
|
keybinding: 'f11',
|
|
when: 'inDebugMode'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.STEP_OUT.id,
|
|
keybinding: 'shift+f11',
|
|
when: 'inDebugMode'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.CONTINUE.id,
|
|
keybinding: 'f5',
|
|
when: 'inDebugMode'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.PAUSE.id,
|
|
keybinding: 'f6',
|
|
when: 'inDebugMode'
|
|
});
|
|
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.TOGGLE_BREAKPOINT.id,
|
|
keybinding: 'f9',
|
|
when: 'editorTextFocus'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugCommands.INLINE_BREAKPOINT.id,
|
|
keybinding: 'shift+f9',
|
|
when: 'editorTextFocus'
|
|
});
|
|
|
|
keybindings.registerKeybinding({
|
|
command: DebugBreakpointWidgetCommands.ACCEPT.id,
|
|
keybinding: 'enter',
|
|
when: 'breakpointWidgetFocus && !suggestWidgetVisible'
|
|
});
|
|
keybindings.registerKeybinding({
|
|
command: DebugBreakpointWidgetCommands.CLOSE.id,
|
|
keybinding: 'esc',
|
|
when: 'isBreakpointWidgetVisible || (breakpointWidgetFocus && !suggestWidgetVisible)'
|
|
});
|
|
}
|
|
|
|
registerToolbarItems(toolbar: TabBarToolbarRegistry): void {
|
|
toolbar.registerItem({
|
|
id: DebugCommands.ADD_FUNCTION_BREAKPOINT.id,
|
|
command: DebugCommands.ADD_FUNCTION_BREAKPOINT.id,
|
|
icon: codicon('add'),
|
|
tooltip: DebugCommands.ADD_FUNCTION_BREAKPOINT.label
|
|
});
|
|
toolbar.registerItem({
|
|
id: DebugCommands.ADD_DATA_BREAKPOINT.id,
|
|
command: DebugCommands.ADD_DATA_BREAKPOINT.id,
|
|
icon: codicon('variable-group'),
|
|
tooltip: DebugCommands.ADD_DATA_BREAKPOINT.label,
|
|
onDidChange: this.manager.onDidStopDebugSession as unknown as Event<void>
|
|
});
|
|
toolbar.registerItem({
|
|
id: DebugCommands.TOGGLE_BREAKPOINTS_ENABLED.id,
|
|
command: DebugCommands.TOGGLE_BREAKPOINTS_ENABLED.id,
|
|
icon: codicon('activate-breakpoints'),
|
|
priority: 1
|
|
});
|
|
toolbar.registerItem({
|
|
id: DebugCommands.REMOVE_ALL_BREAKPOINTS.id,
|
|
command: DebugCommands.REMOVE_ALL_BREAKPOINTS.id,
|
|
icon: codicon('close-all'),
|
|
priority: 2
|
|
});
|
|
|
|
toolbar.registerItem({
|
|
id: DebugCommands.ADD_WATCH_EXPRESSION.id,
|
|
command: DebugCommands.ADD_WATCH_EXPRESSION.id,
|
|
icon: codicon('add'),
|
|
tooltip: DebugCommands.ADD_WATCH_EXPRESSION.label
|
|
});
|
|
toolbar.registerItem({
|
|
id: DebugCommands.COLLAPSE_ALL_WATCH_EXPRESSIONS.id,
|
|
command: DebugCommands.COLLAPSE_ALL_WATCH_EXPRESSIONS.id,
|
|
icon: codicon('collapse-all'),
|
|
tooltip: DebugCommands.COLLAPSE_ALL_WATCH_EXPRESSIONS.label,
|
|
priority: 1
|
|
});
|
|
toolbar.registerItem({
|
|
id: DebugCommands.REMOVE_ALL_WATCH_EXPRESSIONS.id,
|
|
command: DebugCommands.REMOVE_ALL_WATCH_EXPRESSIONS.id,
|
|
icon: codicon('close-all'),
|
|
tooltip: DebugCommands.REMOVE_ALL_WATCH_EXPRESSIONS.label,
|
|
priority: 2
|
|
});
|
|
}
|
|
|
|
protected async openSession(
|
|
session: DebugSession,
|
|
options?: {
|
|
reveal?: boolean;
|
|
}
|
|
): Promise<DebugWidget | DebugSessionWidget> {
|
|
const { reveal } = {
|
|
reveal: true,
|
|
...options
|
|
};
|
|
const debugWidget = await this.openView({ reveal });
|
|
// Only switch to this session if it has a stopped thread
|
|
// Don't switch to background sessions that are just starting up
|
|
if (session.currentThread && session.currentThread.stopped) {
|
|
debugWidget.sessionManager.currentSession = session;
|
|
}
|
|
return debugWidget['sessionWidget'];
|
|
}
|
|
|
|
protected revealSession(session: DebugSession): DebugSessionWidget | undefined {
|
|
const widget = this.tryGetWidget()?.['sessionWidget'];
|
|
if (widget) {
|
|
this.shell.revealWidget(widget.id);
|
|
}
|
|
return widget;
|
|
}
|
|
|
|
async start(noDebug?: boolean, debugSessionOptions?: DebugSessionOptions): Promise<void> {
|
|
let current = debugSessionOptions || this.configurations.current;
|
|
// If no configurations are currently present, create the `launch.json` and prompt users to select the config.
|
|
if (!current) {
|
|
await this.configurations.addConfiguration();
|
|
return;
|
|
}
|
|
|
|
if (noDebug !== undefined) {
|
|
if (current.configuration) {
|
|
current = {
|
|
...current,
|
|
configuration: {
|
|
...current.configuration,
|
|
noDebug
|
|
}
|
|
};
|
|
} else {
|
|
current = {
|
|
...current,
|
|
noDebug
|
|
};
|
|
}
|
|
}
|
|
|
|
await this.manager.start(current);
|
|
}
|
|
|
|
async runTo(uri: URI, line: number, column?: number): Promise<void> {
|
|
const thread = this.manager.currentThread;
|
|
if (!thread) {
|
|
return;
|
|
}
|
|
const checkThread = () => {
|
|
if (thread.stopped && thread === this.manager.currentThread) {
|
|
return true;
|
|
}
|
|
console.warn('Cannot run to the specified location. The current thread has changed or is not stopped.');
|
|
return false;
|
|
};
|
|
if (!checkThread()) {
|
|
return;
|
|
}
|
|
const breakpoint = SourceBreakpoint.create(uri, { line, column });
|
|
let shouldRemoveBreakpoint = this.breakpointManager.addBreakpoint(breakpoint);
|
|
const removeBreakpoint = () => {
|
|
const breakpoints = this.breakpointManager.getBreakpoints(uri);
|
|
const newBreakpoints = breakpoints.filter(bp => bp.id !== breakpoint.id);
|
|
if (breakpoints.length !== newBreakpoints.length) {
|
|
this.breakpointManager.setBreakpoints(uri, newBreakpoints);
|
|
}
|
|
};
|
|
try {
|
|
const sessionBreakpoint = await this.verifyBreakpoint(breakpoint, thread.session);
|
|
if (!checkThread()) {
|
|
return;
|
|
}
|
|
if (!sessionBreakpoint || !sessionBreakpoint.installed || !sessionBreakpoint.verified) {
|
|
this.messageService.warn(nls.localize('theia/debug/cannotRunToThisLocation',
|
|
'Could not run the current thread to the specified location.'
|
|
));
|
|
return;
|
|
}
|
|
const rawBreakpoint = sessionBreakpoint.raw!; // an installed breakpoint always has the underlying raw breakpoint
|
|
if (rawBreakpoint.line !== line || (column && rawBreakpoint.column !== column)) {
|
|
const shouldRun = await new ConfirmDialog({
|
|
title: nls.localize('theia/debug/confirmRunToShiftedPosition_title',
|
|
'Cannot run the current thread to exactly the specified location'),
|
|
msg: nls.localize('theia/debug/confirmRunToShiftedPosition_msg',
|
|
'The target position will be shifted to Ln {0}, Col {1}. Run anyway?', rawBreakpoint.line, rawBreakpoint.column || 1),
|
|
ok: Dialog.YES,
|
|
cancel: Dialog.NO
|
|
}).open();
|
|
if (!shouldRun || !checkThread()) {
|
|
return;
|
|
}
|
|
}
|
|
if (shouldRemoveBreakpoint) {
|
|
Event.toPromise(Event.filter(
|
|
Event.any(this.manager.onDidStopDebugSession, this.manager.onDidDestroyDebugSession),
|
|
session => session === thread.session
|
|
)).then(removeBreakpoint);
|
|
}
|
|
await thread.continue();
|
|
shouldRemoveBreakpoint = false;
|
|
} finally {
|
|
if (shouldRemoveBreakpoint) {
|
|
removeBreakpoint();
|
|
}
|
|
}
|
|
}
|
|
|
|
protected async verifyBreakpoint(breakpoint: SourceBreakpoint, session: DebugSession, timeout = 2000): Promise<DebugBreakpoint | undefined> {
|
|
let sessionBreakpoint = session.getBreakpoint(breakpoint.id);
|
|
if (!sessionBreakpoint || !sessionBreakpoint.installed || !sessionBreakpoint.verified) {
|
|
try {
|
|
await waitForEvent(Event.filter(session.onDidChangeBreakpoints, () => {
|
|
sessionBreakpoint = session.getBreakpoint(breakpoint.id);
|
|
return !!sessionBreakpoint && sessionBreakpoint.installed && sessionBreakpoint.verified;
|
|
}), timeout); // wait up to `timeout` ms for the breakpoint to become installed and verified
|
|
} catch (e) {
|
|
if (!(e instanceof CancellationError)) { // ignore the `CancellationError` on timeout
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
return sessionBreakpoint;
|
|
}
|
|
|
|
get threads(): DebugThreadsWidget | undefined {
|
|
const { currentWidget } = this.shell;
|
|
return currentWidget instanceof DebugThreadsWidget && currentWidget || undefined;
|
|
}
|
|
get selectedSession(): DebugSession | undefined {
|
|
const { threads } = this;
|
|
return threads && threads.selectedElement instanceof DebugSession && threads.selectedElement || undefined;
|
|
}
|
|
get selectedThread(): DebugThread | undefined {
|
|
const { threads } = this;
|
|
return threads && threads.selectedElement instanceof DebugThread && threads.selectedElement || undefined;
|
|
}
|
|
|
|
get frames(): DebugStackFramesWidget | undefined {
|
|
const { currentWidget } = this.shell;
|
|
return currentWidget instanceof DebugStackFramesWidget && currentWidget || undefined;
|
|
}
|
|
get selectedFrame(): DebugStackFrame | undefined {
|
|
const { frames } = this;
|
|
return frames && frames.selectedElement instanceof DebugStackFrame && frames.selectedElement || undefined;
|
|
}
|
|
|
|
get breakpoints(): DebugBreakpointsWidget | undefined {
|
|
const { currentWidget } = this.shell;
|
|
return currentWidget instanceof DebugBreakpointsWidget && currentWidget || undefined;
|
|
}
|
|
get selectedAnyBreakpoint(): DebugBreakpoint | undefined {
|
|
const { breakpoints } = this;
|
|
const selectedElement = breakpoints && breakpoints.selectedElement;
|
|
return selectedElement instanceof DebugBreakpoint ? selectedElement : undefined;
|
|
}
|
|
get selectedBreakpoint(): DebugSourceBreakpoint | undefined {
|
|
const breakpoint = this.selectedAnyBreakpoint;
|
|
return breakpoint && breakpoint instanceof DebugSourceBreakpoint && !breakpoint.logMessage ? breakpoint : undefined;
|
|
}
|
|
get selectedBreakpoints(): DebugBreakpoint[] {
|
|
const { breakpoints } = this;
|
|
return breakpoints && breakpoints.model.selectedNodes
|
|
.filter(TreeElementNode.is)
|
|
.map(node => node.element)
|
|
.filter(element => element instanceof DebugBreakpoint) as DebugBreakpoint[] || [];
|
|
}
|
|
get selectedLogpoint(): DebugSourceBreakpoint | undefined {
|
|
const breakpoint = this.selectedAnyBreakpoint;
|
|
return breakpoint && breakpoint instanceof DebugSourceBreakpoint && !!breakpoint.logMessage ? breakpoint : undefined;
|
|
}
|
|
get selectedFunctionBreakpoint(): DebugFunctionBreakpoint | undefined {
|
|
const breakpoint = this.selectedAnyBreakpoint;
|
|
return breakpoint && breakpoint instanceof DebugFunctionBreakpoint ? breakpoint : undefined;
|
|
}
|
|
get selectedInstructionBreakpoint(): DebugInstructionBreakpoint | undefined {
|
|
if (this.selectedAnyBreakpoint instanceof DebugInstructionBreakpoint) {
|
|
return this.selectedAnyBreakpoint;
|
|
}
|
|
}
|
|
get selectedExceptionBreakpoint(): DebugExceptionBreakpoint | undefined {
|
|
const { breakpoints } = this;
|
|
const selectedElement = breakpoints && breakpoints.selectedElement;
|
|
return selectedElement instanceof DebugExceptionBreakpoint ? selectedElement : undefined;
|
|
}
|
|
|
|
get selectedSettableBreakpoint(): DebugFunctionBreakpoint | DebugInstructionBreakpoint | DebugSourceBreakpoint | undefined {
|
|
const selected = this.selectedAnyBreakpoint;
|
|
if (selected instanceof DebugFunctionBreakpoint || selected instanceof DebugInstructionBreakpoint || selected instanceof DebugSourceBreakpoint) {
|
|
return selected;
|
|
}
|
|
}
|
|
|
|
get consoleWidget(): ConsoleWidget | undefined {
|
|
const { currentWidget } = this.shell;
|
|
return currentWidget instanceof ConsoleWidget && currentWidget.id === DebugConsoleContribution.options.id && currentWidget || undefined;
|
|
}
|
|
get variables(): DebugVariablesWidget | undefined {
|
|
const { currentWidget } = this.shell;
|
|
return currentWidget instanceof DebugVariablesWidget && currentWidget || undefined;
|
|
}
|
|
get variablesSource(): DebugHoverWidget | DebugVariablesWidget | ConsoleContentWidget | undefined {
|
|
const hover = this.editors.model?.hover;
|
|
if (hover?.isVisible) {
|
|
return hover;
|
|
}
|
|
return this.variables ?? this.consoleWidget?.content;
|
|
}
|
|
get selectedVariable(): DebugVariable | undefined {
|
|
const { variablesSource } = this;
|
|
return variablesSource && variablesSource.selectedElement instanceof DebugVariable && variablesSource.selectedElement || undefined;
|
|
}
|
|
|
|
get watch(): DebugWatchWidget | undefined {
|
|
const { currentWidget } = this.shell;
|
|
return currentWidget instanceof DebugWatchWidget && currentWidget || undefined;
|
|
}
|
|
get watchExpression(): DebugWatchExpression | undefined {
|
|
const { watch } = this;
|
|
return watch && watch.selectedElement instanceof DebugWatchExpression && watch.selectedElement || undefined;
|
|
}
|
|
|
|
protected isPosition(position: unknown): position is monaco.IPosition {
|
|
return monaco.Position.isIPosition(position);
|
|
}
|
|
|
|
protected asPosition(position: monaco.IPosition): monaco.Position {
|
|
return monaco.Position.lift(position);
|
|
}
|
|
|
|
registerColors(colors: ColorRegistry): void {
|
|
colors.register(
|
|
// Debug colors should be aligned with https://code.visualstudio.com/api/references/theme-color#debug-colors
|
|
{
|
|
id: 'editor.stackFrameHighlightBackground',
|
|
defaults: {
|
|
dark: '#ffff0033',
|
|
light: '#ffff6673',
|
|
hcDark: '#fff600',
|
|
hcLight: '#ffff6673'
|
|
}, description: nls.localizeByDefault('Background color for the highlight of line at the top stack frame position.')
|
|
},
|
|
{
|
|
id: 'editor.focusedStackFrameHighlightBackground',
|
|
defaults: {
|
|
dark: '#7abd7a4d',
|
|
light: '#cee7ce73',
|
|
hcDark: '#cee7ce',
|
|
hcLight: '#cee7ce73'
|
|
}, description: nls.localizeByDefault('Background color for the highlight of line at focused stack frame position.')
|
|
},
|
|
// Status bar colors should be aligned with debugging colors from https://code.visualstudio.com/api/references/theme-color#status-bar-colors
|
|
{
|
|
id: 'statusBar.debuggingBackground', defaults: {
|
|
dark: '#CC6633',
|
|
light: '#CC6633',
|
|
hcDark: '#CC6633',
|
|
hcLight: '#B5200D'
|
|
}, description: nls.localizeByDefault('Status bar background color when a program is being debugged. The status bar is shown in the bottom of the window')
|
|
},
|
|
{
|
|
id: 'statusBar.debuggingForeground', defaults: {
|
|
dark: 'statusBar.foreground',
|
|
light: 'statusBar.foreground',
|
|
hcDark: 'statusBar.foreground',
|
|
hcLight: 'statusBar.foreground'
|
|
}, description: nls.localizeByDefault('Status bar foreground color when a program is being debugged. The status bar is shown in the bottom of the window')
|
|
},
|
|
{
|
|
id: 'statusBar.debuggingBorder', defaults: {
|
|
dark: 'statusBar.border',
|
|
light: 'statusBar.border',
|
|
hcDark: 'statusBar.border',
|
|
hcLight: 'statusBar.border'
|
|
}, description: nls.localizeByDefault(
|
|
'Status bar border color separating to the sidebar and editor when a program is being debugged. The status bar is shown in the bottom of the window')
|
|
},
|
|
// Debug Exception Widget colors should be aligned with
|
|
// https://github.com/microsoft/vscode/blob/ff5f581425da6230b6f9216ecf19abf6c9d285a6/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts#L23
|
|
{
|
|
id: 'debugExceptionWidget.border', defaults: {
|
|
dark: '#a31515',
|
|
light: '#a31515',
|
|
hcDark: '#a31515',
|
|
hcLight: '#a31515'
|
|
}, description: nls.localizeByDefault('Exception widget border color.'),
|
|
},
|
|
{
|
|
id: 'debugExceptionWidget.background', defaults: {
|
|
dark: '#420b0d',
|
|
light: '#f1dfde',
|
|
hcDark: '#420b0d',
|
|
hcLight: '#f1dfde'
|
|
}, description: nls.localizeByDefault('Exception widget background color.')
|
|
},
|
|
// Debug Icon colors should be aligned with
|
|
// https://code.visualstudio.com/api/references/theme-color#debug-icons-colors
|
|
{
|
|
id: 'debugIcon.breakpointForeground', defaults: {
|
|
dark: '#E51400',
|
|
light: '#E51400',
|
|
hcDark: '#E51400',
|
|
hcLight: '#E51400'
|
|
},
|
|
description: nls.localizeByDefault('Icon color for breakpoints.')
|
|
},
|
|
{
|
|
id: 'debugIcon.breakpointDisabledForeground', defaults: {
|
|
dark: '#848484',
|
|
light: '#848484',
|
|
hcDark: '#848484',
|
|
hcLight: '#848484'
|
|
},
|
|
description: nls.localizeByDefault('Icon color for disabled breakpoints.')
|
|
},
|
|
{
|
|
id: 'debugIcon.breakpointUnverifiedForeground', defaults: {
|
|
dark: '#848484',
|
|
light: '#848484',
|
|
hcDark: '#848484',
|
|
hcLight: '#848484'
|
|
},
|
|
description: nls.localizeByDefault('Icon color for unverified breakpoints.')
|
|
},
|
|
{
|
|
id: 'debugIcon.breakpointCurrentStackframeForeground', defaults: {
|
|
dark: '#FFCC00',
|
|
light: '#BE8700',
|
|
hcDark: '#FFCC00',
|
|
hcLight: '#BE8700'
|
|
},
|
|
description: nls.localizeByDefault('Icon color for the current breakpoint stack frame.')
|
|
},
|
|
{
|
|
id: 'debugIcon.breakpointStackframeForeground', defaults: {
|
|
dark: '#89D185',
|
|
light: '#89D185',
|
|
hcDark: '#89D185',
|
|
hcLight: '#89D185'
|
|
},
|
|
description: nls.localizeByDefault('Icon color for all breakpoint stack frames.')
|
|
},
|
|
{
|
|
id: 'debugIcon.startForeground', defaults: {
|
|
dark: '#89D185',
|
|
light: '#388A34',
|
|
hcDark: '#89D185',
|
|
hcLight: '#388A34'
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for start debugging.')
|
|
},
|
|
{
|
|
id: 'debugIcon.pauseForeground', defaults: {
|
|
dark: '#75BEFF',
|
|
light: '#007ACC',
|
|
hcDark: '#75BEFF',
|
|
hcLight: '#007ACC'
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for pause.')
|
|
},
|
|
{
|
|
id: 'debugIcon.stopForeground', defaults: {
|
|
dark: '#F48771',
|
|
light: '#A1260D',
|
|
hcDark: '#F48771',
|
|
hcLight: '#A1260D'
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for stop.')
|
|
},
|
|
{
|
|
id: 'debugIcon.disconnectForeground', defaults: {
|
|
dark: '#F48771',
|
|
light: '#A1260D',
|
|
hcDark: '#F48771',
|
|
hcLight: '#A1260D'
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for disconnect.')
|
|
},
|
|
{
|
|
id: 'debugIcon.restartForeground', defaults: {
|
|
dark: '#89D185',
|
|
light: '#388A34',
|
|
hcDark: '#89D185',
|
|
hcLight: '#388A34'
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for restart.')
|
|
},
|
|
{
|
|
id: 'debugIcon.stepOverForeground', defaults: {
|
|
dark: '#75BEFF',
|
|
light: '#007ACC',
|
|
hcDark: '#75BEFF',
|
|
hcLight: '#007ACC',
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for step over.')
|
|
},
|
|
{
|
|
id: 'debugIcon.stepIntoForeground', defaults: {
|
|
dark: '#75BEFF',
|
|
light: '#007ACC',
|
|
hcDark: '#75BEFF',
|
|
hcLight: '#007ACC'
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for step into.')
|
|
},
|
|
{
|
|
id: 'debugIcon.stepOutForeground', defaults: {
|
|
dark: '#75BEFF',
|
|
light: '#007ACC',
|
|
hcDark: '#75BEFF',
|
|
hcLight: '#007ACC',
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for step over.')
|
|
},
|
|
{
|
|
id: 'debugIcon.continueForeground', defaults: {
|
|
dark: '#75BEFF',
|
|
light: '#007ACC',
|
|
hcDark: '#75BEFF',
|
|
hcLight: '#007ACC'
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for continue.')
|
|
},
|
|
{
|
|
id: 'debugIcon.stepBackForeground', defaults: {
|
|
dark: '#75BEFF',
|
|
light: '#007ACC',
|
|
hcDark: '#75BEFF',
|
|
hcLight: '#007ACC'
|
|
}, description: nls.localizeByDefault('Debug toolbar icon for step back.')
|
|
},
|
|
{
|
|
id: 'debugConsole.infoForeground', defaults: {
|
|
dark: 'editorInfo.foreground',
|
|
light: 'editorInfo.foreground',
|
|
hcDark: 'foreground',
|
|
hcLight: 'foreground'
|
|
}, description: 'Foreground color for info messages in debug REPL console.' // this description is present in VS Code, but is not currently localized there
|
|
},
|
|
{
|
|
id: 'debugConsole.warningForeground', defaults: {
|
|
dark: 'editorWarning.foreground',
|
|
light: 'editorWarning.foreground',
|
|
hcDark: '#008000',
|
|
hcLight: 'editorWarning.foreground'
|
|
},
|
|
description: 'Foreground color for warning messages in debug REPL console.' // this description is present in VS Code, but is not currently localized there
|
|
},
|
|
{
|
|
id: 'debugConsole.errorForeground', defaults: {
|
|
dark: 'errorForeground',
|
|
light: 'errorForeground',
|
|
hcDark: 'errorForeground',
|
|
hcLight: 'errorForeground'
|
|
},
|
|
description: 'Foreground color for error messages in debug REPL console.', // this description is present in VS Code, but is not currently localized there
|
|
},
|
|
{
|
|
id: 'debugConsole.sourceForeground', defaults: {
|
|
dark: 'foreground',
|
|
light: 'foreground',
|
|
hcDark: 'foreground',
|
|
hcLight: 'foreground'
|
|
},
|
|
description: 'Foreground color for source filenames in debug REPL console.', // this description is present in VS Code, but is not currently localized there
|
|
},
|
|
{
|
|
id: 'debugConsoleInputIcon.foreground', defaults: {
|
|
dark: 'foreground',
|
|
light: 'foreground',
|
|
hcDark: 'foreground',
|
|
hcLight: 'foreground'
|
|
},
|
|
description: 'Foreground color for debug console input marker icon.' // this description is present in VS Code, but is not currently localized there
|
|
}
|
|
);
|
|
}
|
|
|
|
protected updateStatusBar(): void {
|
|
if (this.debuggingStatusBar === document.body.classList.contains('theia-mod-debugging')) {
|
|
return;
|
|
}
|
|
document.body.classList.toggle('theia-mod-debugging');
|
|
}
|
|
|
|
protected get debuggingStatusBar(): boolean {
|
|
if (this.manager.state < DebugState.Running) {
|
|
return false;
|
|
}
|
|
|
|
const session = this.manager.currentSession;
|
|
if (session) {
|
|
if (session.configuration.noDebug) {
|
|
return false;
|
|
}
|
|
if (this.getOption(session, 'suppressDebugStatusbar')) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected getOption(session: DebugSession | undefined, option: keyof {
|
|
[Property in keyof DebugConfiguration]: boolean;
|
|
}): boolean | undefined {
|
|
// If session is undefined there will be no option
|
|
if (!session) {
|
|
return false;
|
|
}
|
|
// If undefined take the value of the parent
|
|
if (option in session.configuration && session.configuration[option] !== undefined) {
|
|
return session.configuration[option];
|
|
}
|
|
|
|
return this.getOption(session.parentSession, option);
|
|
}
|
|
}
|