diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index e9c387146e8..f807ca49def 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -68,11 +68,11 @@ import { statSync } from 'fs'; import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc'; import { IDiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService'; import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; +import { ElectronExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/electron-main/extensionHostDebugIpc'; import { IElectronMainService, ElectronMainService } from 'vs/platform/electron/electron-main/electronMainService'; import { ISharedProcessMainService, SharedProcessMainService } from 'vs/platform/ipc/electron-main/sharedProcessMainService'; import { IDialogMainService, DialogMainService } from 'vs/platform/dialogs/electron-main/dialogs'; import { withNullAsUndefined } from 'vs/base/common/types'; -import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { coalesce } from 'vs/base/common/arrays'; import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys'; import { StorageKeysSyncRegistryChannel } from 'vs/platform/userDataSync/common/userDataSyncIpc'; @@ -80,8 +80,6 @@ import { INativeEnvironmentService } from 'vs/platform/environment/node/environm import { mnemonicButtonLabel, getPathLabel } from 'vs/base/common/labels'; import { WebviewMainService } from 'vs/platform/webview/electron-main/webviewMainService'; import { IWebviewManagerService } from 'vs/platform/webview/common/webviewManagerService'; -import { createServer, AddressInfo } from 'net'; -import { IOpenExtensionWindowResult } from 'vs/platform/debug/common/extensionHostDebug'; import { IFileService } from 'vs/platform/files/common/files'; import { stripComments } from 'vs/base/common/json'; import { generateUuid } from 'vs/base/common/uuid'; @@ -867,100 +865,3 @@ export class CodeApplication extends Disposable { }); } } - -class ElectronExtensionHostDebugBroadcastChannel extends ExtensionHostDebugBroadcastChannel { - - constructor(private windowsMainService: IWindowsMainService) { - super(); - } - - call(ctx: TContext, command: string, arg?: any): Promise { - if (command === 'openExtensionDevelopmentHostWindow') { - return this.openExtensionDevelopmentHostWindow(arg[0], arg[1], arg[2]); - } else { - return super.call(ctx, command, arg); - } - } - - private async openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment, debugRenderer: boolean): Promise { - const pargs = parseArgs(args, OPTIONS); - const extDevPaths = pargs.extensionDevelopmentPath; - if (!extDevPaths) { - return {}; - } - - const [codeWindow] = this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, { - context: OpenContext.API, - cli: pargs, - userEnv: Object.keys(env).length > 0 ? env : undefined - }); - - if (!debugRenderer) { - return {}; - } - - const debug = codeWindow.win.webContents.debugger; - - let listeners = debug.isAttached() ? Infinity : 0; - const server = createServer(listener => { - if (listeners++ === 0) { - debug.attach(); - } - - let closed = false; - const writeMessage = (message: object) => { - if (!closed) { // in case sendCommand promises settle after closed - listener.write(JSON.stringify(message) + '\0'); // null-delimited, CDP-compatible - } - }; - - const onMessage = (_event: Event, method: string, params: unknown, sessionId?: string) => - writeMessage(({ method, params, sessionId })); - - codeWindow.win.on('close', () => { - debug.removeListener('message', onMessage); - listener.end(); - closed = true; - }); - - debug.addListener('message', onMessage); - - let buf = Buffer.alloc(0); - listener.on('data', data => { - buf = Buffer.concat([buf, data]); - for (let delimiter = buf.indexOf(0); delimiter !== -1; delimiter = buf.indexOf(0)) { - let data: { id: number; sessionId: string; params: {} }; - try { - const contents = buf.slice(0, delimiter).toString('utf8'); - buf = buf.slice(delimiter + 1); - data = JSON.parse(contents); - } catch (e) { - console.error('error reading cdp line', e); - } - - // depends on a new API for which electron.d.ts has not been updated: - // @ts-ignore - debug.sendCommand(data.method, data.params, data.sessionId) - .then((result: object) => writeMessage({ id: data.id, sessionId: data.sessionId, result })) - .catch((error: Error) => writeMessage({ id: data.id, sessionId: data.sessionId, error: { code: 0, message: error.message } })); - } - }); - - listener.on('error', err => { - console.error('error on cdp pipe:', err); - }); - - listener.on('close', () => { - closed = true; - if (--listeners === 0) { - debug.detach(); - } - }); - }); - - await new Promise(r => server.listen(0, r)); - codeWindow.win.on('close', () => server.close()); - - return { rendererDebugPort: (server.address() as AddressInfo).port }; - } -} diff --git a/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts b/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts new file mode 100644 index 00000000000..923305acd75 --- /dev/null +++ b/src/vs/platform/debug/electron-main/extensionHostDebugIpc.ts @@ -0,0 +1,109 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IOpenExtensionWindowResult } from 'vs/platform/debug/common/extensionHostDebug'; +import { IProcessEnvironment } from 'vs/base/common/platform'; +import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; +import { createServer, AddressInfo } from 'net'; +import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; +import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows'; +import { OpenContext } from 'vs/platform/windows/node/window'; + +export class ElectronExtensionHostDebugBroadcastChannel extends ExtensionHostDebugBroadcastChannel { + + constructor(private windowsMainService: IWindowsMainService) { + super(); + } + + call(ctx: TContext, command: string, arg?: any): Promise { + if (command === 'openExtensionDevelopmentHostWindow') { + return this.openExtensionDevelopmentHostWindow(arg[0], arg[1], arg[2]); + } else { + return super.call(ctx, command, arg); + } + } + + private async openExtensionDevelopmentHostWindow(args: string[], env: IProcessEnvironment, debugRenderer: boolean): Promise { + const pargs = parseArgs(args, OPTIONS); + const extDevPaths = pargs.extensionDevelopmentPath; + if (!extDevPaths) { + return {}; + } + + const [codeWindow] = this.windowsMainService.openExtensionDevelopmentHostWindow(extDevPaths, { + context: OpenContext.API, + cli: pargs, + userEnv: Object.keys(env).length > 0 ? env : undefined + }); + + if (!debugRenderer) { + return {}; + } + + const debug = codeWindow.win.webContents.debugger; + + let listeners = debug.isAttached() ? Infinity : 0; + const server = createServer(listener => { + if (listeners++ === 0) { + debug.attach(); + } + + let closed = false; + const writeMessage = (message: object) => { + if (!closed) { // in case sendCommand promises settle after closed + listener.write(JSON.stringify(message) + '\0'); // null-delimited, CDP-compatible + } + }; + + const onMessage = (_event: Event, method: string, params: unknown, sessionId?: string) => + writeMessage(({ method, params, sessionId })); + + codeWindow.win.on('close', () => { + debug.removeListener('message', onMessage); + listener.end(); + closed = true; + }); + + debug.addListener('message', onMessage); + + let buf = Buffer.alloc(0); + listener.on('data', data => { + buf = Buffer.concat([buf, data]); + for (let delimiter = buf.indexOf(0); delimiter !== -1; delimiter = buf.indexOf(0)) { + let data: { id: number; sessionId: string; params: {} }; + try { + const contents = buf.slice(0, delimiter).toString('utf8'); + buf = buf.slice(delimiter + 1); + data = JSON.parse(contents); + } catch (e) { + console.error('error reading cdp line', e); + } + + // depends on a new API for which electron.d.ts has not been updated: + // @ts-ignore + debug.sendCommand(data.method, data.params, data.sessionId) + .then((result: object) => writeMessage({ id: data.id, sessionId: data.sessionId, result })) + .catch((error: Error) => writeMessage({ id: data.id, sessionId: data.sessionId, error: { code: 0, message: error.message } })); + } + }); + + listener.on('error', err => { + console.error('error on cdp pipe:', err); + }); + + listener.on('close', () => { + closed = true; + if (--listeners === 0) { + debug.detach(); + } + }); + }); + + await new Promise(r => server.listen(0, r)); + codeWindow.win.on('close', () => server.close()); + + return { rendererDebugPort: (server.address() as AddressInfo).port }; + } +}