diff --git a/src/vs/code/electron-browser/sharedProcess.html b/src/vs/code/electron-browser/sharedProcess.html
new file mode 100644
index 00000000000..869131118cd
--- /dev/null
+++ b/src/vs/code/electron-browser/sharedProcess.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+ Shared Process
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/vs/code/electron-browser/sharedProcess.js b/src/vs/code/electron-browser/sharedProcess.js
new file mode 100644
index 00000000000..b28716a7cea
--- /dev/null
+++ b/src/vs/code/electron-browser/sharedProcess.js
@@ -0,0 +1,107 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+// Warning: Do not use the `let` declarator in this file, it breaks our minification
+
+'use strict';
+
+/*global window,document,define*/
+
+const path = require('path');
+const electron = require('electron');
+const remote = electron.remote;
+const ipc = electron.ipcRenderer;
+
+function assign(destination, source) {
+ return Object.keys(source)
+ .reduce(function (r, key) { r[key] = source[key]; return r; }, destination);
+}
+
+function parseURLQueryArgs() {
+ const search = window.location.search || '';
+
+ return search.split(/[?&]/)
+ .filter(function (param) { return !!param; })
+ .map(function (param) { return param.split('='); })
+ .filter(function (param) { return param.length === 2; })
+ .reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {});
+}
+
+function createScript(src, onload) {
+ const script = document.createElement('script');
+ script.src = src;
+ script.addEventListener('load', onload);
+
+ const head = document.getElementsByTagName('head')[0];
+ head.insertBefore(script, head.lastChild);
+}
+
+function uriFromPath(_path) {
+ var pathName = path.resolve(_path).replace(/\\/g, '/');
+ if (pathName.length > 0 && pathName.charAt(0) !== '/') {
+ pathName = '/' + pathName;
+ }
+
+ return encodeURI('file://' + pathName);
+}
+
+function main() {
+ const args = parseURLQueryArgs();
+ const configuration = JSON.parse(args['config'] || '{}') || {};
+
+ // Correctly inherit the parent's environment
+ assign(process.env, configuration.userEnv);
+
+ // Get the nls configuration into the process.env as early as possible.
+ var nlsConfig = { availableLanguages: {} };
+ const config = process.env['VSCODE_NLS_CONFIG'];
+ if (config) {
+ process.env['VSCODE_NLS_CONFIG'] = config;
+ try {
+ nlsConfig = JSON.parse(config);
+ } catch (e) { /*noop*/ }
+ }
+
+ var locale = nlsConfig.availableLanguages['*'] || 'en';
+ if (locale === 'zh-tw') {
+ locale = 'zh-Hant';
+ } else if (locale === 'zh-cn') {
+ locale = 'zh-Hans';
+ }
+
+ window.document.documentElement.setAttribute('lang', locale);
+
+ // Load the loader and start loading the workbench
+ const rootUrl = uriFromPath(configuration.appRoot) + '/out';
+
+ // In the bundled version the nls plugin is packaged with the loader so the NLS Plugins
+ // loads as soon as the loader loads. To be able to have pseudo translation
+ createScript(rootUrl + '/vs/loader.js', function () {
+ define('fs', ['original-fs'], function (originalFS) { return originalFS; }); // replace the patched electron fs with the original node fs for all AMD code
+
+ window.MonacoEnvironment = {};
+
+ const nodeCachedDataErrors = window.MonacoEnvironment.nodeCachedDataErrors = [];
+ require.config({
+ baseUrl: rootUrl,
+ 'vs/nls': nlsConfig,
+ nodeCachedDataDir: configuration.nodeCachedDataDir,
+ onNodeCachedDataError: function (err) { nodeCachedDataErrors.push(err) },
+ nodeModules: [/*BUILD->INSERT_NODE_MODULES*/]
+ });
+
+ if (nlsConfig.pseudo) {
+ require(['vs/nls'], function (nlsPlugin) {
+ nlsPlugin.setPseudoTranslation(nlsConfig.pseudo);
+ });
+ }
+
+ require(['vs/code/electron-browser/sharedProcessMain'], function () {
+
+ });
+ });
+}
+
+main();
diff --git a/src/vs/code/node/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcessMain.ts
similarity index 91%
rename from src/vs/code/node/sharedProcessMain.ts
rename to src/vs/code/electron-browser/sharedProcessMain.ts
index d6ca3fa783c..5bef18daefb 100644
--- a/src/vs/code/node/sharedProcessMain.ts
+++ b/src/vs/code/electron-browser/sharedProcessMain.ts
@@ -28,32 +28,16 @@ import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProper
import { TelemetryAppenderChannel } from 'vs/platform/telemetry/common/telemetryIpc';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender';
-import { ISharedProcessInitData } from './sharedProcess';
+// import { ISharedProcessInitData } from './sharedProcess';
import { IChoiceService } from 'vs/platform/message/common/message';
import { ChoiceChannelClient } from 'vs/platform/message/common/messageIpc';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc';
import { ActiveWindowManager } from 'vs/code/common/windows';
+import { ipcRenderer } from 'electron';
-function quit(err?: Error) {
- if (err) {
- console.error(err.stack || err);
- }
-
- process.exit(err ? 1 : 0);
-}
-
-/**
- * Plan B is to kill oneself if one's parent dies. Much drama.
- */
-function setupPlanB(parentPid: number): void {
- setInterval(function () {
- try {
- process.kill(parentPid, 0); // throws an exception if the main process doesn't exist anymore.
- } catch (e) {
- process.exit();
- }
- }, 5000);
+interface ISharedProcessInitData {
+ args: any;
}
const eventPrefix = 'monacoworkbench';
@@ -161,14 +145,13 @@ function setupIPC(hook: string): TPromise {
function handshake(): TPromise {
return new TPromise((c, e) => {
- process.once('message', c);
- process.once('error', e);
- process.send('hello');
+ ipcRenderer.once('handshake', (_, r) => c(r));
+ ipcRenderer.send('handshake');
});
}
setupIPC(process.env['VSCODE_SHARED_IPC_HOOK'])
.then(server => handshake()
- .then(data => main(server, data))
- .then(() => setupPlanB(process.env['VSCODE_PID']))
- .done(null, quit));
\ No newline at end of file
+ .then(data => main(server, data)));
+ // .then(() => setupPlanB(process.env['VSCODE_PID']))
+ // .done(null, quit));
diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts
index ba8f2436591..9912806456f 100644
--- a/src/vs/code/electron-main/main.ts
+++ b/src/vs/code/electron-main/main.ts
@@ -27,9 +27,8 @@ import { Server, serve, connect } from 'vs/base/parts/ipc/node/ipc.net';
import { TPromise } from 'vs/base/common/winjs.base';
import { AskpassChannel } from 'vs/workbench/parts/git/common/gitIpc';
import { GitAskpassService } from 'vs/workbench/parts/git/electron-main/askpassService';
-import { spawnSharedProcess } from 'vs/code/node/sharedProcess';
+import { spawnSharedProcess } from 'vs/code/electron-main/sharedProcess';
import { Mutex } from 'windows-mutex';
-import { IDisposable } from 'vs/base/common/lifecycle';
import { LaunchService, ILaunchChannel, LaunchChannel, LaunchChannelClient, ILaunchService } from './launch';
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
@@ -144,17 +143,9 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
// Spawn shared process
const initData = { args: environmentService.args };
- const options = {
- allowOutput: !environmentService.isBuilt || environmentService.verbose,
- debugPort: environmentService.isBuilt ? null : 5871
- };
- let sharedProcessDisposable: IDisposable;
-
- const sharedProcess = spawnSharedProcess(initData, options).then(disposable => {
- sharedProcessDisposable = disposable;
- return connect(environmentService.sharedIPCHandle, 'main');
- });
+ const sharedProcess = spawnSharedProcess(initData)
+ .then(disposable => connect(environmentService.sharedIPCHandle, 'main'));
// Create a new service collection, because the telemetry service
// requires a connection to shared process, which was only established
@@ -220,10 +211,6 @@ function main(accessor: ServicesAccessor, mainIpcServer: Server, userEnv: platfo
mainIpcServer = null;
}
- if (sharedProcessDisposable) {
- sharedProcessDisposable.dispose();
- }
-
if (windowsMutex) {
windowsMutex.release();
}
diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts
new file mode 100644
index 00000000000..66c7a783cf2
--- /dev/null
+++ b/src/vs/code/electron-main/sharedProcess.ts
@@ -0,0 +1,42 @@
+/*---------------------------------------------------------------------------------------------
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for license information.
+ *--------------------------------------------------------------------------------------------*/
+
+import { assign } from 'vs/base/common/objects';
+import { ParsedArgs } from 'vs/platform/environment/common/environment';
+import { TPromise } from 'vs/base/common/winjs.base';
+import { BrowserWindow, ipcMain } from 'electron';
+
+export interface ISharedProcessInitData {
+ args: ParsedArgs;
+}
+
+export function spawnSharedProcess(initData: ISharedProcessInitData): TPromise {
+ const window = new BrowserWindow();
+ const config = assign({
+ userEnv: {},
+ appRoot: '',
+ nodeCachedDataDir: ''
+ });
+
+ const url = `${require.toUrl('vs/code/electron-browser/sharedProcess.html')}?config=${encodeURIComponent(JSON.stringify(config))}`;
+ window.loadURL(url);
+ // window.hide();
+ window.webContents.openDevTools();
+
+ // Prevent the window from dying
+ window.on('close', e => {
+ if (window.isVisible()) {
+ e.preventDefault();
+ window.hide();
+ }
+ });
+
+ return new TPromise((c, e) => {
+ ipcMain.once('handshake', ({ sender }) => {
+ sender.send('handshake', initData);
+ c(null);
+ });
+ });
+}
\ No newline at end of file
diff --git a/src/vs/code/node/sharedProcess.ts b/src/vs/code/node/sharedProcess.ts
deleted file mode 100644
index 46f0f1ea9b5..00000000000
--- a/src/vs/code/node/sharedProcess.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-/*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
-
-import * as cp from 'child_process';
-import URI from 'vs/base/common/uri';
-import { IDisposable } from 'vs/base/common/lifecycle';
-import { assign } from 'vs/base/common/objects';
-import { ParsedArgs } from 'vs/platform/environment/common/environment';
-import { TPromise } from 'vs/base/common/winjs.base';
-
-export interface ISharedProcessInitData {
- args: ParsedArgs;
-}
-
-export interface ISharedProcessOptions {
- allowOutput?: boolean;
- debugPort?: number;
-}
-
-const boostrapPath = URI.parse(require.toUrl('bootstrap')).fsPath;
-
-function _spawnSharedProcess(initData: ISharedProcessInitData, options: ISharedProcessOptions): cp.ChildProcess {
- const execArgv: string[] = [];
- const env = assign({}, process.env, {
- AMD_ENTRYPOINT: 'vs/code/node/sharedProcessMain',
- ELECTRON_NO_ASAR: '1'
- });
-
- if (options.allowOutput) {
- env['VSCODE_ALLOW_IO'] = 'true';
- }
-
- if (options.debugPort) {
- execArgv.push(`--debug=${options.debugPort}`);
- }
-
- const result = cp.fork(boostrapPath, ['--type=SharedProcess'], { env, execArgv });
-
- return result;
-}
-
-export function spawnSharedProcess(initData: ISharedProcessInitData, options: ISharedProcessOptions = {}): TPromise {
- let spawnCount = 0;
- let child: cp.ChildProcess;
-
- let promise: TPromise;
-
- const spawn = () => {
- if (++spawnCount > 10) {
- return;
- }
-
- child = _spawnSharedProcess(initData, options);
- promise = new TPromise((c, e) => {
- // handshake
- child.once('message', () => {
- child.send(initData);
- c({
- dispose: () => {
- if (child) {
- child.removeListener('exit', spawn);
- child.kill();
- child = null;
- }
- }
- });
- });
- });
- child.on('exit', spawn);
- };
-
- spawn();
-
- return promise;
-}
\ No newline at end of file