Skip to content

Commit 106985a

Browse files
committed
launch ext host window internally
1 parent 7b681f8 commit 106985a

11 files changed

Lines changed: 86 additions & 114 deletions

File tree

src/vs/platform/windows/common/windows.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ export interface IWindowsService {
153153
// Global methods
154154
openWindow(windowId: number, uris: IURIToOpen[], options: IOpenSettings): Promise<void>;
155155
openNewWindow(options?: INewWindowOptions): Promise<void>;
156+
openExtensionDevelopmentHostWindow(args: ParsedArgs): Promise<void>;
156157
getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>;
157158
getWindowCount(): Promise<number>;
158159
log(severity: string, ...messages: string[]): Promise<void>;

src/vs/platform/windows/electron-browser/windowsService.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ export class WindowsService implements IWindowsService {
195195
return this.channel.call('openNewWindow', options);
196196
}
197197

198+
openExtensionDevelopmentHostWindow(args: ParsedArgs): Promise<void> {
199+
return this.channel.call('openExtensionDevelopmentHostWindow', args);
200+
}
201+
198202
async getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {
199203
const result = await this.channel.call<{
200204
id: number;

src/vs/platform/windows/electron-main/windowsService.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,17 @@ export class WindowsService extends Disposable implements IWindowsService, IURLH
306306
this.windowsMainService.openNewWindow(OpenContext.API, options);
307307
}
308308

309+
async openExtensionDevelopmentHostWindow(args: ParsedArgs): Promise<void> {
310+
this.logService.trace('windowsService#openExtensionDevelopmentHostWindow ' + JSON.stringify(args));
311+
312+
if (args.extensionDevelopmentPath) {
313+
this.windowsMainService.openExtensionDevelopmentHostWindow(args.extensionDevelopmentPath, {
314+
context: OpenContext.API,
315+
cli: args
316+
});
317+
}
318+
}
319+
309320
async getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {
310321
this.logService.trace('windowsService#getWindows');
311322

src/vs/platform/windows/node/windowsIpc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export class WindowsChannel implements IServerChannel {
102102
return this.service.openWindow(arg[0], urisToOpen, options);
103103
}
104104
case 'openNewWindow': return this.service.openNewWindow(arg);
105+
case 'openExtensionDevelopmentHostWindow': return this.service.openExtensionDevelopmentHostWindow(arg);
105106
case 'getWindows': return this.service.getWindows();
106107
case 'getWindowCount': return this.service.getWindowCount();
107108
case 'relaunch': return this.service.relaunch(arg[0]);

src/vs/workbench/browser/web.simpleservices.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import { CommentingRanges } from 'vs/editor/common/modes';
4545
import { Range } from 'vs/editor/common/core/range';
4646
import { isUndefinedOrNull } from 'vs/base/common/types';
4747
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
48+
import { ParsedArgs } from 'vs/platform/environment/common/environment';
4849

4950
//#region Backup File
5051

@@ -1052,6 +1053,10 @@ export class SimpleWindowsService implements IWindowsService {
10521053
return Promise.resolve();
10531054
}
10541055

1056+
openExtensionDevelopmentHostWindow(args: ParsedArgs): Promise<void> {
1057+
return Promise.resolve();
1058+
}
1059+
10551060
getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> {
10561061
return Promise.resolve([]);
10571062
}

src/vs/workbench/contrib/debug/browser/debugHelperService.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { ServiceIdentifier, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
7-
import { ITerminalLauncher, IDebugHelperService, ILaunchVSCodeArguments } from 'vs/workbench/contrib/debug/common/debug';
7+
import { ITerminalLauncher, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug';
88
import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService';
99
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1010
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
@@ -17,10 +17,6 @@ export class BrowserDebugHelperService implements IDebugHelperService {
1717
throw new Error('Method createTerminalLauncher not implemented.');
1818
}
1919

20-
launchVsCode(vscodeArgs: ILaunchVSCodeArguments): Promise<number> {
21-
throw new Error('Method launchVsCode not implemented.');
22-
}
23-
2420
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined {
2521
return undefined;
2622
}

src/vs/workbench/contrib/debug/browser/debugSession.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { Event, Emitter } from 'vs/base/common/event';
1212
import { CompletionItem, completionKindFromString } from 'vs/editor/common/modes';
1313
import { Position } from 'vs/editor/common/core/position';
1414
import * as aria from 'vs/base/browser/ui/aria/aria';
15-
import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug';
15+
import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource } from 'vs/workbench/contrib/debug/common/debug';
1616
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
1717
import { mixin } from 'vs/base/common/objects';
1818
import { Thread, ExpressionContainer, DebugModel } from 'vs/workbench/contrib/debug/common/debugModel';
@@ -22,7 +22,7 @@ import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspac
2222
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
2323
import { RunOnceScheduler } from 'vs/base/common/async';
2424
import { generateUuid } from 'vs/base/common/uuid';
25-
import { IWindowService } from 'vs/platform/windows/common/windows';
25+
import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows';
2626
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
2727
import { normalizeDriveLetter } from 'vs/base/common/labels';
2828
import { Range } from 'vs/editor/common/core/range';
@@ -68,7 +68,7 @@ export class DebugSession implements IDebugSession {
6868
@INotificationService private readonly notificationService: INotificationService,
6969
@ISignService private readonly signService: ISignService,
7070
@IProductService private readonly productService: IProductService,
71-
@IDebugHelperService private readonly debugUIService: IDebugHelperService
71+
@IWindowsService private readonly windowsService: IWindowsService
7272
) {
7373
this.id = generateUuid();
7474
this.repl = new ReplModel(this);
@@ -169,7 +169,7 @@ export class DebugSession implements IDebugSession {
169169

170170
return dbgr.createDebugAdapter(this).then(debugAdapter => {
171171

172-
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.signService, this.debugUIService);
172+
this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.signService, this.windowsService);
173173

174174
return this.raw!.start().then(() => {
175175

src/vs/workbench/contrib/debug/browser/rawDebugSession.ts

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,28 @@ import * as objects from 'vs/base/common/objects';
99
import { Action } from 'vs/base/common/actions';
1010
import * as errors from 'vs/base/common/errors';
1111
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
12-
import { formatPII } from 'vs/workbench/contrib/debug/common/debugUtils';
13-
import { IDebugAdapter, IConfig, AdapterEndEvent, IDebugger, IDebugHelperService, ILaunchVSCodeArguments } from 'vs/workbench/contrib/debug/common/debug';
12+
import { formatPII, isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
13+
import { IDebugAdapter, IConfig, AdapterEndEvent, IDebugger } from 'vs/workbench/contrib/debug/common/debug';
1414
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
1515
import { ISignService } from 'vs/platform/sign/common/sign';
16+
import { ParsedArgs } from 'vs/platform/environment/common/environment';
17+
import { IWindowsService } from 'vs/platform/windows/common/windows';
18+
import { URI } from 'vs/base/common/uri';
19+
20+
/**
21+
* This interface represents a single command line argument split into a "prefix" and a "path" half.
22+
* The optional "prefix" contains arbitrary text and the optional "path" contains a file system path.
23+
* Concatenating both results in the original command line argument.
24+
*/
25+
interface ILaunchVSCodeArgument {
26+
prefix?: string;
27+
path?: string;
28+
}
29+
30+
interface ILaunchVSCodeArguments {
31+
args: ILaunchVSCodeArgument[];
32+
env?: { [key: string]: string | null; };
33+
}
1634

1735
/**
1836
* Encapsulates the DebugAdapter lifecycle and some idiosyncrasies of the Debug Adapter Protocol.
@@ -56,7 +74,8 @@ export class RawDebugSession {
5674
private readonly telemetryService: ITelemetryService,
5775
public readonly customTelemetryService: ITelemetryService | undefined,
5876
private readonly signService: ISignService,
59-
private readonly debugUIService: IDebugHelperService
77+
private readonly windowsService: IWindowsService
78+
6079
) {
6180
this.debugAdapter = debugAdapter;
6281
this._capabilities = Object.create(null);
@@ -503,9 +522,9 @@ export class RawDebugSession {
503522

504523
switch (request.command) {
505524
case 'launchVSCode':
506-
this.debugUIService.launchVsCode(<ILaunchVSCodeArguments>request.arguments).then(pid => {
525+
this.launchVsCode(<ILaunchVSCodeArguments>request.arguments).then(_ => {
507526
response.body = {
508-
processId: pid
527+
//processId: pid
509528
};
510529
safeSendResponse(response);
511530
}, err => {
@@ -549,6 +568,35 @@ export class RawDebugSession {
549568
}
550569
}
551570

571+
private launchVsCode(vscodeArgs: ILaunchVSCodeArguments): Promise<void> {
572+
573+
let args: ParsedArgs = {
574+
_: []
575+
};
576+
577+
for (let arg of vscodeArgs.args) {
578+
if (arg.prefix) {
579+
const a2 = (arg.prefix || '') + (arg.path || '');
580+
const match = /^--(.+)=(.+)$/.exec(a2);
581+
if (match && match.length === 3) {
582+
const key = match[1];
583+
let value = match[2];
584+
585+
if ((key === 'file-uri' || key === 'folder-uri') && !isUri(arg.path)) {
586+
value = URI.file(value).toString();
587+
}
588+
589+
args[key] = value;
590+
591+
} else {
592+
args._.push(a2);
593+
}
594+
}
595+
}
596+
597+
return this.windowsService.openExtensionDevelopmentHostWindow(args);
598+
}
599+
552600
private send<R extends DebugProtocol.Response>(command: string, args: any, timeout?: number): Promise<R> {
553601
return new Promise<R>((completeDispatch, errorDispatch) => {
554602
if (!this.debugAdapter) {

src/vs/workbench/contrib/debug/common/debug.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -843,27 +843,10 @@ export interface IDebugEditorContribution extends IEditorContribution {
843843
export const DEBUG_HELPER_SERVICE_ID = 'debugHelperService';
844844
export const IDebugHelperService = createDecorator<IDebugHelperService>(DEBUG_HELPER_SERVICE_ID);
845845

846-
/**
847-
* This interface represents a single command line argument split into a "prefix" and a "path" half.
848-
* The optional "prefix" contains arbitrary text and the optional "path" contains a file system path.
849-
* Concatenating both results in the original command line argument.
850-
*/
851-
export interface ILaunchVSCodeArgument {
852-
prefix?: string;
853-
path?: string;
854-
}
855-
856-
export interface ILaunchVSCodeArguments {
857-
args: ILaunchVSCodeArgument[];
858-
env?: { [key: string]: string | null; };
859-
}
860-
861846
export interface IDebugHelperService {
862847
_serviceBrand: any;
863848

864849
createTerminalLauncher(instantiationService: IInstantiationService): ITerminalLauncher;
865850

866-
launchVsCode(vscodeArgs: ILaunchVSCodeArguments): Promise<number>;
867-
868851
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined;
869852
}

src/vs/workbench/contrib/debug/node/debugHelperService.ts

Lines changed: 1 addition & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6-
import * as objects from 'vs/base/common/objects';
7-
import { isUri } from 'vs/workbench/contrib/debug/common/debugUtils';
8-
import * as cp from 'child_process';
9-
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
106
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
117
import { TerminalLauncher } from 'vs/workbench/contrib/debug/node/terminalSupport';
12-
import { ITerminalLauncher, IDebugHelperService, ILaunchVSCodeArguments } from 'vs/workbench/contrib/debug/common/debug';
8+
import { ITerminalLauncher, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug';
139
import { Client as TelemetryClient } from 'vs/base/parts/ipc/node/ipc.cp';
1410
import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc';
1511
import { getPathFromAmdModule } from 'vs/base/common/amd';
@@ -21,90 +17,13 @@ export class NodeDebugHelperService implements IDebugHelperService {
2117
_serviceBrand: any;
2218

2319
constructor(
24-
@IEnvironmentService private readonly environmentService: IEnvironmentService
2520
) {
2621
}
2722

2823
createTerminalLauncher(instantiationService: IInstantiationService): ITerminalLauncher {
2924
return instantiationService.createInstance(TerminalLauncher);
3025
}
3126

32-
launchVsCode(vscodeArgs: ILaunchVSCodeArguments): Promise<number> {
33-
34-
const spawnOpts: cp.SpawnOptions = {
35-
detached: false // https://github.com/Microsoft/vscode/issues/57018
36-
};
37-
38-
if (vscodeArgs.env) {
39-
// merge environment variables into a copy of the process.env
40-
const envArgs = objects.mixin(objects.mixin({}, process.env), vscodeArgs.env);
41-
// and delete some if necessary
42-
Object.keys(envArgs).filter(k => envArgs[k] === null).forEach(key => delete envArgs[key]);
43-
spawnOpts.env = envArgs;
44-
}
45-
46-
let spawnArgs = vscodeArgs.args.map(a => {
47-
if ((a.prefix === '--file-uri=' || a.prefix === '--folder-uri=') && !isUri(a.path)) {
48-
return (a.path || '');
49-
}
50-
return (a.prefix || '') + (a.path || '');
51-
});
52-
53-
let runtimeExecutable = this.environmentService['execPath'];
54-
if (!runtimeExecutable) {
55-
return Promise.reject(new Error(`VS Code executable unknown`));
56-
}
57-
58-
// if VS Code runs out of sources, add the VS Code workspace path as the first argument so that Electron turns into VS Code
59-
const electronIdx = runtimeExecutable.indexOf(process.platform === 'win32' ? '\\.build\\electron\\' : '/.build/electron/');
60-
if (electronIdx > 0) {
61-
// guess the VS Code workspace path from the executable
62-
const vscodeWorkspacePath = runtimeExecutable.substr(0, electronIdx);
63-
64-
// only add VS Code workspace path if user hasn't already added that path as a (folder) argument
65-
const x = spawnArgs.filter(a => a.indexOf(vscodeWorkspacePath) === 0);
66-
if (x.length === 0) {
67-
spawnArgs.unshift(vscodeWorkspacePath);
68-
}
69-
}
70-
71-
// Workaround for bug Microsoft/vscode#45832
72-
if (process.platform === 'win32' && runtimeExecutable.indexOf(' ') > 0) {
73-
let foundArgWithSpace = false;
74-
75-
// check whether there is one arg with a space
76-
const args: string[] = [];
77-
for (const a of spawnArgs) {
78-
if (a.indexOf(' ') > 0) {
79-
args.push(`"${a}"`);
80-
foundArgWithSpace = true;
81-
} else {
82-
args.push(a);
83-
}
84-
}
85-
86-
if (foundArgWithSpace) {
87-
spawnArgs = args;
88-
runtimeExecutable = `"${runtimeExecutable}"`;
89-
spawnOpts.shell = true;
90-
}
91-
}
92-
93-
return new Promise((resolve, reject) => {
94-
const process = cp.spawn(runtimeExecutable, spawnArgs, spawnOpts);
95-
process.on('error', error => {
96-
reject(error);
97-
});
98-
process.on('exit', code => {
99-
if (code === 0) {
100-
resolve(process.pid);
101-
} else {
102-
reject(new Error(`VS Code exited with ${code}`));
103-
}
104-
});
105-
});
106-
}
107-
10827
createTelemetryService(configurationService: IConfigurationService, args: string[]): TelemetryService | undefined {
10928

11029
const client = new TelemetryClient(

0 commit comments

Comments
 (0)