diff --git a/src/vs/workbench/parts/debug/browser/debugActions.ts b/src/vs/workbench/parts/debug/browser/debugActions.ts index d320a436b18b..121bbad4fe12 100644 --- a/src/vs/workbench/parts/debug/browser/debugActions.ts +++ b/src/vs/workbench/parts/debug/browser/debugActions.ts @@ -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 { - 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; } } diff --git a/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts b/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts index 7e3a817e2fe0..c4cf22bb0cd8 100644 --- a/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts +++ b/src/vs/workbench/parts/debug/browser/debugQuickOpen.ts @@ -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; } diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 247595748048..b94c9f95fc6a 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -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; + /** * Creates a new debug process. Depending on the configuration will either 'launch' or 'attach'. */ - createProcess(configurationOrName: IConfig | string): TPromise; + createProcess(config: IConfig): TPromise; /** * Restarts a process or creates a new one if there is no active session. diff --git a/src/vs/workbench/parts/debug/electron-browser/debugCommands.ts b/src/vs/workbench/parts/debug/electron-browser/debugCommands.ts index 178dfd1a489f..2afc6c433824 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugCommands.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugCommands.ts @@ -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 diff --git a/src/vs/workbench/parts/debug/electron-browser/debugService.ts b/src/vs/workbench/parts/debug/electron-browser/debugService.ts index e3dfae5fec60..c1ce6a1a4f00 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugService.ts @@ -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(); @@ -559,24 +566,63 @@ export class DebugService implements debug.IDebugService { this.model.removeWatchExpressions(id); } - public createProcess(configurationOrName: debug.IConfig | string): TPromise { + public startDebugging(configName?: string, noDebug = false): TPromise { + 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 { 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 diff --git a/src/vs/workbench/parts/debug/test/common/mockDebug.ts b/src/vs/workbench/parts/debug/test/common/mockDebug.ts index 119b7caeaa80..2676e666f536 100644 --- a/src/vs/workbench/parts/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/parts/debug/test/common/mockDebug.ts @@ -71,7 +71,11 @@ export class MockDebugService implements debug.IDebugService { public removeWatchExpressions(id?: string): void { } - public createProcess(configurationOrName: debug.IConfig | string): TPromise { + public startDebugging(configName?: string, noDebug?: boolean): TPromise { + return TPromise.as(null); + } + + public createProcess(config: debug.IConfig): TPromise { return TPromise.as(null); }