diff --git a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts index 421cb44dafb3530ec8129ec11e5525e76fe64fb0..84b6d6bf048b4232265191e94b2fc976720facbb 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadDebugService.ts @@ -6,7 +6,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import uri from 'vs/base/common/uri'; -import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IAdapterExecutable, ITerminalLauncher, ITerminalSettings } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IAdapterExecutable, ITerminalSettings, IDebugAdapter } from 'vs/workbench/parts/debug/common/debug'; import { TPromise } from 'vs/base/common/winjs.base'; import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, @@ -24,8 +24,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { private _proxy: ExtHostDebugServiceShape; private _toDispose: IDisposable[]; private _breakpointEventsActive: boolean; - private _debugAdapters: Map; - private _debugAdaptersHandleCounter = 1; + private _extensionHostDebugAdapterProvider: ExtensionHostDebugAdapterProvider; constructor( extHostContext: IExtHostContext, @@ -52,20 +51,11 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { } })); - this._debugAdapters = new Map(); - - // register a default EH DA provider - debugService.getConfigurationManager().registerDebugAdapterProvider('*', { - createDebugAdapter: (debugType, adapterInfo) => { - const handle = this._debugAdaptersHandleCounter++; - const da = new ExtensionHostDebugAdapter(handle, this._proxy, debugType, adapterInfo); - this._debugAdapters.set(handle, da); - return da; - } - }); + this._extensionHostDebugAdapterProvider = new ExtensionHostDebugAdapterProvider(this._proxy); + } - // register a default EH terminal launcher - debugService.getConfigurationManager().registerEHTerminalLauncher(new ExtensionHostTerminalLauncher(this._proxy)); + public $registerDebugTypes(debugTypes: string[]) { + this._toDispose.push(this.debugService.getConfigurationManager().registerDebugAdapterProvider(debugTypes, this._extensionHostDebugAdapterProvider)); } public dispose(): void { @@ -237,15 +227,15 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape { } }); - this._debugAdapters.get(handle).acceptMessage(message); + this._extensionHostDebugAdapterProvider.acceptMessage(handle, message); } public $acceptDAError(handle: number, name: string, message: string, stack: string) { - this._debugAdapters.get(handle).fireError(handle, new Error(`${name}: ${message}\n${stack}`)); + this._extensionHostDebugAdapterProvider.acceptDAError(handle, new Error(`${name}: ${message}\n${stack}`)); } public $acceptDAExit(handle: number, code: number, signal: string) { - this._debugAdapters.get(handle).fireExit(handle, code, signal); + this._extensionHostDebugAdapterProvider.acceptDAExit(handle, code, signal); } } @@ -285,9 +275,32 @@ class ExtensionHostDebugAdapter extends AbstractDebugAdapter { } } -class ExtensionHostTerminalLauncher implements ITerminalLauncher { +class ExtensionHostDebugAdapterProvider { + + private _debugAdapters: Map; + private _debugAdaptersHandleCounter = 1; constructor(private _proxy: ExtHostDebugServiceShape) { + this._debugAdapters = new Map(); + } + + acceptMessage(handle: number, message: DebugProtocol.ProtocolMessage) { + this._debugAdapters.get(handle).acceptMessage(message); + } + + acceptDAError(handle: number, error: Error) { + this._debugAdapters.get(handle).fireError(handle, error); + } + + acceptDAExit(handle: number, code: number, signal: string) { + this._debugAdapters.get(handle).fireExit(handle, code, signal); + } + + createDebugAdapter(debugType: string, adapterInfo): IDebugAdapter { + const handle = this._debugAdaptersHandleCounter++; + const da = new ExtensionHostDebugAdapter(handle, this._proxy, debugType, adapterInfo); + this._debugAdapters.set(handle, da); + return da; } runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise { diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index d1bd5db0104897f386751a2a829d79528eeb19d7..d467d8c9e76592ee86f1735c105659f5434f8072 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -463,6 +463,7 @@ export interface MainThreadSCMShape extends IDisposable { export type DebugSessionUUID = string; export interface MainThreadDebugServiceShape extends IDisposable { + $registerDebugTypes(debugTypes: string[]); $acceptDAMessage(handle: number, message: DebugProtocol.ProtocolMessage); $acceptDAError(handle: number, name: string, message: string, stack: string); $acceptDAExit(handle: number, code: number, signal: string); diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index b6fcdc55a474be9ce4b40574f580bbd5226a8636..7e7a0fe405b90d19883db2689ea6900f3ed4de18 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -19,7 +19,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { DebugAdapter, convertToVSCPaths, convertToDAPaths } from 'vs/workbench/parts/debug/node/debugAdapter'; import * as paths from 'vs/base/common/paths'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; -import { IAdapterExecutable, ITerminalSettings } from 'vs/workbench/parts/debug/common/debug'; +import { IAdapterExecutable, ITerminalSettings, IDebuggerContribution } from 'vs/workbench/parts/debug/common/debug'; import { getTerminalLauncher } from 'vs/workbench/parts/debug/node/terminals'; @@ -81,10 +81,33 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { this._breakpointEventsActive = false; this._debugAdapters = new Map(); + + // register all debug extensions + const debugTypes: string[] = []; + for (const ed of this._extensionService.getAllExtensionDescriptions()) { + if (ed.contributes) { + const debuggers = ed.contributes['debuggers']; + if (debuggers && debuggers.length > 0) { + for (const dbg of debuggers) { + // only debugger contributions with a "label" are considered a "main" debugger contribution + if (dbg.type && dbg.label) { + debugTypes.push(dbg.type); + } + } + } + } + } + if (debugTypes.length > 0) { + this._debugServiceProxy.$registerDebugTypes(debugTypes); + } } public $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise { - return getTerminalLauncher().runInTerminal(args, config); + const terminalLauncher = getTerminalLauncher(); + if (terminalLauncher) { + return terminalLauncher.runInTerminal(args, config); + } + return void 0; } public $startDASession(handle: number, debugType: string, adpaterExecutable: IAdapterExecutable | null): TPromise { diff --git a/src/vs/workbench/parts/debug/common/debug.ts b/src/vs/workbench/parts/debug/common/debug.ts index 687eb04aacc95efa159f0babed7e51a76d762a45..5f43b0a3c1a81ba7e9d1c9b83f692f1f511deb5a 100644 --- a/src/vs/workbench/parts/debug/common/debug.ts +++ b/src/vs/workbench/parts/debug/common/debug.ts @@ -394,7 +394,7 @@ export interface IDebugAdapter extends IDisposable { stopSession(): TPromise; } -export interface IDebugAdapterProvider { +export interface IDebugAdapterProvider extends ITerminalLauncher { createDebugAdapter(debugType: string, adapterInfo: IAdapterExecutable | null): IDebugAdapter; } @@ -496,11 +496,9 @@ export interface IConfigurationManager { resolveConfigurationByProviders(folderUri: uri | undefined, type: string | undefined, debugConfiguration: any): TPromise; debugAdapterExecutable(folderUri: uri | undefined, type: string): TPromise; - registerDebugAdapterProvider(debugType: string, debugAdapterLauncher: IDebugAdapterProvider); - createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable | null): IDebugAdapter; - - registerEHTerminalLauncher(launcher: ITerminalLauncher): void; - runInTerminal(extensionHost: boolean, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise; + registerDebugAdapterProvider(debugTypes: string[], debugAdapterLauncher: IDebugAdapterProvider): IDisposable; + createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable | null): IDebugAdapter | undefined; + runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise; } export interface ILaunch { diff --git a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts index d722e8e68fa22e7a98bd81f607a309c7cadf0546..8f07813290a09e9545b433f465ab97ca40553f55 100644 --- a/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/parts/debug/electron-browser/debugConfigurationManager.ts @@ -26,7 +26,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IDebugConfigurationProvider, IDebuggerContribution, ICompound, IDebugConfiguration, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch, IAdapterExecutable, IDebugAdapterProvider, IDebugAdapter, ITerminalLauncher, ITerminalSettings } from 'vs/workbench/parts/debug/common/debug'; +import { IDebugConfigurationProvider, IDebuggerContribution, ICompound, IDebugConfiguration, IConfig, IEnvConfig, IGlobalConfig, IConfigurationManager, ILaunch, IAdapterExecutable, IDebugAdapterProvider, IDebugAdapter, ITerminalSettings, ITerminalLauncher } from 'vs/workbench/parts/debug/common/debug'; import { Debugger } from 'vs/workbench/parts/debug/node/debugger'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; @@ -231,8 +231,7 @@ export class ConfigurationManager implements IConfigurationManager { private _onDidSelectConfigurationName = new Emitter(); private providers: IDebugConfigurationProvider[]; private debugAdapterProviders: Map; - private _terminalLauncher: ITerminalLauncher; - private _ehTerminalLauncher: ITerminalLauncher; + private terminalLauncher: ITerminalLauncher; constructor( @@ -266,10 +265,10 @@ export class ConfigurationManager implements IConfigurationManager { debugConfigurationProvider.handle = handle; this.providers = this.providers.filter(p => p.handle !== handle); this.providers.push(debugConfigurationProvider); - const adapter = this.getDebugger(debugConfigurationProvider.type); + const dbg = this.getDebugger(debugConfigurationProvider.type); // Check if the provider contributes provideDebugConfigurations method - if (adapter && debugConfigurationProvider.provideDebugConfigurations) { - adapter.hasConfigurationProvider = true; + if (dbg && debugConfigurationProvider.provideDebugConfigurations) { + dbg.hasConfigurationProvider = true; } } @@ -306,32 +305,37 @@ export class ConfigurationManager implements IConfigurationManager { return TPromise.as(undefined); } - public registerDebugAdapterProvider(debugType: string, debugAdapterLauncher: IDebugAdapterProvider) { - this.debugAdapterProviders.set(debugType, debugAdapterLauncher); + public registerDebugAdapterProvider(debugTypes: string[], debugAdapterLauncher: IDebugAdapterProvider): IDisposable { + debugTypes.forEach(debugType => this.debugAdapterProviders.set(debugType, debugAdapterLauncher)); + return { + dispose: () => { + debugTypes.forEach(debugType => this.debugAdapterProviders.delete(debugType)); + } + }; } - public createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable): IDebugAdapter { - let dap = this.debugAdapterProviders.get(debugType); - if (!dap) { - dap = this.debugAdapterProviders.get('*'); - } - return dap.createDebugAdapter(debugType, adapterExecutable); + private getDebugAdapterProvider(type: string): IDebugAdapterProvider | undefined { + return this.debugAdapterProviders.get(type); } - public registerEHTerminalLauncher(launcher: ITerminalLauncher): void { - this._ehTerminalLauncher = launcher; + public createDebugAdapter(debugType: string, adapterExecutable: IAdapterExecutable): IDebugAdapter | undefined { + let dap = this.getDebugAdapterProvider(debugType); + if (dap) { + return dap.createDebugAdapter(debugType, adapterExecutable); + } + return undefined; } - public runInTerminal(extensionHost: boolean, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise { + public runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise { - if (extensionHost && this._ehTerminalLauncher) { - return this._ehTerminalLauncher.runInTerminal(args, config); - } else { - if (!this._terminalLauncher) { - this._terminalLauncher = this.instantiationService.createInstance(TerminalLauncher); + let tl: ITerminalLauncher = this.getDebugAdapterProvider(debugType); + if (!tl) { + if (!this.terminalLauncher) { + this.terminalLauncher = this.instantiationService.createInstance(TerminalLauncher); } - return this._terminalLauncher.runInTerminal(args, config); + tl = this.terminalLauncher; } + return tl.runInTerminal(args, config); } private registerListeners(lifecycleService: ILifecycleService): void { diff --git a/src/vs/workbench/parts/debug/node/debugAdapter.ts b/src/vs/workbench/parts/debug/node/debugAdapter.ts index 943bb658fb92227c8f5703ad7eced97274b92c33..381b7def6f0b4f7ee608c00ee24ad9774573d515 100644 --- a/src/vs/workbench/parts/debug/node/debugAdapter.ts +++ b/src/vs/workbench/parts/debug/node/debugAdapter.ts @@ -249,7 +249,7 @@ export class DebugAdapter extends StreamDebugAdapter { "Cannot determine executable for debug adapter '{0}'.", this._debugType))); } - if (this._adapterExecutable.command === 'node' /*&& this.outputService*/) { + if (this._adapterExecutable.command === 'node' && this._outputService) { if (Array.isArray(this._adapterExecutable.args) && this._adapterExecutable.args.length > 0) { stdfork.fork(this._adapterExecutable.args[0], this._adapterExecutable.args.slice(1), {}, (err, child) => { if (err) { diff --git a/src/vs/workbench/parts/debug/node/debugger.ts b/src/vs/workbench/parts/debug/node/debugger.ts index c6e420b6f4544e692fc263750c1ea9a0250ec08a..b3e1907e2ce15597cffe24d03e670f3f66fbdba2 100644 --- a/src/vs/workbench/parts/debug/node/debugger.ts +++ b/src/vs/workbench/parts/debug/node/debugger.ts @@ -62,7 +62,8 @@ export class Debugger { public runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): TPromise { const debugConfigs = this.configurationService.getValue('debug'); const config = this.configurationService.getValue('terminal'); - return this.configurationManager.runInTerminal(debugConfigs && debugConfigs.extensionHostDebugAdapter, args, config); + const type = debugConfigs.extensionHostDebugAdapter ? this.type : '*'; + return this.configurationManager.runInTerminal(type, args, config); } public get aiKey(): string { diff --git a/src/vs/workbench/parts/debug/node/terminals.ts b/src/vs/workbench/parts/debug/node/terminals.ts index 492aed9cba1f5a56dacb5174b2f2ecd7c82b59e8..c0cfca5db357ab78637129e6aeb2b65a19f6b558 100644 --- a/src/vs/workbench/parts/debug/node/terminals.ts +++ b/src/vs/workbench/parts/debug/node/terminals.ts @@ -64,14 +64,14 @@ let _DEFAULT_TERMINAL_WINDOWS: string = null; export function getDefaultTerminalWindows(): string { if (!_DEFAULT_TERMINAL_WINDOWS) { const isWoW64 = !!process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'); - _DEFAULT_TERMINAL_WINDOWS = `${process.env.windir ? process.env.windir : 'C:'}\\${isWoW64 ? 'Sysnative' : 'System32'}\\cmd.exe`; + _DEFAULT_TERMINAL_WINDOWS = `${process.env.windir ? process.env.windir : 'C:\\Windows'}\\${isWoW64 ? 'Sysnative' : 'System32'}\\cmd.exe`; } return _DEFAULT_TERMINAL_WINDOWS; } abstract class TerminalLauncher implements ITerminalLauncher { public runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): TPromise { - return this.runInTerminal0(args.title, args.cwd, args.args, args.env, config); + return this.runInTerminal0(args.title, args.cwd, args.args, args.env || {}, config); } runInTerminal0(title: string, dir: string, args: string[], envVars: env.IProcessEnvironment, config): TPromise { return void 0; diff --git a/src/vs/workbench/parts/execution/electron-browser/terminal.ts b/src/vs/workbench/parts/execution/electron-browser/terminal.ts index c4230a35fdf3037ef8adbb56b83a341e02e5b24f..c6dab0141ca842e97cb53e2dbf89203769faecdd 100644 --- a/src/vs/workbench/parts/execution/electron-browser/terminal.ts +++ b/src/vs/workbench/parts/execution/electron-browser/terminal.ts @@ -43,7 +43,7 @@ let _DEFAULT_TERMINAL_WINDOWS: string = null; export function getDefaultTerminalWindows(): string { if (!_DEFAULT_TERMINAL_WINDOWS) { const isWoW64 = !!process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'); - _DEFAULT_TERMINAL_WINDOWS = `${process.env.windir ? process.env.windir : 'C:'}\\${isWoW64 ? 'Sysnative' : 'System32'}\\cmd.exe`; + _DEFAULT_TERMINAL_WINDOWS = `${process.env.windir ? process.env.windir : 'C:\\Windows'}\\${isWoW64 ? 'Sysnative' : 'System32'}\\cmd.exe`; } return _DEFAULT_TERMINAL_WINDOWS; }