mirror of
https://github.com/microsoft/vscode.git
synced 2026-10-05 15:36:22 +01:00
debug: bring together all ways to start debugging
fixes #22312 fixes #21835
This commit is contained in:
1 parent
63389c46a2
commit
65a12a2b50
6 files changed
+90
-98
No files matched your search
@@ -12,10 +12,9 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IDebugService, IConfig, State, IProcess, IThread, IEnablement, IBreakpoint, IStackFrame, IFunctionBreakpoint, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, IExpression, REPL_ID }
|
||||
import { IDebugService, State, IProcess, IThread, IEnablement, IBreakpoint, IStackFrame, IFunctionBreakpoint, IDebugEditorContribution, EDITOR_CONTRIBUTION_ID, IExpression, REPL_ID }
|
||||
from 'vs/workbench/parts/debug/common/debug';
|
||||
import { Variable, Expression, Thread, Breakpoint, Process } from 'vs/workbench/parts/debug/common/debugModel';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -105,11 +104,6 @@ export class ConfigureAction extends AbstractDebugAction {
|
||||
}
|
||||
}
|
||||
|
||||
interface StartSessionResult {
|
||||
status: 'ok' | 'initialConfiguration' | 'saveConfiguration';
|
||||
content?: string;
|
||||
};
|
||||
|
||||
export class StartAction extends AbstractDebugAction {
|
||||
static ID = 'workbench.action.debug.start';
|
||||
static LABEL = nls.localize('startDebug', "Start Debugging");
|
||||
@@ -117,10 +111,7 @@ export class StartAction extends AbstractDebugAction {
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@ICommandService private commandService: ICommandService,
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService,
|
||||
@IFileService private fileService: IFileService,
|
||||
@ITextFileService private textFileService: ITextFileService
|
||||
@IWorkspaceContextService private contextService: IWorkspaceContextService
|
||||
) {
|
||||
super(id, label, 'debug-action start', debugService, keybindingService);
|
||||
this.debugService.getViewModel().onDidSelectConfiguration(() => {
|
||||
@@ -129,53 +120,11 @@ export class StartAction extends AbstractDebugAction {
|
||||
}
|
||||
|
||||
public run(): TPromise<any> {
|
||||
return this.textFileService.saveAll().then(() => {
|
||||
if (this.debugService.getModel().getProcesses().length === 0) {
|
||||
this.debugService.removeReplExpressions();
|
||||
}
|
||||
const manager = this.debugService.getConfigurationManager();
|
||||
const configName = this.debugService.getViewModel().selectedConfigurationName;
|
||||
const compound = manager.getCompound(configName);
|
||||
if (compound) {
|
||||
return this.commandService.executeCommand('_workbench.startDebug', configName);
|
||||
}
|
||||
|
||||
let configuration = manager.getConfiguration(configName);
|
||||
return manager.getStartSessionCommand(configuration ? configuration.type : undefined).then(commandAndType => {
|
||||
configuration = this.massageConfiguartion(configuration);
|
||||
if (commandAndType && commandAndType.command) {
|
||||
return this.commandService.executeCommand(commandAndType.command, configuration || this.getDefaultConfiguration()).then((result: StartSessionResult) => {
|
||||
if (this.contextService.getWorkspace()) {
|
||||
if (result && result.status === 'initialConfiguration') {
|
||||
return manager.openConfigFile(false, commandAndType.type);
|
||||
}
|
||||
|
||||
if (result && result.status === 'saveConfiguration') {
|
||||
return this.fileService.updateContent(manager.configFileUri, result.content).then(() => manager.openConfigFile(false));
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
if (configName) {
|
||||
return this.commandService.executeCommand('_workbench.startDebug', configuration || configName);
|
||||
}
|
||||
|
||||
if (this.contextService.getWorkspace() && commandAndType) {
|
||||
return manager.openConfigFile(false, commandAndType.type);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
return this.debugService.startDebugging(undefined, this.isNoDebug());
|
||||
}
|
||||
|
||||
protected getDefaultConfiguration(): any {
|
||||
return {};
|
||||
}
|
||||
|
||||
protected massageConfiguartion(config: IConfig): IConfig {
|
||||
return config;
|
||||
protected isNoDebug(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Disabled if the launch drop down shows the launch config that is already running.
|
||||
@@ -190,27 +139,8 @@ export class RunAction extends StartAction {
|
||||
static ID = 'workbench.action.debug.run';
|
||||
static LABEL = nls.localize('startWithoutDebugging', "Start Without Debugging");
|
||||
|
||||
constructor(id: string, label: string,
|
||||
@IDebugService debugService: IDebugService,
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@ICommandService commandService: ICommandService,
|
||||
@IWorkspaceContextService contextService: IWorkspaceContextService,
|
||||
@IFileService fileService: IFileService,
|
||||
@ITextFileService textFileService: ITextFileService
|
||||
) {
|
||||
super(id, label, debugService, keybindingService, commandService, contextService, fileService, textFileService);
|
||||
}
|
||||
|
||||
protected getDefaultConfiguration(): any {
|
||||
return { noDebug: true };
|
||||
}
|
||||
|
||||
protected massageConfiguartion(config: IConfig): IConfig {
|
||||
if (config) {
|
||||
config.noDebug = true;
|
||||
}
|
||||
|
||||
return config;
|
||||
protected isNoDebug(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ class DebugEntry extends Model.QuickOpenEntry {
|
||||
}
|
||||
// Run selected debug configuration
|
||||
this.debugService.getViewModel().setSelectedConfigurationName(this.configurationName);
|
||||
this.debugService.createProcess(this.configurationName).done(undefined, errors.onUnexpectedError);
|
||||
this.debugService.startDebugging().done(undefined, errors.onUnexpectedError);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -488,10 +488,17 @@ export interface IDebugService {
|
||||
*/
|
||||
removeWatchExpressions(id?: string): void;
|
||||
|
||||
/**
|
||||
* Starts debugging. If the configName is not passed uses the selected configuration in the debug dropdown.
|
||||
* Also saves all files, manages if compounds are present in the configuration
|
||||
* and calls the startSessionCommand if an adapter registered it.
|
||||
*/
|
||||
startDebugging(configName?: string, noDebug?: boolean): TPromise<any>;
|
||||
|
||||
/**
|
||||
* Creates a new debug process. Depending on the configuration will either 'launch' or 'attach'.
|
||||
*/
|
||||
createProcess(configurationOrName: IConfig | string): TPromise<any>;
|
||||
createProcess(config: IConfig): TPromise<any>;
|
||||
|
||||
/**
|
||||
* Restarts a process or creates a new one if there is no active session.
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ICommonCodeEditor } from 'vs/editor/common/editorCommon';
|
||||
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
|
||||
import { IListService } from 'vs/platform/list/browser/listService';
|
||||
import { IDebugService, IEnablement, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { IDebugService, IConfig, IEnablement, CONTEXT_NOT_IN_DEBUG_MODE, CONTEXT_IN_DEBUG_MODE, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_WATCH_EXPRESSIONS_FOCUSED, CONTEXT_VARIABLES_FOCUSED, EDITOR_CONTRIBUTION_ID, IDebugEditorContribution } from 'vs/workbench/parts/debug/common/debug';
|
||||
import { Expression, Variable, Breakpoint, FunctionBreakpoint } from 'vs/workbench/parts/debug/common/debugModel';
|
||||
import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions';
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
@@ -21,13 +21,18 @@ export function registerCommands(): void {
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: '_workbench.startDebug',
|
||||
weight: KeybindingsRegistry.WEIGHT.workbenchContrib(),
|
||||
handler(accessor: ServicesAccessor, configurationOrName: any) {
|
||||
handler(accessor: ServicesAccessor, configurationOrName: IConfig | string) {
|
||||
const debugService = accessor.get(IDebugService);
|
||||
if (!configurationOrName) {
|
||||
configurationOrName = debugService.getViewModel().selectedConfigurationName;
|
||||
}
|
||||
|
||||
return debugService.createProcess(configurationOrName);
|
||||
if (typeof configurationOrName === 'string') {
|
||||
debugService.getViewModel().setSelectedConfigurationName(configurationOrName);
|
||||
return debugService.startDebugging();
|
||||
} else {
|
||||
return debugService.createProcess(configurationOrName);
|
||||
}
|
||||
},
|
||||
when: CONTEXT_NOT_IN_DEBUG_MODE,
|
||||
primary: undefined
|
||||
|
||||
@@ -28,6 +28,7 @@ import { IWindowsService } from 'vs/platform/windows/common/windows';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
|
||||
import { TelemetryAppenderClient } from 'vs/platform/telemetry/common/telemetryIpc';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import * as debug from 'vs/workbench/parts/debug/common/debug';
|
||||
import { RawDebugSession } from 'vs/workbench/parts/debug/electron-browser/rawDebugSession';
|
||||
@@ -56,6 +57,11 @@ const DEBUG_EXCEPTION_BREAKPOINTS_KEY = 'debug.exceptionbreakpoint';
|
||||
const DEBUG_WATCH_EXPRESSIONS_KEY = 'debug.watchexpressions';
|
||||
const DEBUG_SELECTED_CONFIG_NAME_KEY = 'debug.selectedconfigname';
|
||||
|
||||
interface StartSessionResult {
|
||||
status: 'ok' | 'initialConfiguration' | 'saveConfiguration';
|
||||
content?: string;
|
||||
};
|
||||
|
||||
export class DebugService implements debug.IDebugService {
|
||||
public _serviceBrand: any;
|
||||
|
||||
@@ -92,6 +98,7 @@ export class DebugService implements debug.IDebugService {
|
||||
@ITaskService private taskService: ITaskService,
|
||||
@IFileService private fileService: IFileService,
|
||||
@IConfigurationService private configurationService: IConfigurationService,
|
||||
@ICommandService private commandService: ICommandService
|
||||
) {
|
||||
this.toDispose = [];
|
||||
this.toDisposeOnSessionEnd = new Map<string, lifecycle.IDisposable[]>();
|
||||
@@ -559,24 +566,63 @@ export class DebugService implements debug.IDebugService {
|
||||
this.model.removeWatchExpressions(id);
|
||||
}
|
||||
|
||||
public createProcess(configurationOrName: debug.IConfig | string): TPromise<any> {
|
||||
public startDebugging(configName?: string, noDebug = false): TPromise<any> {
|
||||
return this.textFileService.saveAll().then(() => {
|
||||
if (this.model.getProcesses().length === 0) {
|
||||
this.removeReplExpressions();
|
||||
}
|
||||
const manager = this.getConfigurationManager();
|
||||
configName = configName || this.viewModel.selectedConfigurationName;
|
||||
const config = manager.getConfiguration(configName);
|
||||
const compound = manager.getCompound(configName);
|
||||
if (compound) {
|
||||
if (!compound.configurations) {
|
||||
return TPromise.wrapError(new Error(nls.localize({ key: 'compoundMustHaveConfigurations', comment: ['compound indicates a "compounds" configuration item', '"configurations" is an attribute and should not be localized'] },
|
||||
"Compound must have \"configurations\" attribute set in order to start multiple configurations.")));
|
||||
}
|
||||
|
||||
return TPromise.join(compound.configurations.map(name => this.startDebugging(name)));
|
||||
}
|
||||
if (configName && !config) {
|
||||
return TPromise.wrapError(new Error(nls.localize('configMissing', "Configuration '{0}' is missing in 'launch.json'.", configName)));
|
||||
}
|
||||
|
||||
return manager.getStartSessionCommand(config ? config.type : undefined).then(commandAndType => {
|
||||
if (noDebug && config) {
|
||||
config.noDebug = true;
|
||||
}
|
||||
if (commandAndType && commandAndType.command) {
|
||||
const defaultConfig = noDebug ? { noDebug: true } : {};
|
||||
return this.commandService.executeCommand(commandAndType.command, config || defaultConfig).then((result: StartSessionResult) => {
|
||||
if (this.contextService.getWorkspace()) {
|
||||
if (result && result.status === 'initialConfiguration') {
|
||||
return manager.openConfigFile(false, commandAndType.type);
|
||||
}
|
||||
|
||||
if (result && result.status === 'saveConfiguration') {
|
||||
return this.fileService.updateContent(manager.configFileUri, result.content).then(() => manager.openConfigFile(false));
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
if (config) {
|
||||
return this.createProcess(config);
|
||||
}
|
||||
if (this.contextService.getWorkspace() && commandAndType) {
|
||||
return manager.openConfigFile(false, commandAndType.type);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public createProcess(config: debug.IConfig): TPromise<any> {
|
||||
return this.textFileService.saveAll().then(() => this.configurationService.reloadConfiguration()) // make sure configuration is up to date
|
||||
.then(() => this.extensionService.onReady()
|
||||
.then(() => {
|
||||
const compound = typeof configurationOrName === 'string' ? this.configurationManager.getCompound(configurationOrName) : null;
|
||||
if (compound) {
|
||||
if (!compound.configurations) {
|
||||
return TPromise.wrapError(new Error(nls.localize({ key: 'compoundMustHaveConfigurations', comment: ['compound indicates a "compounds" configuration item', '"configurations" is an attribute and should not be localized'] },
|
||||
"Compound must have \"configurations\" attribute set in order to start multiple configurations.")));
|
||||
}
|
||||
|
||||
return TPromise.join(compound.configurations.map(name => this.createProcess(name)));
|
||||
}
|
||||
const config = typeof configurationOrName === 'string' ? this.configurationManager.getConfiguration(configurationOrName) : configurationOrName;
|
||||
if (!config) {
|
||||
return TPromise.wrapError(new Error(nls.localize('configMissing', "Configuration '{0}' is missing in 'launch.json'.", configurationOrName)));
|
||||
}
|
||||
|
||||
return this.configurationManager.resloveConfiguration(config).then(resolvedConfig => {
|
||||
if (!resolvedConfig) {
|
||||
// User canceled resolving of interactive variables, silently return
|
||||
|
||||
@@ -71,7 +71,11 @@ export class MockDebugService implements debug.IDebugService {
|
||||
|
||||
public removeWatchExpressions(id?: string): void { }
|
||||
|
||||
public createProcess(configurationOrName: debug.IConfig | string): TPromise<any> {
|
||||
public startDebugging(configName?: string, noDebug?: boolean): TPromise<any> {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
public createProcess(config: debug.IConfig): TPromise<any> {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user