diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index 8465b2b8a15..9d7f57a3d85 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -406,10 +406,10 @@ "./vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts", "./vs/workbench/services/extensions/electron-browser/extensionHost.ts", "./vs/workbench/services/extensions/electron-browser/extensionHostProfiler.ts", + "./vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts", "./vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler.ts", "./vs/workbench/services/extensions/node/extensionDescriptionRegistry.ts", "./vs/workbench/services/extensions/node/extensionHostProtocol.ts", - "./vs/workbench/services/extensions/node/extensionManagementServerService.ts", "./vs/workbench/services/extensions/node/extensionPoints.ts", "./vs/workbench/services/extensions/node/lazyPromise.ts", "./vs/workbench/services/extensions/node/proxyIdentifier.ts", diff --git a/src/vs/base/common/hash.ts b/src/vs/base/common/hash.ts index 6c0025b1d74..a4bad6fe5a2 100644 --- a/src/vs/base/common/hash.ts +++ b/src/vs/base/common/hash.ts @@ -3,6 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { isString } from 'vs/base/common/types'; + /** * Return a hash value for an object. */ @@ -69,4 +71,345 @@ export class Hasher { this._value = hash(obj, this._value); return this._value; } -} \ No newline at end of file +} + +//#region SHA1 + +export function computeSHA1Hash(value: string): string { + const data = encodeToArrayBuffer(value); + const hash = new SHA1(); + + if (data.byteLength) { + hash.update(data); + } + + return hash.digest(); +} + +class SHA1 { + + // Reference: http://en.wikipedia.org/wiki/SHA-1 + + private static BLOCK_SIZE = 64; // 512 / 8 + + private length: number; + private buffer: Uint8Array | null; + private bufferDV: DataView | null; + private bufferLength: number; + + private bigBlock32: DataView; + private h0 = 0x67452301; + private h1 = 0xEFCDAB89; + private h2 = 0x98BADCFE; + private h3 = 0x10325476; + private h4 = 0xC3D2E1F0; + + static digest(data: string): string; + static digest(data: Uint8Array): string; + static digest(data: ArrayBuffer): string; + static digest(data: DataView): string; + static digest(data: any): string { + let sha = new SHA1(); + sha.update(data); + + return sha.digest(); + } + + constructor() { + this.length = 0; + + this.buffer = new Uint8Array(SHA1.BLOCK_SIZE); + this.bufferDV = new DataView(this.buffer.buffer); + this.bufferLength = 0; + + this.bigBlock32 = new DataView(new ArrayBuffer(320)); // 80 * 4 = 320; + } + + update(data: string): void; + update(data: Uint8Array): void; + update(data: ArrayBuffer): void; + update(data: DataView): void; + update(arg: any): void { + if (!this.buffer || !this.bufferDV) { + throw new Error('Digest already computed.'); + } + + let data: Uint8Array; + + if (isString(arg)) { + data = new Uint8Array(encodeToArrayBuffer(arg)); + } else if (arg instanceof ArrayBuffer) { + data = new Uint8Array(arg); + } else if (arg instanceof DataView) { + data = new Uint8Array((arg).buffer); + } else { + data = arg; + } + + let bytesRead = 0, totalBytesRead = 0; + + while (totalBytesRead < data.byteLength) { + bytesRead = copy(this.buffer, this.bufferLength, data, totalBytesRead, data.byteLength); + + this.bufferLength += bytesRead; + totalBytesRead += bytesRead; + + if (this.bufferLength === SHA1.BLOCK_SIZE) { + this.step(this.bufferDV); + this.bufferLength = 0; + } + } + + this.length += totalBytesRead; + } + + digest(): string { + if (this.buffer) { + this.wrapUp(); + } + + return toHexString(this.h0) + toHexString(this.h1) + toHexString(this.h2) + toHexString(this.h3) + toHexString(this.h4); + } + + private wrapUp(): void { + if (!this.buffer || !this.bufferDV) { + return; // already wrapped up + } + + this.buffer[this.bufferLength++] = 0x80; + fill(this.buffer, this.bufferLength); + + if (this.bufferLength > 56) { + this.step(this.bufferDV); + fill(this.buffer); + } + + let ml = multiply64(8, this.length); + this.bufferDV.setUint32(56, ml[0], false); + this.bufferDV.setUint32(60, ml[1], false); + + this.step(this.bufferDV); + + this.buffer = null; + this.bufferDV = null; + this.bufferLength = -1; + } + + private step(data: DataView): void { + for (let j = 0; j < 64 /* 16*4 */; j += 4) { + this.bigBlock32.setUint32(j, data.getUint32(j, false), false); + } + + for (let j = 64; j < 320 /* 80*4 */; j += 4) { + this.bigBlock32.setUint32(j, leftRotate((this.bigBlock32.getUint32(j - 12, false) ^ this.bigBlock32.getUint32(j - 32, false) ^ this.bigBlock32.getUint32(j - 56, false) ^ this.bigBlock32.getUint32(j - 64, false)), 1), false); + } + + let a = this.h0; + let b = this.h1; + let c = this.h2; + let d = this.h3; + let e = this.h4; + + let f: number, k: number; + let temp: number; + + for (let j = 0; j < 80; j++) { + if (j < 20) { + f = (b & c) | ((~b) & d); + k = 0x5A827999; + } else if (j < 40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (j < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + + temp = (leftRotate(a, 5) + f + e + k + this.bigBlock32.getUint32(j * 4, false)) & 0xFFFFFFFF; + e = d; + d = c; + c = leftRotate(b, 30); + b = a; + a = temp; + } + + this.h0 = (this.h0 + a) & 0xFFFFFFFF; + this.h1 = (this.h1 + b) & 0xFFFFFFFF; + this.h2 = (this.h2 + c) & 0xFFFFFFFF; + this.h3 = (this.h3 + d) & 0xFFFFFFFF; + this.h4 = (this.h4 + e) & 0xFFFFFFFF; + } +} + +function leftPad(value: string, length: number, char: string = '0'): string { + return new Array(length - value.length + 1).join(char) + value; +} + +function toHexString(value: number, bitsize: number = 32): string { + return leftPad((value >>> 0).toString(16), bitsize / 4); +} + +function leftRotate(value: number, bits: number, totalBits: number = 32): number { + + // delta + bits = totalBits + let delta = totalBits - bits; + + // All ones, expect `delta` zeros aligned to the right + let mask = ~((1 << delta) - 1); + + // Join (value left-shifted `bits` bits) with (masked value right-shifted `delta` bits) + return ((value << bits) | ((mask & value) >>> delta)) >>> 0; +} + +function multiply64(a: number, b: number): number[] { + /* A1 A0 => A + * B1 B0 => B + * B0 * A1 B0 * A0 + * B1 * A1 B1 * A0 + * C3 C2 C1 C0 => C + */ + + let a0 = a & 0xFFFF, a1 = a >>> 16; + let b0 = b & 0xFFFF, b1 = b >>> 16; + let c0 = 0, c1 = 0, c2 = 0, c3 = 0; + + let x = b0 * a0; + c0 += x & 0xFFFF; + c1 += x >>> 16; + + x = b0 * a1; + c1 += x & 0xFFFF; + c2 += x >>> 16; + + x = b1 * a0; + c1 += x & 0xFFFF; + c2 += x >>> 16; + + c2 += c1 >>> 16; + c1 = c1 & 0xFFFF; + + x = b1 * a1; + c2 += x & 0xFFFF; + c3 += x >>> 16; + + c3 += c2 >>> 16; + c2 = c2 & 0xFFFF; + + return [(c3 << 16 | c2) >>> 0, (c1 << 16 | c0) >>> 0]; +} + +function encodeToArrayBuffer(str: string): ArrayBuffer { + let i: number, len: number, length = 0, charCode = 0, trailCharCode = 0, codepoint = 0; + + // First pass, for the size + for (i = 0, len = str.length; i < len; i++) { + charCode = str.charCodeAt(i); + + // Surrogate pair + if (charCode >= 0xD800 && charCode < 0xDC00) { + trailCharCode = str.charCodeAt(++i); + + if (!(trailCharCode >= 0xDC00 && trailCharCode < 0xE000)) { + throw new Error('Invalid char code'); + } + + // Code point can be obtained by subtracting 0xD800 and 0xDC00 from both char codes respectively + // and joining the 10 least significant bits from each, finally adding 0x10000. + codepoint = ((((charCode - 0xD800) & 0x3FF) << 10) | ((trailCharCode - 0xDC00) & 0x3FF)) + 0x10000; + + } else { + codepoint = charCode; + } + + length += byteSizeInUTF8(codepoint); + } + + let result = new ArrayBuffer(length); + let view = new Uint8Array(result); + let pos = 0; + + // Second pass, for the data + for (i = 0, len = str.length; i < len; i++) { + charCode = str.charCodeAt(i); + + if (charCode >= 0xD800 && charCode < 0xDC00) { + trailCharCode = str.charCodeAt(++i); + codepoint = ((((charCode - 0xD800) & 0x3FF) << 10) | ((trailCharCode - 0xDC00) & 0x3FF)) + 0x10000; + } else { + codepoint = charCode; + } + + pos += writeUTF8(codepoint, view, pos); + } + + return result; +} + +function byteSizeInUTF8(codePoint: number): number { + codePoint = codePoint >>> 0; + + if (codePoint < 0x80) { + return 1; + } else if (codePoint < 0x800) { + return 2; + } else if (codePoint < 0x10000) { + return 3; + } else if (codePoint < 0x200000) { + return 4; + } else if (codePoint < 0x4000000) { + return 5; + } else if (codePoint < 0x80000000) { + return 6; + } else { + throw new Error('Code point 0x' + toHexString(codePoint) + ' not encodable in UTF8.'); + } +} + +function writeUTF8(codePoint: number, buffer: Uint8Array, pos: number): number { + + // How many bits needed for codePoint + let byteSize = byteSizeInUTF8(codePoint); + + // 0xxxxxxx + if (byteSize === 1) { + buffer[pos] = codePoint; + return 1; + } + + // 110xxxxx 10xxxxxx + // 1110xxxx 10xxxxxx 10xxxxxx + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + + // first byte + buffer[pos] = ((0xFC << (6 - byteSize)) | (codePoint >>> (6 * (byteSize - 1)))) & 0xFF; + + // successive bytes + for (let i = 1; i < byteSize; i++) { + buffer[pos + i] = (0x80 | (0x3F & (codePoint >>> (6 * (byteSize - i - 1))))) & 0xFF; + } + + return byteSize; +} + +function copy(dest: Uint8Array, destIndex: number, src: Uint8Array, srcIndex: number, count: number): number { + const len = Math.min(dest.byteLength - destIndex, src.byteLength - srcIndex, count); + + for (let i = 0; i < len; i++) { + dest[destIndex + i] = src[srcIndex + i]; + } + + return len; +} + +function fill(dest: Uint8Array, index: number = 0, count: number = dest.byteLength, value: number = 0): void { + for (let i = 0; i < count; i++) { + dest[index + i] = value; + } +} + +//#endregion \ No newline at end of file diff --git a/src/vs/base/test/common/hash.test.ts b/src/vs/base/test/common/hash.test.ts index d197cdf4f1f..b9b65f7b68c 100644 --- a/src/vs/base/test/common/hash.test.ts +++ b/src/vs/base/test/common/hash.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { hash } from 'vs/base/common/hash'; +import { hash, computeSHA1Hash } from 'vs/base/common/hash'; suite('Hash', () => { test('string', () => { @@ -43,4 +43,12 @@ suite('Hash', () => { assert.notEqual(hash({ 'foo': 'bar' }), hash({ 'foo': 'bar2' })); assert.notEqual(hash({}), hash([])); }); + + test('computeSHA1Hash', () => { + assert.equal(computeSHA1Hash(''), 'da39a3ee5e6b4b0d3255bfef95601890afd80709'); + assert.equal(computeSHA1Hash('hello world'), '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'); + assert.equal(computeSHA1Hash('da39a3ee5e6b4b0d3255bfef95601890afd80709'), '10a34637ad661d98ba3344717656fcc76209c2f8'); + assert.equal(computeSHA1Hash('2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'), 'd6b0d82cea4269b51572b8fab43adcee9fc3cf9a'); + assert.equal(computeSHA1Hash('öäü_?ß()<>ÖÄÜ'), 'b64beaeff9e317b0193c8e40a2431b210388eba9'); + }); }); \ No newline at end of file diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index c4d6e66aaa8..e655f7cffe9 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -16,7 +16,6 @@ import * as os from 'os'; import { debounce } from 'vs/base/common/decorators'; import * as platform from 'vs/base/common/platform'; import { Disposable } from 'vs/base/common/lifecycle'; -import { Client as ElectronIPCClient } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser'; import { getDelayedChannel } from 'vs/base/parts/ipc/node/ipc'; import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; @@ -28,7 +27,8 @@ import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; -import { WindowsChannelClient } from 'vs/platform/windows/node/windowsIpc'; +import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; +import { MainProcessService, IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { IssueReporterModel } from 'vs/code/electron-browser/issue/issueReporterModel'; import { IssueReporterData, IssueReporterStyles, IssueType, ISettingsSearchIssueReporterData, IssueReporterFeatures, IssueReporterExtensionData } from 'vs/platform/issue/common/issue'; @@ -273,14 +273,14 @@ export class IssueReporter extends Disposable { private initServices(configuration: IWindowConfiguration): void { const serviceCollection = new ServiceCollection(); - const mainProcessClient = new ElectronIPCClient(String(`window${configuration.windowId}`)); + const mainProcessService = new MainProcessService(configuration.windowId); + serviceCollection.set(IMainProcessService, mainProcessService); - const windowsChannel = mainProcessClient.getChannel('windows'); - serviceCollection.set(IWindowsService, new WindowsChannelClient(windowsChannel)); + serviceCollection.set(IWindowsService, new WindowsService(mainProcessService)); this.environmentService = new EnvironmentService(configuration, configuration.execPath); const logService = createSpdLogService(`issuereporter${configuration.windowId}`, getLogLevel(this.environmentService), this.environmentService.logsPath); - const logLevelClient = new LogLevelSetterChannelClient(mainProcessClient.getChannel('loglevel')); + const logLevelClient = new LogLevelSetterChannelClient(mainProcessService.getChannel('loglevel')); this.logService = new FollowerLogService(logLevelClient, logService); const sharedProcess = (serviceCollection.get(IWindowsService)).whenSharedProcessReady() diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 2cd26d6cf6a..ae90617ca38 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -28,7 +28,7 @@ import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIp import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppender'; import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows'; -import { WindowsChannelClient } from 'vs/platform/windows/node/windowsIpc'; +import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; import { ipcRenderer } from 'electron'; import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; @@ -41,11 +41,13 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IDisposable, dispose, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { DownloadService } from 'vs/platform/download/node/downloadService'; import { IDownloadService } from 'vs/platform/download/common/download'; -import { StaticRouter } from 'vs/base/parts/ipc/node/ipc'; +import { StaticRouter, IServerChannel, IChannel } from 'vs/base/parts/ipc/node/ipc'; import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner'; import { LanguagePackCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner'; import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/storageDataCleaner'; import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export interface ISharedProcessConfiguration { readonly machineId: string; @@ -63,6 +65,20 @@ interface ISharedProcessInitData { const eventPrefix = 'monacoworkbench'; +class MainProcessService implements IMainProcessService { + constructor(private server: Server, private mainRouter: StaticRouter) { } + + _serviceBrand: ServiceIdentifier; + + getChannel(channelName: string): IChannel { + return this.server.getChannel(channelName, this.mainRouter); + } + + registerChannel(channelName: string, channel: IServerChannel): void { + this.server.registerChannel(channelName, channel); + } +} + function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): void { const services = new ServiceCollection(); @@ -89,8 +105,10 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I services.set(IRequestService, new SyncDescriptor(RequestService)); services.set(IDownloadService, new SyncDescriptor(DownloadService)); - const windowsChannel = server.getChannel('windows', mainRouter); - const windowsService = new WindowsChannelClient(windowsChannel); + const mainProcessService = new MainProcessService(server, mainRouter); + services.set(IMainProcessService, mainProcessService); + + const windowsService = new WindowsService(mainProcessService); services.set(IWindowsService, windowsService); const activeWindowManager = new ActiveWindowManager(windowsService); diff --git a/src/vs/code/electron-browser/workbench/workbench.nodeless.html b/src/vs/code/electron-browser/workbench/workbench.nodeless.html new file mode 100644 index 00000000000..e37abfdf5ae --- /dev/null +++ b/src/vs/code/electron-browser/workbench/workbench.nodeless.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/vs/code/electron-browser/workbench/workbench.nodeless.js b/src/vs/code/electron-browser/workbench/workbench.nodeless.js new file mode 100644 index 00000000000..9f52c0ab096 --- /dev/null +++ b/src/vs/code/electron-browser/workbench/workbench.nodeless.js @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check +'use strict'; + +(function () { + + function loadScript(path, callback) { + let script = document.createElement('script'); + script.onload = callback; + script.async = true; + script.type = 'text/javascript'; + script.src = path; + document.head.appendChild(script); + } + + loadScript('../../../../../src/vs/loader.js', function () { + + // @ts-ignore + require.config({ + baseUrl: 'file:../../../../../out' + }); + + // @ts-ignore + require([ + 'vs/workbench/workbench.nodeless.main', + 'vs/nls!vs/workbench/workbench.nodeless.main', + 'vs/css!vs/workbench/workbench.nodeless.main' + ], function () { + + // @ts-ignore + require('vs/workbench/browser/nodeless.main').main().then(undefined, console.error); + }); + }); +})(); \ No newline at end of file diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 234ed41eeb1..a59450a3083 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -78,6 +78,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { private readonly touchBarGroups: Electron.TouchBarSegmentedControl[]; + private nodeless: boolean; + constructor( config: IWindowCreationOptions, @ILogService private readonly logService: ILogService, @@ -94,6 +96,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._readyState = ReadyState.NONE; this.whenReadyCallbacks = []; + this.nodeless = !!(environmentService.args.nodeless && !environmentService.isBuilt); + // create browser window this.createBrowserWindow(config); @@ -123,7 +127,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { height: this.windowState.height, x: this.windowState.x, y: this.windowState.y, - backgroundColor: getBackgroundColor(this.stateService), + backgroundColor: this.nodeless ? undefined : getBackgroundColor(this.stateService), minWidth: CodeWindow.MIN_WIDTH, minHeight: CodeWindow.MIN_HEIGHT, show: !isFullscreenOrMaximized, @@ -133,10 +137,14 @@ export class CodeWindow extends Disposable implements ICodeWindow { // want to enforce that Code stays in the foreground. This triggers a disable_hidden_ // flag that Electron provides via patch: // https://github.com/electron/libchromiumcontent/blob/master/patches/common/chromium/disable_hidden.patch - 'backgroundThrottling': false + backgroundThrottling: false } }; + if (this.nodeless) { + options.webPreferences!.nodeIntegration = false; // simulate Electron 5 behaviour + } + if (isLinux) { options.icon = path.join(this.environmentService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s) } @@ -188,6 +196,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { } } + if (this.nodeless) { + this._win.webContents.toggleDevTools(); + } + this._lastFocusTime = Date.now(); // since we show directly, we need to set the last focus time too } @@ -387,7 +399,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { } // Window (Un)Maximize - this._win.on('maximize', e => { + this._win.on('maximize', (e: Event) => { if (this.currentConfig) { this.currentConfig.maximized = true; } @@ -395,7 +407,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { app.emit('browser-window-maximize', e, this._win); }); - this._win.on('unmaximize', e => { + this._win.on('unmaximize', (e: Event) => { if (this.currentConfig) { this.currentConfig.maximized = false; } @@ -618,6 +630,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private doGetUrl(config: object): string { + if (this.nodeless) { + return `${require.toUrl('vs/code/electron-browser/workbench/workbench.nodeless.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; + } + return `${require.toUrl('vs/code/electron-browser/workbench/workbench.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; } diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 416092593c5..dd5a38ac707 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -42,7 +42,6 @@ import { IProgressRunner, IProgressService } from 'vs/platform/progress/common/p import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { ILayoutService, IDimension } from 'vs/platform/layout/browser/layoutService'; export class SimpleModel implements IResolvedTextEditorModel { @@ -218,31 +217,6 @@ export class SimpleNotificationService implements INotificationService { } } -export class BrowserAccessibilityService implements IAccessibilityService { - _serviceBrand: any; - - private _accessibilitySupport = AccessibilitySupport.Unknown; - private readonly _onDidChangeAccessibilitySupport = new Emitter(); - readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; - - alwaysUnderlineAccessKeys(): Promise { - return Promise.resolve(false); - } - - setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void { - if (this._accessibilitySupport === accessibilitySupport) { - return; - } - - this._accessibilitySupport = accessibilitySupport; - this._onDidChangeAccessibilitySupport.fire(); - } - - getAccessibilitySupport(): AccessibilitySupport { - return this._accessibilitySupport; - } -} - export class StandaloneCommandService implements ICommandService { _serviceBrand: any; diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index ec8771e32bb..e01573a80f1 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -13,7 +13,7 @@ import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; -import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService, BrowserAccessibilityService, SimpleLayoutService } from 'vs/editor/standalone/browser/simpleServices'; +import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService, SimpleLayoutService } from 'vs/editor/standalone/browser/simpleServices'; import { StandaloneCodeEditorServiceImpl } from 'vs/editor/standalone/browser/standaloneCodeServiceImpl'; import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standaloneThemeServiceImpl'; import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; @@ -46,6 +46,7 @@ import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDeco import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl'; import { ISuggestMemoryService, SuggestMemoryService } from 'vs/editor/contrib/suggest/suggestMemory'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; export interface IEditorOverrideServices { @@ -201,7 +202,7 @@ export class DynamicStandaloneServices extends Disposable { let contextViewService = ensure(IContextViewService, () => this._register(new ContextViewService(layoutService))); - ensure(IContextMenuService, () => this._register(new ContextMenuService(domElement, telemetryService, notificationService, contextViewService, keybindingService, themeService))); + ensure(IContextMenuService, () => this._register(new ContextMenuService(layoutService, telemetryService, notificationService, contextViewService, keybindingService, themeService))); ensure(IMenuService, () => new MenuService(commandService)); diff --git a/src/vs/platform/accessibility/common/accessibilityService.ts b/src/vs/platform/accessibility/common/accessibilityService.ts new file mode 100644 index 00000000000..8af1badf8ae --- /dev/null +++ b/src/vs/platform/accessibility/common/accessibilityService.ts @@ -0,0 +1,34 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter, Event } from 'vs/base/common/event'; +import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { Disposable } from 'vs/base/common/lifecycle'; + +export class BrowserAccessibilityService extends Disposable implements IAccessibilityService { + + _serviceBrand: any; + + private _accessibilitySupport = AccessibilitySupport.Unknown; + private readonly _onDidChangeAccessibilitySupport = new Emitter(); + readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; + + alwaysUnderlineAccessKeys(): Promise { + return Promise.resolve(false); + } + + setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void { + if (this._accessibilitySupport === accessibilitySupport) { + return; + } + + this._accessibilitySupport = accessibilitySupport; + this._onDidChangeAccessibilitySupport.fire(); + } + + getAccessibilitySupport(): AccessibilitySupport { + return this._accessibilitySupport; + } +} \ No newline at end of file diff --git a/src/vs/platform/contextview/browser/contextMenuService.ts b/src/vs/platform/contextview/browser/contextMenuService.ts index c19131d8c83..10608ab124c 100644 --- a/src/vs/platform/contextview/browser/contextMenuService.ts +++ b/src/vs/platform/contextview/browser/contextMenuService.ts @@ -12,6 +12,7 @@ import { IContextMenuDelegate } from 'vs/base/browser/contextmenu'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Disposable } from 'vs/base/common/lifecycle'; +import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; export class ContextMenuService extends Disposable implements IContextMenuService { _serviceBrand: any; @@ -22,7 +23,7 @@ export class ContextMenuService extends Disposable implements IContextMenuServic private contextMenuHandler: ContextMenuHandler; constructor( - container: HTMLElement | null, + @ILayoutService layoutService: ILayoutService, @ITelemetryService telemetryService: ITelemetryService, @INotificationService notificationService: INotificationService, @IContextViewService contextViewService: IContextViewService, @@ -31,7 +32,7 @@ export class ContextMenuService extends Disposable implements IContextMenuServic ) { super(); - this.contextMenuHandler = this._register(new ContextMenuHandler(container, contextViewService, telemetryService, notificationService, keybindingService, themeService)); + this.contextMenuHandler = this._register(new ContextMenuHandler(layoutService.container, contextViewService, telemetryService, notificationService, keybindingService, themeService)); } dispose(): void { diff --git a/src/vs/platform/download/node/downloadIpc.ts b/src/vs/platform/download/node/downloadIpc.ts index 52ca30256fe..9fa57a3d065 100644 --- a/src/vs/platform/download/node/downloadIpc.ts +++ b/src/vs/platform/download/node/downloadIpc.ts @@ -4,19 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import * as path from 'vs/base/common/path'; import * as fs from 'fs'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IServerChannel } from 'vs/base/parts/ipc/node/ipc'; import { Event, Emitter } from 'vs/base/common/event'; -import { IDownloadService } from 'vs/platform/download/common/download'; -import { mkdirp } from 'vs/base/node/pfs'; -import { IURITransformer } from 'vs/base/common/uriIpc'; -import { tmpdir } from 'os'; -import { generateUuid } from 'vs/base/common/uuid'; -export type UploadResponse = Buffer | string | undefined; +type UploadResponse = Buffer | string | undefined; -export function upload(uri: URI): Event { +function upload(uri: URI): Event { const stream = new Emitter(); const readstream = fs.createReadStream(uri.fsPath); readstream.on('data', data => stream.fire(data)); @@ -41,36 +35,3 @@ export class DownloadServiceChannel implements IServerChannel { throw new Error(`Call not found: ${command}`); } } - -export class DownloadServiceChannelClient implements IDownloadService { - - _serviceBrand: any; - - constructor(private channel: IChannel, private getUriTransformer: () => IURITransformer) { } - - download(from: URI, to: string = path.join(tmpdir(), generateUuid())): Promise { - from = this.getUriTransformer().transformOutgoingURI(from); - const dirName = path.dirname(to); - let out: fs.WriteStream; - return new Promise((c, e) => { - return mkdirp(dirName) - .then(() => { - out = fs.createWriteStream(to); - out.once('close', () => c(to)); - out.once('error', e); - const uploadStream = this.channel.listen('upload', from); - const disposable = uploadStream(result => { - if (result === undefined) { - disposable.dispose(); - out.end(() => c(to)); - } else if (Buffer.isBuffer(result)) { - out.write(result); - } else if (typeof result === 'string') { - disposable.dispose(); - out.end(() => e(result)); - } - }); - }); - }); - } -} diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index 3232b5ce1c8..9eb99a03f58 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -3,10 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { IWindowDriver, IElement, WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platform/driver/node/driver'; -import { IPCClient } from 'vs/base/parts/ipc/node/ipc'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { getTopLeftOffset, getClientArea } from 'vs/base/browser/dom'; import * as electron from 'electron'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -214,25 +214,24 @@ class WindowDriver implements IWindowDriver { } } -export async function registerWindowDriver( - client: IPCClient, - windowId: number, - instantiationService: IInstantiationService -): Promise { +export async function registerWindowDriver(accessor: ServicesAccessor): Promise { + const instantiationService = accessor.get(IInstantiationService); + const mainProcessService = accessor.get(IMainProcessService); + const windowService = accessor.get(IWindowService); + const windowDriver = instantiationService.createInstance(WindowDriver); const windowDriverChannel = new WindowDriverChannel(windowDriver); - client.registerChannel('windowDriver', windowDriverChannel); + mainProcessService.registerChannel('windowDriver', windowDriverChannel); - const windowDriverRegistryChannel = client.getChannel('windowDriverRegistry'); + const windowDriverRegistryChannel = mainProcessService.getChannel('windowDriverRegistry'); const windowDriverRegistry = new WindowDriverRegistryChannelClient(windowDriverRegistryChannel); - await windowDriverRegistry.registerWindowDriver(windowId); + await windowDriverRegistry.registerWindowDriver(windowService.getCurrentWindowId()); // const options = await windowDriverRegistry.registerWindowDriver(windowId); // if (options.verbose) { // windowDriver.openDevTools(); // } - const disposable = toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowId)); - return combinedDisposable([disposable, client]); + return toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowService.getCurrentWindowId())); } diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 024131e5381..eb1873cd94c 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -69,6 +69,7 @@ export interface ParsedArgs { 'driver'?: string; 'driver-verbose'?: boolean; remote?: string; + 'nodeless'?: boolean; // TODO@ben revisit electron5 nodeless support } export const IEnvironmentService = createDecorator('environmentService'); diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index 25b3fae01f6..170944dbe39 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -91,7 +91,8 @@ export const options: Option[] = [ { id: 'force', type: 'boolean' }, { id: 'trace-category-filter', type: 'string' }, { id: 'trace-options', type: 'string' }, - { id: 'prof-code-loading', type: 'boolean' } + { id: 'prof-code-loading', type: 'boolean' }, + { id: 'nodeless', type: 'boolean' } // TODO@ben revisit electron5 nodeless support ]; export function parseArgs(args: string[], isOptionSupported = (_: Option) => true): ParsedArgs { diff --git a/src/vs/platform/ipc/electron-browser/mainProcessService.ts b/src/vs/platform/ipc/electron-browser/mainProcessService.ts new file mode 100644 index 00000000000..a60095a445e --- /dev/null +++ b/src/vs/platform/ipc/electron-browser/mainProcessService.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; +import { Client } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser'; +import { Disposable } from 'vs/base/common/lifecycle'; + +export const IMainProcessService = createDecorator('mainProcessService'); + +export interface IMainProcessService { + + _serviceBrand: ServiceIdentifier; + + getChannel(channelName: string): IChannel; + + registerChannel(channelName: string, channel: IServerChannel): void; +} + +export class MainProcessService extends Disposable implements IMainProcessService { + + _serviceBrand: ServiceIdentifier; + + private mainProcessConnection: Client; + + constructor( + windowId: number + ) { + super(); + + this.mainProcessConnection = this._register(new Client(`window:${windowId}`)); + } + + getChannel(channelName: string): IChannel { + return this.mainProcessConnection.getChannel(channelName); + } + + registerChannel(channelName: string, channel: IServerChannel): void { + this.mainProcessConnection.registerChannel(channelName, channel); + } +} \ No newline at end of file diff --git a/src/vs/platform/sharedProcess/node/sharedProcessService.ts b/src/vs/platform/ipc/electron-browser/sharedProcessService.ts similarity index 97% rename from src/vs/platform/sharedProcess/node/sharedProcessService.ts rename to src/vs/platform/ipc/electron-browser/sharedProcessService.ts index 39734b76166..90100879bee 100644 --- a/src/vs/platform/sharedProcess/node/sharedProcessService.ts +++ b/src/vs/platform/ipc/electron-browser/sharedProcessService.ts @@ -32,7 +32,7 @@ export class SharedProcessService implements ISharedProcessService { @IEnvironmentService environmentService: IEnvironmentService ) { this.withSharedProcessConnection = windowsService.whenSharedProcessReady() - .then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.getConfiguration().windowId}`)); + .then(() => connect(environmentService.sharedIPCHandle, `window:${windowService.getCurrentWindowId()}`)); } getChannel(channelName: string): IChannel { diff --git a/src/vs/platform/issue/electron-browser/issueService.ts b/src/vs/platform/issue/electron-browser/issueService.ts new file mode 100644 index 00000000000..705c5ce41be --- /dev/null +++ b/src/vs/platform/issue/electron-browser/issueService.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IIssueService, IssueReporterData, ProcessExplorerData } from 'vs/platform/issue/common/issue'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; + +export class IssueService implements IIssueService { + + _serviceBrand: ServiceIdentifier; + + private channel: IChannel; + + constructor(@IMainProcessService mainProcessService: IMainProcessService) { + this.channel = mainProcessService.getChannel('issue'); + } + + openReporter(data: IssueReporterData): Promise { + return this.channel.call('openIssueReporter', data); + } + + openProcessExplorer(data: ProcessExplorerData): Promise { + return this.channel.call('openProcessExplorer', data); + } +} \ No newline at end of file diff --git a/src/vs/platform/issue/node/issueIpc.ts b/src/vs/platform/issue/node/issueIpc.ts index a4a3df818fb..2183eac8e61 100644 --- a/src/vs/platform/issue/node/issueIpc.ts +++ b/src/vs/platform/issue/node/issueIpc.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; -import { IIssueService, IssueReporterData, ProcessExplorerData } from '../common/issue'; +import { IServerChannel } from 'vs/base/parts/ipc/node/ipc'; import { Event } from 'vs/base/common/event'; +import { IIssueService } from 'vs/platform/issue/common/issue'; export class IssueChannel implements IServerChannel { @@ -25,19 +25,4 @@ export class IssueChannel implements IServerChannel { throw new Error(`Call not found: ${command}`); } -} - -export class IssueChannelClient implements IIssueService { - - _serviceBrand: any; - - constructor(private channel: IChannel) { } - - openReporter(data: IssueReporterData): Promise { - return this.channel.call('openIssueReporter', data); - } - - openProcessExplorer(data: ProcessExplorerData): Promise { - return this.channel.call('openProcessExplorer', data); - } } \ No newline at end of file diff --git a/src/vs/platform/lifecycle/common/lifecycleService.ts b/src/vs/platform/lifecycle/common/lifecycleService.ts new file mode 100644 index 00000000000..dd8e343759a --- /dev/null +++ b/src/vs/platform/lifecycle/common/lifecycleService.ts @@ -0,0 +1,74 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event, Emitter } from 'vs/base/common/event'; +import { Barrier } from 'vs/base/common/async'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { ILifecycleService, BeforeShutdownEvent, WillShutdownEvent, StartupKind, LifecyclePhase, LifecyclePhaseToString } from 'vs/platform/lifecycle/common/lifecycle'; +import { ILogService } from 'vs/platform/log/common/log'; +import { mark } from 'vs/base/common/performance'; + +export abstract class AbstractLifecycleService extends Disposable implements ILifecycleService { + + _serviceBrand: any; + + protected readonly _onBeforeShutdown = this._register(new Emitter()); + get onBeforeShutdown(): Event { return this._onBeforeShutdown.event; } + + protected readonly _onWillShutdown = this._register(new Emitter()); + get onWillShutdown(): Event { return this._onWillShutdown.event; } + + protected readonly _onShutdown = this._register(new Emitter()); + get onShutdown(): Event { return this._onShutdown.event; } + + protected _startupKind: StartupKind; + get startupKind(): StartupKind { return this._startupKind; } + + private _phase: LifecyclePhase = LifecyclePhase.Starting; + get phase(): LifecyclePhase { return this._phase; } + + private phaseWhen = new Map(); + + constructor( + @ILogService protected readonly logService: ILogService + ) { + super(); + } + + set phase(value: LifecyclePhase) { + if (value < this.phase) { + throw new Error('Lifecycle cannot go backwards'); + } + + if (this._phase === value) { + return; + } + + this.logService.trace(`lifecycle: phase changed (value: ${value})`); + + this._phase = value; + mark(`LifecyclePhase/${LifecyclePhaseToString(value)}`); + + const barrier = this.phaseWhen.get(this._phase); + if (barrier) { + barrier.open(); + this.phaseWhen.delete(this._phase); + } + } + + when(phase: LifecyclePhase): Promise { + if (phase <= this._phase) { + return Promise.resolve(); + } + + let barrier = this.phaseWhen.get(phase); + if (!barrier) { + barrier = new Barrier(); + this.phaseWhen.set(phase, barrier); + } + + return barrier.wait(); + } +} \ No newline at end of file diff --git a/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts b/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts index 7d55e6eb062..2e2bf75aa00 100644 --- a/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts +++ b/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts @@ -4,50 +4,30 @@ *--------------------------------------------------------------------------------------------*/ import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { ILifecycleService, BeforeShutdownEvent, ShutdownReason, StartupKind, LifecyclePhase, handleVetos, LifecyclePhaseToString, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle'; +import { ShutdownReason, StartupKind, handleVetos } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ipcRenderer as ipc } from 'electron'; -import { Event, Emitter } from 'vs/base/common/event'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { mark } from 'vs/base/common/performance'; -import { Barrier } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { Disposable } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; -export class LifecycleService extends Disposable implements ILifecycleService { +export class LifecycleService extends AbstractLifecycleService { private static readonly LAST_SHUTDOWN_REASON_KEY = 'lifecyle.lastShutdownReason'; _serviceBrand: any; - private readonly _onBeforeShutdown = this._register(new Emitter()); - get onBeforeShutdown(): Event { return this._onBeforeShutdown.event; } - - private readonly _onWillShutdown = this._register(new Emitter()); - get onWillShutdown(): Event { return this._onWillShutdown.event; } - - private readonly _onShutdown = this._register(new Emitter()); - get onShutdown(): Event { return this._onShutdown.event; } - - private readonly _startupKind: StartupKind; - get startupKind(): StartupKind { return this._startupKind; } - - private _phase: LifecyclePhase = LifecyclePhase.Starting; - get phase(): LifecyclePhase { return this._phase; } - - private phaseWhen = new Map(); - private shutdownReason: ShutdownReason; constructor( @INotificationService private readonly notificationService: INotificationService, @IWindowService private readonly windowService: IWindowService, - @IStorageService private readonly storageService: IStorageService, - @ILogService private readonly logService: ILogService + @IStorageService readonly storageService: IStorageService, + @ILogService readonly logService: ILogService ) { - super(); + super(logService); this._startupKind = this.resolveStartupKind(); @@ -148,39 +128,4 @@ export class LifecycleService extends Disposable implements ILifecycleService { onUnexpectedError(err); }); } - - set phase(value: LifecyclePhase) { - if (value < this.phase) { - throw new Error('Lifecycle cannot go backwards'); - } - - if (this._phase === value) { - return; - } - - this.logService.trace(`lifecycle: phase changed (value: ${value})`); - - this._phase = value; - mark(`LifecyclePhase/${LifecyclePhaseToString(value)}`); - - const barrier = this.phaseWhen.get(this._phase); - if (barrier) { - barrier.open(); - this.phaseWhen.delete(this._phase); - } - } - - when(phase: LifecyclePhase): Promise { - if (phase <= this._phase) { - return Promise.resolve(); - } - - let barrier = this.phaseWhen.get(phase); - if (!barrier) { - barrier = new Barrier(); - this.phaseWhen.set(phase, barrier); - } - - return barrier.wait(); - } } diff --git a/src/vs/platform/localizations/electron-browser/localizationsService.ts b/src/vs/platform/localizations/electron-browser/localizationsService.ts new file mode 100644 index 00000000000..13d70a8872f --- /dev/null +++ b/src/vs/platform/localizations/electron-browser/localizationsService.ts @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IChannel } from 'vs/base/parts/ipc/node/ipc'; +import { Event } from 'vs/base/common/event'; +import { ILocalizationsService, LanguageType } from 'vs/platform/localizations/common/localizations'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; + +export class LocalizationsService implements ILocalizationsService { + + _serviceBrand: ServiceIdentifier; + + private channel: IChannel; + + constructor(@ISharedProcessService sharedProcessService: ISharedProcessService) { + this.channel = sharedProcessService.getChannel('localizations'); + } + + get onDidLanguagesChange(): Event { return this.channel.listen('onDidLanguagesChange'); } + + getLanguageIds(type?: LanguageType): Promise { + return this.channel.call('getLanguageIds', type); + } +} \ No newline at end of file diff --git a/src/vs/platform/localizations/node/localizationsIpc.ts b/src/vs/platform/localizations/node/localizationsIpc.ts index eef2f972727..02c36add60e 100644 --- a/src/vs/platform/localizations/node/localizationsIpc.ts +++ b/src/vs/platform/localizations/node/localizationsIpc.ts @@ -3,10 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IServerChannel } from 'vs/base/parts/ipc/node/ipc'; import { Event } from 'vs/base/common/event'; -import { ILocalizationsService, LanguageType } from 'vs/platform/localizations/common/localizations'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; export class LocalizationsChannel implements IServerChannel { @@ -32,20 +31,3 @@ export class LocalizationsChannel implements IServerChannel { throw new Error(`Call not found: ${command}`); } } - -export class LocalizationsChannelClient implements ILocalizationsService { - - _serviceBrand: any; - - private channel: IChannel; - - constructor(@ISharedProcessService sharedProcessService: ISharedProcessService) { - this.channel = sharedProcessService.getChannel('localizations'); - } - - get onDidLanguagesChange(): Event { return this.channel.listen('onDidLanguagesChange'); } - - getLanguageIds(type?: LanguageType): Promise { - return this.channel.call('getLanguageIds', type); - } -} \ No newline at end of file diff --git a/src/vs/platform/menubar/electron-browser/menubarService.ts b/src/vs/platform/menubar/electron-browser/menubarService.ts new file mode 100644 index 00000000000..55ad9a46142 --- /dev/null +++ b/src/vs/platform/menubar/electron-browser/menubarService.ts @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; + +export class MenubarService implements IMenubarService { + + _serviceBrand: ServiceIdentifier; + + private channel: IChannel; + + constructor(@IMainProcessService mainProcessService: IMainProcessService) { + this.channel = mainProcessService.getChannel('menubar'); + } + + updateMenubar(windowId: number, menuData: IMenubarData): Promise { + return this.channel.call('updateMenubar', [windowId, menuData]); + } +} diff --git a/src/vs/platform/menubar/node/menubarIpc.ts b/src/vs/platform/menubar/node/menubarIpc.ts index ff2166784ef..3b92dada057 100644 --- a/src/vs/platform/menubar/node/menubarIpc.ts +++ b/src/vs/platform/menubar/node/menubarIpc.ts @@ -2,8 +2,9 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; -import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar'; + +import { IServerChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IMenubarService } from 'vs/platform/menubar/common/menubar'; import { Event } from 'vs/base/common/event'; export class MenubarChannel implements IServerChannel { @@ -21,15 +22,4 @@ export class MenubarChannel implements IServerChannel { throw new Error(`Call not found: ${command}`); } -} - -export class MenubarChannelClient implements IMenubarService { - - _serviceBrand: any; - - constructor(private channel: IChannel) { } - - updateMenubar(windowId: number, menuData: IMenubarData): Promise { - return this.channel.call('updateMenubar', [windowId, menuData]); - } -} +} \ No newline at end of file diff --git a/src/vs/platform/telemetry/node/telemetryService.ts b/src/vs/platform/telemetry/electron-browser/telemetryService.ts similarity index 96% rename from src/vs/platform/telemetry/node/telemetryService.ts rename to src/vs/platform/telemetry/electron-browser/telemetryService.ts index 3ef3a9fe94c..31d0309b041 100644 --- a/src/vs/platform/telemetry/node/telemetryService.ts +++ b/src/vs/platform/telemetry/electron-browser/telemetryService.ts @@ -9,7 +9,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { Disposable } from 'vs/base/common/lifecycle'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IProductService } from 'vs/platform/product/common/product'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { TelemetryAppenderClient } from 'vs/platform/telemetry/node/telemetryIpc'; import { ILogService } from 'vs/platform/log/common/log'; import { IStorageService } from 'vs/platform/storage/common/storage'; diff --git a/src/vs/platform/update/electron-browser/updateService.ts b/src/vs/platform/update/electron-browser/updateService.ts new file mode 100644 index 00000000000..57ac62f05ca --- /dev/null +++ b/src/vs/platform/update/electron-browser/updateService.ts @@ -0,0 +1,59 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IChannel } from 'vs/base/parts/ipc/node/ipc'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IUpdateService, State } from 'vs/platform/update/common/update'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; + +export class UpdateService implements IUpdateService { + + _serviceBrand: ServiceIdentifier; + + private _onStateChange = new Emitter(); + get onStateChange(): Event { return this._onStateChange.event; } + + private _state: State = State.Uninitialized; + get state(): State { return this._state; } + + private channel: IChannel; + + constructor(@IMainProcessService mainProcessService: IMainProcessService) { + this.channel = mainProcessService.getChannel('update'); + + // always set this._state as the state changes + this.onStateChange(state => this._state = state); + + this.channel.call('_getInitialState').then(state => { + // fire initial state + this._onStateChange.fire(state); + + // fire subsequent states as they come in from remote + + this.channel.listen('onStateChange')(state => this._onStateChange.fire(state)); + }); + } + + checkForUpdates(context: any): Promise { + return this.channel.call('checkForUpdates', context); + } + + downloadUpdate(): Promise { + return this.channel.call('downloadUpdate'); + } + + applyUpdate(): Promise { + return this.channel.call('applyUpdate'); + } + + quitAndInstall(): Promise { + return this.channel.call('quitAndInstall'); + } + + isLatestVersion(): Promise { + return this.channel.call('isLatestVersion'); + } +} diff --git a/src/vs/platform/update/node/updateIpc.ts b/src/vs/platform/update/node/updateIpc.ts index 69308aaacb3..df6760eda45 100644 --- a/src/vs/platform/update/node/updateIpc.ts +++ b/src/vs/platform/update/node/updateIpc.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; -import { Event, Emitter } from 'vs/base/common/event'; -import { IUpdateService, State } from 'vs/platform/update/common/update'; +import { IServerChannel } from 'vs/base/parts/ipc/node/ipc'; +import { Event } from 'vs/base/common/event'; +import { IUpdateService } from 'vs/platform/update/common/update'; export class UpdateChannel implements IServerChannel { @@ -31,49 +31,4 @@ export class UpdateChannel implements IServerChannel { throw new Error(`Call not found: ${command}`); } -} - -export class UpdateChannelClient implements IUpdateService { - - _serviceBrand: any; - - private _onStateChange = new Emitter(); - get onStateChange(): Event { return this._onStateChange.event; } - - private _state: State = State.Uninitialized; - get state(): State { return this._state; } - - constructor(private channel: IChannel) { - // always set this._state as the state changes - this.onStateChange(state => this._state = state); - - channel.call('_getInitialState').then(state => { - // fire initial state - this._onStateChange.fire(state); - - // fire subsequent states as they come in from remote - - this.channel.listen('onStateChange')(state => this._onStateChange.fire(state)); - }); - } - - checkForUpdates(context: any): Promise { - return this.channel.call('checkForUpdates', context); - } - - downloadUpdate(): Promise { - return this.channel.call('downloadUpdate'); - } - - applyUpdate(): Promise { - return this.channel.call('applyUpdate'); - } - - quitAndInstall(): Promise { - return this.channel.call('quitAndInstall'); - } - - isLatestVersion(): Promise { - return this.channel.call('isLatestVersion'); - } -} +} \ No newline at end of file diff --git a/src/vs/platform/url/common/urlService.ts b/src/vs/platform/url/common/urlService.ts index a08ae07d15a..afcfff01be4 100644 --- a/src/vs/platform/url/common/urlService.ts +++ b/src/vs/platform/url/common/urlService.ts @@ -8,10 +8,11 @@ import { URI } from 'vs/base/common/uri'; import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { first } from 'vs/base/common/async'; import { values } from 'vs/base/common/map'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class URLService implements IURLService { - _serviceBrand: any; + _serviceBrand: ServiceIdentifier; private handlers = new Set(); @@ -25,18 +26,3 @@ export class URLService implements IURLService { return toDisposable(() => this.handlers.delete(handler)); } } - -export class RelayURLService extends URLService implements IURLHandler { - - constructor(private urlService: IURLService) { - super(); - } - - open(uri: URI): Promise { - return this.urlService.open(uri); - } - - handleURL(uri: URI): Promise { - return super.open(uri); - } -} diff --git a/src/vs/platform/url/electron-browser/urlService.ts b/src/vs/platform/url/electron-browser/urlService.ts new file mode 100644 index 00000000000..814ad021e59 --- /dev/null +++ b/src/vs/platform/url/electron-browser/urlService.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; +import { URI } from 'vs/base/common/uri'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { URLServiceChannelClient, URLHandlerChannel } from 'vs/platform/url/node/urlIpc'; +import { URLService } from 'vs/platform/url/common/urlService'; + +export class RelayURLService extends URLService implements IURLHandler { + private urlService: IURLService; + + constructor(@IMainProcessService mainProcessService: IMainProcessService) { + super(); + + this.urlService = new URLServiceChannelClient(mainProcessService.getChannel('url')); + + mainProcessService.registerChannel('urlHandler', new URLHandlerChannel(this)); + } + + open(uri: URI): Promise { + return this.urlService.open(uri); + } + + handleURL(uri: URI): Promise { + return super.open(uri); + } +} diff --git a/src/vs/platform/windows/electron-browser/windowsService.ts b/src/vs/platform/windows/electron-browser/windowsService.ts new file mode 100644 index 00000000000..531d7ce55a0 --- /dev/null +++ b/src/vs/platform/windows/electron-browser/windowsService.ts @@ -0,0 +1,250 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event } from 'vs/base/common/event'; +import { IChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, CrashReporterStartOptions, IMessageBoxResult, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IDevToolsOptions, INewWindowOptions, IURIToOpen } from 'vs/platform/windows/common/windows'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IRecentlyOpened, IRecent, isRecentWorkspace } from 'vs/platform/history/common/history'; +import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; +import { URI } from 'vs/base/common/uri'; +import { ParsedArgs } from 'vs/platform/environment/common/environment'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; + +export class WindowsService implements IWindowsService { + + _serviceBrand: any; + + private channel: IChannel; + + constructor(@IMainProcessService mainProcessService: IMainProcessService) { + this.channel = mainProcessService.getChannel('windows'); + } + + get onWindowOpen(): Event { return this.channel.listen('onWindowOpen'); } + get onWindowFocus(): Event { return this.channel.listen('onWindowFocus'); } + get onWindowBlur(): Event { return this.channel.listen('onWindowBlur'); } + get onWindowMaximize(): Event { return this.channel.listen('onWindowMaximize'); } + get onWindowUnmaximize(): Event { return this.channel.listen('onWindowUnmaximize'); } + get onRecentlyOpenedChange(): Event { return this.channel.listen('onRecentlyOpenedChange'); } + + pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise { + return this.channel.call('pickFileFolderAndOpen', options); + } + + pickFileAndOpen(options: INativeOpenDialogOptions): Promise { + return this.channel.call('pickFileAndOpen', options); + } + + pickFolderAndOpen(options: INativeOpenDialogOptions): Promise { + return this.channel.call('pickFolderAndOpen', options); + } + + pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise { + return this.channel.call('pickWorkspaceAndOpen', options); + } + + showMessageBox(windowId: number, options: MessageBoxOptions): Promise { + return this.channel.call('showMessageBox', [windowId, options]); + } + + showSaveDialog(windowId: number, options: SaveDialogOptions): Promise { + return this.channel.call('showSaveDialog', [windowId, options]); + } + + showOpenDialog(windowId: number, options: OpenDialogOptions): Promise { + return this.channel.call('showOpenDialog', [windowId, options]); + } + + reloadWindow(windowId: number, args?: ParsedArgs): Promise { + return this.channel.call('reloadWindow', [windowId, args]); + } + + openDevTools(windowId: number, options?: IDevToolsOptions): Promise { + return this.channel.call('openDevTools', [windowId, options]); + } + + toggleDevTools(windowId: number): Promise { + return this.channel.call('toggleDevTools', windowId); + } + + closeWorkspace(windowId: number): Promise { + return this.channel.call('closeWorkspace', windowId); + } + + enterWorkspace(windowId: number, path: URI): Promise { + return this.channel.call('enterWorkspace', [windowId, path]).then((result: IEnterWorkspaceResult) => { + result.workspace = reviveWorkspaceIdentifier(result.workspace); + return result; + }); + } + + toggleFullScreen(windowId: number): Promise { + return this.channel.call('toggleFullScreen', windowId); + } + + setRepresentedFilename(windowId: number, fileName: string): Promise { + return this.channel.call('setRepresentedFilename', [windowId, fileName]); + } + + addRecentlyOpened(recent: IRecent[]): Promise { + return this.channel.call('addRecentlyOpened', recent); + } + + removeFromRecentlyOpened(paths: Array): Promise { + return this.channel.call('removeFromRecentlyOpened', paths); + } + + clearRecentlyOpened(): Promise { + return this.channel.call('clearRecentlyOpened'); + } + + getRecentlyOpened(windowId: number): Promise { + return this.channel.call('getRecentlyOpened', windowId) + .then((recentlyOpened: IRecentlyOpened) => { + recentlyOpened.workspaces.forEach(recent => isRecentWorkspace(recent) ? recent.workspace = reviveWorkspaceIdentifier(recent.workspace) : recent.folderUri = URI.revive(recent.folderUri)); + recentlyOpened.files.forEach(recent => recent.fileUri = URI.revive(recent.fileUri)); + return recentlyOpened; + }); + } + + newWindowTab(): Promise { + return this.channel.call('newWindowTab'); + } + + showPreviousWindowTab(): Promise { + return this.channel.call('showPreviousWindowTab'); + } + + showNextWindowTab(): Promise { + return this.channel.call('showNextWindowTab'); + } + + moveWindowTabToNewWindow(): Promise { + return this.channel.call('moveWindowTabToNewWindow'); + } + + mergeAllWindowTabs(): Promise { + return this.channel.call('mergeAllWindowTabs'); + } + + toggleWindowTabsBar(): Promise { + return this.channel.call('toggleWindowTabsBar'); + } + + focusWindow(windowId: number): Promise { + return this.channel.call('focusWindow', windowId); + } + + closeWindow(windowId: number): Promise { + return this.channel.call('closeWindow', windowId); + } + + isFocused(windowId: number): Promise { + return this.channel.call('isFocused', windowId); + } + + isMaximized(windowId: number): Promise { + return this.channel.call('isMaximized', windowId); + } + + maximizeWindow(windowId: number): Promise { + return this.channel.call('maximizeWindow', windowId); + } + + unmaximizeWindow(windowId: number): Promise { + return this.channel.call('unmaximizeWindow', windowId); + } + + minimizeWindow(windowId: number): Promise { + return this.channel.call('minimizeWindow', windowId); + } + + onWindowTitleDoubleClick(windowId: number): Promise { + return this.channel.call('onWindowTitleDoubleClick', windowId); + } + + setDocumentEdited(windowId: number, flag: boolean): Promise { + return this.channel.call('setDocumentEdited', [windowId, flag]); + } + + quit(): Promise { + return this.channel.call('quit'); + } + + relaunch(options: { addArgs?: string[], removeArgs?: string[] }): Promise { + return this.channel.call('relaunch', [options]); + } + + whenSharedProcessReady(): Promise { + return this.channel.call('whenSharedProcessReady'); + } + + toggleSharedProcess(): Promise { + return this.channel.call('toggleSharedProcess'); + } + + openWindow(windowId: number, uris: IURIToOpen[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean, forceOpenWorkspaceAsFile?: boolean, args?: ParsedArgs }): Promise { + return this.channel.call('openWindow', [windowId, uris, options]); + } + + openNewWindow(options?: INewWindowOptions): Promise { + return this.channel.call('openNewWindow', options); + } + + showWindow(windowId: number): Promise { + return this.channel.call('showWindow', windowId); + } + + getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> { + return this.channel.call<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>('getWindows').then(result => { + for (const win of result) { + if (win.folderUri) { + win.folderUri = URI.revive(win.folderUri); + } + if (win.workspace) { + win.workspace = reviveWorkspaceIdentifier(win.workspace); + } + } + return result; + }); + } + + getWindowCount(): Promise { + return this.channel.call('getWindowCount'); + } + + log(severity: string, ...messages: string[]): Promise { + return this.channel.call('log', [severity, messages]); + } + + showItemInFolder(path: URI): Promise { + return this.channel.call('showItemInFolder', path); + } + + getActiveWindowId(): Promise { + return this.channel.call('getActiveWindowId'); + } + + openExternal(url: string): Promise { + return this.channel.call('openExternal', url); + } + + startCrashReporter(config: CrashReporterStartOptions): Promise { + return this.channel.call('startCrashReporter', config); + } + + updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise { + return this.channel.call('updateTouchBar', [windowId, items]); + } + + openAboutDialog(): Promise { + return this.channel.call('openAboutDialog'); + } + + resolveProxy(windowId: number, url: string): Promise { + return Promise.resolve(this.channel.call('resolveProxy', [windowId, url])); + } +} \ No newline at end of file diff --git a/src/vs/platform/windows/node/windowsIpc.ts b/src/vs/platform/windows/node/windowsIpc.ts index b06f9df6fce..287e5c6aa78 100644 --- a/src/vs/platform/windows/node/windowsIpc.ts +++ b/src/vs/platform/windows/node/windowsIpc.ts @@ -4,13 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; -import { IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, CrashReporterStartOptions, IMessageBoxResult, MessageBoxOptions, SaveDialogOptions, OpenDialogOptions, IDevToolsOptions, INewWindowOptions, IURIToOpen } from 'vs/platform/windows/common/windows'; -import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { IRecentlyOpened, isRecentFile, isRecentFolder, IRecent, isRecentWorkspace } from 'vs/platform/history/common/history'; -import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; +import { IServerChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IWindowsService, IURIToOpen } from 'vs/platform/windows/common/windows'; +import { reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; -import { ParsedArgs } from 'vs/platform/environment/common/environment'; +import { IRecent, isRecentFile, isRecentFolder } from 'vs/platform/history/common/history'; export class WindowsChannel implements IServerChannel { @@ -108,236 +106,4 @@ export class WindowsChannel implements IServerChannel { throw new Error(`Call not found: ${command}`); } -} - -export class WindowsChannelClient implements IWindowsService { - - _serviceBrand: any; - - constructor(private channel: IChannel) { } - - get onWindowOpen(): Event { return this.channel.listen('onWindowOpen'); } - get onWindowFocus(): Event { return this.channel.listen('onWindowFocus'); } - get onWindowBlur(): Event { return this.channel.listen('onWindowBlur'); } - get onWindowMaximize(): Event { return this.channel.listen('onWindowMaximize'); } - get onWindowUnmaximize(): Event { return this.channel.listen('onWindowUnmaximize'); } - get onRecentlyOpenedChange(): Event { return this.channel.listen('onRecentlyOpenedChange'); } - - pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise { - return this.channel.call('pickFileFolderAndOpen', options); - } - - pickFileAndOpen(options: INativeOpenDialogOptions): Promise { - return this.channel.call('pickFileAndOpen', options); - } - - pickFolderAndOpen(options: INativeOpenDialogOptions): Promise { - return this.channel.call('pickFolderAndOpen', options); - } - - pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise { - return this.channel.call('pickWorkspaceAndOpen', options); - } - - showMessageBox(windowId: number, options: MessageBoxOptions): Promise { - return this.channel.call('showMessageBox', [windowId, options]); - } - - showSaveDialog(windowId: number, options: SaveDialogOptions): Promise { - return this.channel.call('showSaveDialog', [windowId, options]); - } - - showOpenDialog(windowId: number, options: OpenDialogOptions): Promise { - return this.channel.call('showOpenDialog', [windowId, options]); - } - - reloadWindow(windowId: number, args?: ParsedArgs): Promise { - return this.channel.call('reloadWindow', [windowId, args]); - } - - openDevTools(windowId: number, options?: IDevToolsOptions): Promise { - return this.channel.call('openDevTools', [windowId, options]); - } - - toggleDevTools(windowId: number): Promise { - return this.channel.call('toggleDevTools', windowId); - } - - closeWorkspace(windowId: number): Promise { - return this.channel.call('closeWorkspace', windowId); - } - - enterWorkspace(windowId: number, path: URI): Promise { - return this.channel.call('enterWorkspace', [windowId, path]).then((result: IEnterWorkspaceResult) => { - result.workspace = reviveWorkspaceIdentifier(result.workspace); - return result; - }); - } - - toggleFullScreen(windowId: number): Promise { - return this.channel.call('toggleFullScreen', windowId); - } - - setRepresentedFilename(windowId: number, fileName: string): Promise { - return this.channel.call('setRepresentedFilename', [windowId, fileName]); - } - - addRecentlyOpened(recent: IRecent[]): Promise { - return this.channel.call('addRecentlyOpened', recent); - } - - removeFromRecentlyOpened(paths: Array): Promise { - return this.channel.call('removeFromRecentlyOpened', paths); - } - - clearRecentlyOpened(): Promise { - return this.channel.call('clearRecentlyOpened'); - } - - getRecentlyOpened(windowId: number): Promise { - return this.channel.call('getRecentlyOpened', windowId) - .then((recentlyOpened: IRecentlyOpened) => { - recentlyOpened.workspaces.forEach(recent => isRecentWorkspace(recent) ? recent.workspace = reviveWorkspaceIdentifier(recent.workspace) : recent.folderUri = URI.revive(recent.folderUri)); - recentlyOpened.files.forEach(recent => recent.fileUri = URI.revive(recent.fileUri)); - return recentlyOpened; - }); - } - - newWindowTab(): Promise { - return this.channel.call('newWindowTab'); - } - - showPreviousWindowTab(): Promise { - return this.channel.call('showPreviousWindowTab'); - } - - showNextWindowTab(): Promise { - return this.channel.call('showNextWindowTab'); - } - - moveWindowTabToNewWindow(): Promise { - return this.channel.call('moveWindowTabToNewWindow'); - } - - mergeAllWindowTabs(): Promise { - return this.channel.call('mergeAllWindowTabs'); - } - - toggleWindowTabsBar(): Promise { - return this.channel.call('toggleWindowTabsBar'); - } - - focusWindow(windowId: number): Promise { - return this.channel.call('focusWindow', windowId); - } - - closeWindow(windowId: number): Promise { - return this.channel.call('closeWindow', windowId); - } - - isFocused(windowId: number): Promise { - return this.channel.call('isFocused', windowId); - } - - isMaximized(windowId: number): Promise { - return this.channel.call('isMaximized', windowId); - } - - maximizeWindow(windowId: number): Promise { - return this.channel.call('maximizeWindow', windowId); - } - - unmaximizeWindow(windowId: number): Promise { - return this.channel.call('unmaximizeWindow', windowId); - } - - minimizeWindow(windowId: number): Promise { - return this.channel.call('minimizeWindow', windowId); - } - - onWindowTitleDoubleClick(windowId: number): Promise { - return this.channel.call('onWindowTitleDoubleClick', windowId); - } - - setDocumentEdited(windowId: number, flag: boolean): Promise { - return this.channel.call('setDocumentEdited', [windowId, flag]); - } - - quit(): Promise { - return this.channel.call('quit'); - } - - relaunch(options: { addArgs?: string[], removeArgs?: string[] }): Promise { - return this.channel.call('relaunch', [options]); - } - - whenSharedProcessReady(): Promise { - return this.channel.call('whenSharedProcessReady'); - } - - toggleSharedProcess(): Promise { - return this.channel.call('toggleSharedProcess'); - } - - openWindow(windowId: number, uris: IURIToOpen[], options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean, forceOpenWorkspaceAsFile?: boolean, args?: ParsedArgs }): Promise { - return this.channel.call('openWindow', [windowId, uris, options]); - } - - openNewWindow(options?: INewWindowOptions): Promise { - return this.channel.call('openNewWindow', options); - } - - showWindow(windowId: number): Promise { - return this.channel.call('showWindow', windowId); - } - - getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> { - return this.channel.call<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>('getWindows').then(result => { - for (const win of result) { - if (win.folderUri) { - win.folderUri = URI.revive(win.folderUri); - } - if (win.workspace) { - win.workspace = reviveWorkspaceIdentifier(win.workspace); - } - } - return result; - }); - } - - getWindowCount(): Promise { - return this.channel.call('getWindowCount'); - } - - log(severity: string, ...messages: string[]): Promise { - return this.channel.call('log', [severity, messages]); - } - - showItemInFolder(path: URI): Promise { - return this.channel.call('showItemInFolder', path); - } - - getActiveWindowId(): Promise { - return this.channel.call('getActiveWindowId'); - } - - openExternal(url: string): Promise { - return this.channel.call('openExternal', url); - } - - startCrashReporter(config: CrashReporterStartOptions): Promise { - return this.channel.call('startCrashReporter', config); - } - - updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise { - return this.channel.call('updateTouchBar', [windowId, items]); - } - - openAboutDialog(): Promise { - return this.channel.call('openAboutDialog'); - } - - resolveProxy(windowId: number, url: string): Promise { - return Promise.resolve(this.channel.call('resolveProxy', [windowId, url])); - } } \ No newline at end of file diff --git a/src/vs/platform/workspaces/electron-browser/workspacesService.ts b/src/vs/platform/workspaces/electron-browser/workspacesService.ts new file mode 100644 index 00000000000..d9cbca83c41 --- /dev/null +++ b/src/vs/platform/workspaces/electron-browser/workspacesService.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IWorkspacesService, IWorkspaceIdentifier, IWorkspaceFolderCreationData, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { URI } from 'vs/base/common/uri'; + +export class WorkspacesService implements IWorkspacesService { + + _serviceBrand: ServiceIdentifier; + + private channel: IChannel; + + constructor(@IMainProcessService mainProcessService: IMainProcessService) { + this.channel = mainProcessService.getChannel('workspaces'); + } + + createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { + return this.channel.call('createUntitledWorkspace', [folders, remoteAuthority]).then(reviveWorkspaceIdentifier); + } + + deleteUntitledWorkspace(workspaceIdentifier: IWorkspaceIdentifier): Promise { + return this.channel.call('deleteUntitledWorkspace', workspaceIdentifier); + } + + getWorkspaceIdentifier(configPath: URI): Promise { + return this.channel.call('getWorkspaceIdentifier', configPath); + } +} diff --git a/src/vs/platform/workspaces/node/workspacesIpc.ts b/src/vs/platform/workspaces/node/workspacesIpc.ts index 405479b69ef..efc6351bf93 100644 --- a/src/vs/platform/workspaces/node/workspacesIpc.ts +++ b/src/vs/platform/workspaces/node/workspacesIpc.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; -import { IWorkspacesService, IWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesMainService, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { IServerChannel } from 'vs/base/parts/ipc/node/ipc'; +import { IWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesMainService } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; @@ -45,22 +45,3 @@ export class WorkspacesChannel implements IServerChannel { throw new Error(`Call not found: ${command}`); } } - -export class WorkspacesChannelClient implements IWorkspacesService { - - _serviceBrand: any; - - constructor(private channel: IChannel) { } - - createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[], remoteAuthority?: string): Promise { - return this.channel.call('createUntitledWorkspace', [folders, remoteAuthority]).then(reviveWorkspaceIdentifier); - } - - deleteUntitledWorkspace(workspaceIdentifier: IWorkspaceIdentifier): Promise { - return this.channel.call('deleteUntitledWorkspace', workspaceIdentifier); - } - - getWorkspaceIdentifier(configPath: URI): Promise { - return this.channel.call('getWorkspaceIdentifier', configPath); - } -} diff --git a/src/vs/workbench/browser/nodeless.main.ts b/src/vs/workbench/browser/nodeless.main.ts new file mode 100644 index 00000000000..20096e14059 --- /dev/null +++ b/src/vs/workbench/browser/nodeless.main.ts @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { mark } from 'vs/base/common/performance'; +import { domContentLoaded, addDisposableListener, EventType } from 'vs/base/browser/dom'; +import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { ILogService } from 'vs/platform/log/common/log'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { SimpleLogService } from 'vs/workbench/browser/nodeless.simpleservices'; +import { Workbench } from 'vs/workbench/browser/workbench'; + +class CodeRendererMain extends Disposable { + + private workbench: Workbench; + + open(): Promise { + const services = this.initServices(); + + return domContentLoaded().then(() => { + mark('willStartWorkbench'); + + // Create Workbench + this.workbench = new Workbench( + document.body, + services.serviceCollection, + services.logService + ); + + // Layout + this._register(addDisposableListener(window, EventType.RESIZE, () => this.workbench.layout())); + + // Workbench Lifecycle + this._register(this.workbench.onShutdown(() => this.dispose())); + + // Startup + this.workbench.startup(); + }); + } + + private initServices(): { serviceCollection: ServiceCollection, logService: ILogService } { + const serviceCollection = new ServiceCollection(); + + const logService = new SimpleLogService(); + serviceCollection.set(ILogService, logService); + + return { serviceCollection, logService }; + } +} + +export function main(): Promise { + const renderer = new CodeRendererMain(); + + return renderer.open(); +} diff --git a/src/vs/workbench/browser/nodeless.simpleservices.ts b/src/vs/workbench/browser/nodeless.simpleservices.ts new file mode 100644 index 00000000000..656520895a7 --- /dev/null +++ b/src/vs/workbench/browser/nodeless.simpleservices.ts @@ -0,0 +1,1786 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { URI } from 'vs/base/common/uri'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { ITextSnapshot, IFileStat, IContent, IFileService, IResourceEncodings, IResolveFileOptions, IResolveFileResult, IResolveContentOptions, IStreamContent, IUpdateContentOptions, snapshotToString, ICreateFileOptions } from 'vs/platform/files/common/files'; +import { ITextBufferFactory } from 'vs/editor/common/model'; +import { createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; +import { keys, ResourceMap } from 'vs/base/common/map'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { Event } from 'vs/base/common/event'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +// tslint:disable-next-line: import-patterns no-standalone-editor +import { SimpleConfigurationService as StandaloneEditorConfigurationService, SimpleDialogService as StandaloneEditorDialogService, StandaloneKeybindingService, SimpleResourcePropertiesService } from 'vs/editor/standalone/browser/simpleServices'; +import { IDialogService, IFileDialogService, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs'; +import { IDownloadService } from 'vs/platform/download/common/download'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IEnvironmentService, IExtensionHostDebugParams, IDebugParams } from 'vs/platform/environment/common/environment'; +import { IExtensionGalleryService, IQueryOptions, IGalleryExtension, InstallOperation, StatisticType, ITranslation, IGalleryExtensionVersion, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IPager } from 'vs/base/common/paging'; +import { IExtensionManifest, ExtensionType, ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { NullExtensionService, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { IURLHandler, IURLService } from 'vs/platform/url/common/url'; +import { IJSONEditingService, IJSONValue } from 'vs/workbench/services/configuration/common/jsonEditing'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; +import { ILogService, NullLogService, LogLevel } from 'vs/platform/log/common/log'; +import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar'; +import { IProductService } from 'vs/platform/product/common/product'; +import { IRemoteAuthorityResolverService, ResolvedAuthority } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { joinPath, isEqualOrParent, isEqual } from 'vs/base/common/resources'; +import { basename } from 'vs/base/common/path'; +import { ISearchService, ITextQueryProps, ISearchProgressItem, ISearchComplete, IFileQueryProps, SearchProviderType, ISearchResultProvider, ITextQuery, IFileMatch, QueryType, FileMatch, pathIncludedInQuery } from 'vs/workbench/services/search/common/search'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { coalesce } from 'vs/base/common/arrays'; +import { Schemas } from 'vs/base/common/network'; +import { editorMatchesToTextSearchResults, addContextToEditorMatches } from 'vs/workbench/services/search/common/searchHelpers'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { InMemoryStorageService, IStorageService } from 'vs/platform/storage/common/storage'; +import { ITextMateService, IGrammar as ITextMategrammar } from 'vs/workbench/services/textMate/common/textMateService'; +import { LanguageId } from 'vs/editor/common/modes'; +import { IUpdateService, State } from 'vs/platform/update/common/update'; +import { IWindowConfiguration, IPath, IPathsToWaitFor, IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IURIToOpen, IMessageBoxResult, IWindowsService } from 'vs/platform/windows/common/windows'; +import { IProcessEnvironment, isWindows } from 'vs/base/common/platform'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceFolderCreationData, isSingleFolderWorkspaceIdentifier, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { ExportData } from 'vs/base/common/performance'; +import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; +import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; +import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceContextService, Workspace, toWorkspaceFolders, IWorkspaceFolder, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; +import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +export const workspaceResource = URI.file(isWindows ? 'C:\\simpleWorkspace' : '/simpleWorkspace'); + +//#region Backup File + +export class SimpleBackupFileService implements IBackupFileService { + + _serviceBrand: any; + + private backups: Map = new Map(); + + hasBackups(): Promise { + return Promise.resolve(this.backups.size > 0); + } + + loadBackupResource(resource: URI): Promise { + const backupResource = this.toBackupResource(resource); + if (this.backups.has(backupResource.toString())) { + return Promise.resolve(backupResource); + } + + return Promise.resolve(undefined); + } + + backupResource(resource: URI, content: ITextSnapshot, versionId?: number): Promise { + const backupResource = this.toBackupResource(resource); + this.backups.set(backupResource.toString(), content); + + return Promise.resolve(); + } + + resolveBackupContent(backupResource: URI): Promise { + const snapshot = this.backups.get(backupResource.toString()); + if (snapshot) { + return Promise.resolve(createTextBufferFactoryFromSnapshot(snapshot)); + } + + return Promise.resolve(undefined); + } + + getWorkspaceFileBackups(): Promise { + return Promise.resolve(keys(this.backups).map(key => URI.parse(key))); + } + + discardResourceBackup(resource: URI): Promise { + this.backups.delete(this.toBackupResource(resource).toString()); + + return Promise.resolve(); + } + + discardAllWorkspaceBackups(): Promise { + this.backups.clear(); + + return Promise.resolve(); + } + + toBackupResource(resource: URI): URI { + return resource; + } +} + +registerSingleton(IBackupFileService, SimpleBackupFileService, true); + +//#endregion + +//#region Broadcast + +export const IBroadcastService = createDecorator('broadcastService'); + +export interface IBroadcast { + channel: string; + payload: any; +} + +export interface IBroadcastService { + _serviceBrand: any; + + onBroadcast: Event; + + broadcast(b: IBroadcast): void; +} + +export class SimpleBroadcastService implements IBroadcastService { + + _serviceBrand: any; + + readonly onBroadcast: Event = Event.None; + + broadcast(b: IBroadcast): void { } +} + +registerSingleton(IBroadcastService, SimpleBroadcastService, true); + +//#endregion + +//#region Clipboard + +export class SimpleClipboardService implements IClipboardService { + + _serviceBrand: any; + + writeText(text: string, type?: string): void { } + + readText(type?: string): string { + return undefined; + } + + readFindText(): string { + return undefined; + } + + writeFindText(text: string): void { } + + writeResources(resources: URI[]): void { } + + readResources(): URI[] { + return []; + } + + hasResources(): boolean { + return false; + } +} + +registerSingleton(IClipboardService, SimpleClipboardService, true); + +//#endregion + +//#region Configuration + +export class SimpleConfigurationService extends StandaloneEditorConfigurationService { } + +registerSingleton(IConfigurationService, SimpleConfigurationService); + +//#endregion + +//#region Dialog + +export class SimpleDialogService extends StandaloneEditorDialogService { } + +registerSingleton(IDialogService, SimpleDialogService, true); + +//#endregion + +//#region Download + +export class SimpleDownloadService implements IDownloadService { + + _serviceBrand: any; + + download(uri: URI, to?: string, cancellationToken?: CancellationToken): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(IDownloadService, SimpleDownloadService, true); + +//#endregion + +//#region Environment + +export class SimpleEnvironmentService implements IEnvironmentService { + untitledWorkspacesHome: URI; + extensionTestsLocationURI?: URI; + _serviceBrand: any; + args = { _: [] }; + execPath: string; + cliPath: string; + appRoot: string = '/nodeless/'; + userHome: string; + userDataPath: string; + appNameLong: string; + appQuality?: string; + appSettingsHome: string = '/nodeless/settings'; + appSettingsPath: string = '/nodeless/settings/settings.json'; + appKeybindingsPath: string = '/nodeless/settings/keybindings.json'; + settingsSearchBuildId?: number; + settingsSearchUrl?: string; + globalStorageHome: string; + workspaceStorageHome: string; + backupHome: string; + backupWorkspacesPath: string; + workspacesHome: string; + isExtensionDevelopment: boolean; + disableExtensions: boolean | string[]; + builtinExtensionsPath: string; + extensionsPath: string; + extensionDevelopmentLocationURI?: URI; + extensionTestsPath?: string; + debugExtensionHost: IExtensionHostDebugParams; + debugSearch: IDebugParams; + logExtensionHostCommunication: boolean; + isBuilt: boolean; + wait: boolean; + status: boolean; + log?: string; + logsPath: string; + verbose: boolean; + skipGettingStarted: boolean; + skipReleaseNotes: boolean; + skipAddToRecentlyOpened: boolean; + mainIPCHandle: string; + sharedIPCHandle: string; + nodeCachedDataDir?: string; + installSourcePath: string; + disableUpdates: boolean; + disableCrashReporter: boolean; + driverHandle?: string; + driverVerbose: boolean; +} + +registerSingleton(IEnvironmentService, SimpleEnvironmentService); + +//#endregion + +//#region Extension Gallery + +export class SimpleExtensionGalleryService implements IExtensionGalleryService { + + _serviceBrand: any; + + isEnabled(): boolean { + return false; + } + + query(options?: IQueryOptions): Promise> { + return Promise.resolve(undefined); + } + + download(extension: IGalleryExtension, operation: InstallOperation): Promise { + return Promise.resolve(undefined); + } + + reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise { + return Promise.resolve(undefined); + } + + getReadme(extension: IGalleryExtension, token: CancellationToken): Promise { + return Promise.resolve(undefined); + } + + getManifest(extension: IGalleryExtension, token: CancellationToken): Promise { + return Promise.resolve(undefined); + } + + getChangelog(extension: IGalleryExtension, token: CancellationToken): Promise { + return Promise.resolve(undefined); + } + + getCoreTranslation(extension: IGalleryExtension, languageId: string): Promise { + return Promise.resolve(undefined); + } + + getAllVersions(extension: IGalleryExtension, compatible: boolean): Promise { + return Promise.resolve(undefined); + } + + loadAllDependencies(dependencies: IExtensionIdentifier[], token: CancellationToken): Promise { + return Promise.resolve(undefined); + } + + getExtensionsReport(): Promise { + return Promise.resolve(undefined); + } + + getCompatibleExtension(extension: IGalleryExtension): Promise; + getCompatibleExtension(id: IExtensionIdentifier, version?: string): Promise; + getCompatibleExtension(id: any, version?: any) { + return Promise.resolve(undefined); + } +} + +registerSingleton(IExtensionGalleryService, SimpleExtensionGalleryService, true); + +//#endregion + +//#region Extension Management + +export class SimpleExtensionManagementService implements IExtensionManagementService { + + _serviceBrand: any; + + onInstallExtension = Event.None; + onDidInstallExtension = Event.None; + onUninstallExtension = Event.None; + onDidUninstallExtension = Event.None; + + zip(extension: ILocalExtension): Promise { + return Promise.resolve(undefined); + } + + unzip(zipLocation: URI, type: ExtensionType): Promise { + return Promise.resolve(undefined); + } + + install(vsix: URI): Promise { + return Promise.resolve(undefined); + } + + installFromGallery(extension: IGalleryExtension): Promise { + return Promise.resolve(undefined); + } + + uninstall(extension: ILocalExtension, force?: boolean): Promise { + return Promise.resolve(undefined); + } + + reinstallFromGallery(extension: ILocalExtension): Promise { + return Promise.resolve(undefined); + } + + getInstalled(type?: ExtensionType): Promise { + return Promise.resolve(undefined); + } + + getExtensionsReport(): Promise { + return Promise.resolve(undefined); + } + + updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(IExtensionManagementService, SimpleExtensionManagementService); + +//#endregion + +//#region Extensions + +export class SimpleExtensionService extends NullExtensionService { } + +registerSingleton(IExtensionService, SimpleExtensionService); + +//#endregion + +//#region Extension URL Handler + +export const IExtensionUrlHandler = createDecorator('inactiveExtensionUrlHandler'); + +export interface IExtensionUrlHandler { + readonly _serviceBrand: any; + registerExtensionHandler(extensionId: ExtensionIdentifier, handler: IURLHandler): void; + unregisterExtensionHandler(extensionId: ExtensionIdentifier): void; +} + +export class SimpleExtensionURLHandler implements IExtensionUrlHandler { + + _serviceBrand: any; + + registerExtensionHandler(extensionId: ExtensionIdentifier, handler: IURLHandler): void { + throw new Error('Method not implemented.'); + } + + unregisterExtensionHandler(extensionId: ExtensionIdentifier): void { + throw new Error('Method not implemented.'); + } +} + +registerSingleton(IExtensionUrlHandler, SimpleExtensionURLHandler, true); + +//#endregion + +//#region File Dialog + +export class SimpleFileDialogService implements IFileDialogService { + + _serviceBrand: any; + + defaultFilePath(schemeFilter?: string): URI { + throw new Error('Method not implemented.'); + } + + defaultFolderPath(schemeFilter?: string): URI { + throw new Error('Method not implemented.'); + } + + defaultWorkspacePath(schemeFilter?: string): URI { + throw new Error('Method not implemented.'); + } + + pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { + throw new Error('Method not implemented.'); + } + + pickFileAndOpen(options: IPickAndOpenOptions): Promise { + throw new Error('Method not implemented.'); + } + + pickFolderAndOpen(options: IPickAndOpenOptions): Promise { + throw new Error('Method not implemented.'); + } + + pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { + throw new Error('Method not implemented.'); + } + + showSaveDialog(options: ISaveDialogOptions): Promise { + throw new Error('Method not implemented.'); + } + + showOpenDialog(options: IOpenDialogOptions): Promise { + throw new Error('Method not implemented.'); + } +} + +registerSingleton(IFileDialogService, SimpleFileDialogService, true); + +//#endregion + +//#region JSON Editing + +export class SimpleJSONEditingService implements IJSONEditingService { + + _serviceBrand: any; + + write(resource: URI, value: IJSONValue, save: boolean): Promise { + return Promise.resolve(); + } +} + +registerSingleton(IJSONEditingService, SimpleJSONEditingService, true); + +//#endregion + +//#region Keybinding + +export class SimpleKeybindingService extends StandaloneKeybindingService { + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @ICommandService commandService: ICommandService, + @ITelemetryService telemetryService: ITelemetryService, + @INotificationService notificationService: INotificationService, + ) { + super(contextKeyService, commandService, telemetryService, notificationService, window.document.body); + } +} + +registerSingleton(IKeybindingService, SimpleKeybindingService); + +//#endregion + +//#region Lifecycle + +export class SimpleLifecycleService extends AbstractLifecycleService { + + _serviceBrand: any; + + constructor( + @ILogService readonly logService: ILogService + ) { + super(logService); + + this.registerListeners(); + } + + private registerListeners(): void { + window.onbeforeunload = () => this.beforeUnload(); + } + + private beforeUnload(): string { + + // Before Shutdown + this._onBeforeShutdown.fire({ + veto(value) { + if (value === true) { + console.warn(new Error('Preventing onBeforeUnload currently not supported')); + } else if (value instanceof Promise) { + console.warn(new Error('Long running onBeforeShutdown currently not supported')); + } + }, + reason: ShutdownReason.QUIT + }); + + // Will Shutdown + this._onWillShutdown.fire({ + join() { + console.warn(new Error('Long running onWillShutdown currently not supported')); + }, + reason: ShutdownReason.QUIT + }); + + return null; + } +} + +registerSingleton(ILifecycleService, SimpleLifecycleService); + +//#endregion + +//#region Log + +export class SimpleLogService extends NullLogService { } + +//#endregion + +//#region Menu Bar + +export class SimpleMenubarService implements IMenubarService { + + _serviceBrand: any; + + updateMenubar(windowId: number, menuData: IMenubarData): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(IMenubarService, SimpleMenubarService); + +//#endregion + +//#region Multi Extension Management + +export class SimpleMultiExtensionsManagementService implements IExtensionManagementService { + + _serviceBrand: any; + + onInstallExtension = Event.None; + onDidInstallExtension = Event.None; + onUninstallExtension = Event.None; + onDidUninstallExtension = Event.None; + + zip(extension: ILocalExtension): Promise { + return Promise.resolve(undefined); + } + + unzip(zipLocation: URI, type: ExtensionType): Promise { + return Promise.resolve(undefined); + } + + install(vsix: URI): Promise { + return Promise.resolve(undefined); + } + + installFromGallery(extension: IGalleryExtension): Promise { + return Promise.resolve(undefined); + } + + uninstall(extension: ILocalExtension, force?: boolean): Promise { + return Promise.resolve(undefined); + } + + reinstallFromGallery(extension: ILocalExtension): Promise { + return Promise.resolve(undefined); + } + + getInstalled(type?: ExtensionType): Promise { + return Promise.resolve(undefined); + } + + getExtensionsReport(): Promise { + return Promise.resolve(undefined); + } + + updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise { + return Promise.resolve(undefined); + } +} + +//#endregion + +//#region Product + +export class SimpleProductService implements IProductService { + + _serviceBrand: any; + + version?: string; + commit?: string; + + enableTelemetry: boolean = false; +} + +registerSingleton(IProductService, SimpleProductService, true); + +//#endregion + +//#region Remote Agent + +export const IRemoteAgentService = createDecorator('remoteAgentService'); + +export interface IRemoteAgentService { + _serviceBrand: any; + + getConnection(): object; +} + +export class SimpleRemoteAgentService implements IRemoteAgentService { + + _serviceBrand: any; + + getConnection(): object { + return undefined; + } +} + +registerSingleton(IRemoteAgentService, SimpleRemoteAgentService); + +//#endregion + +//#region Remote Authority Resolver + +export class SimpleRemoteAuthorityResolverService implements IRemoteAuthorityResolverService { + + _serviceBrand: any; + + resolveAuthority(authority: string): Promise { + return Promise.resolve(undefined); + } + + setResolvedAuthority(resolvedAuthority: ResolvedAuthority): void { } + + setResolvedAuthorityError(authority: string, err: any): void { } +} + +registerSingleton(IRemoteAuthorityResolverService, SimpleRemoteAuthorityResolverService, true); + +//#endregion + +//#region File Servie + +const fileMap: ResourceMap = new ResourceMap(); +const contentMap: ResourceMap = new ResourceMap(); +initFakeFileSystem(); + +export class SimpleRemoteFileService implements IFileService { + + _serviceBrand: any; + + encoding: IResourceEncodings; + + readonly onFileChanges = Event.None; + readonly onAfterOperation = Event.None; + readonly onDidChangeFileSystemProviderRegistrations = Event.None; + + resolveFile(resource: URI, options?: IResolveFileOptions): Promise { + return Promise.resolve(fileMap.get(resource)); + } + + resolveFiles(toResolve: { resource: URI, options?: IResolveFileOptions }[]): Promise { + return Promise.all(toResolve.map(resourceAndOption => this.resolveFile(resourceAndOption.resource, resourceAndOption.options))).then(stats => stats.map(stat => ({ stat, success: true }))); + } + + existsFile(resource: URI): Promise { + return Promise.resolve(fileMap.has(resource)); + } + + resolveContent(resource: URI, _options?: IResolveContentOptions): Promise { + return Promise.resolve(contentMap.get(resource)); + } + + resolveStreamContent(resource: URI, _options?: IResolveContentOptions): Promise { + return Promise.resolve(contentMap.get(resource)).then(content => { + return { + resource: content.resource, + value: { + on: (event: string, callback: Function): void => { + if (event === 'data') { + callback(content.value); + } + + if (event === 'end') { + callback(); + } + } + }, + etag: content.etag, + encoding: content.encoding, + mtime: content.mtime, + name: content.name + }; + }); + } + + updateContent(resource: URI, value: string | ITextSnapshot, _options?: IUpdateContentOptions): Promise { + return Promise.resolve(fileMap.get(resource)).then(file => { + const content = contentMap.get(resource); + + if (typeof value === 'string') { + content.value = value; + } else { + content.value = snapshotToString(value); + } + + return file; + }); + } + + moveFile(_source: URI, _target: URI, _overwrite?: boolean): Promise { return Promise.resolve(null!); } + + copyFile(_source: URI, _target: URI, _overwrite?: boolean): Promise { throw new Error('not implemented'); } + + createFile(_resource: URI, _content?: string, _options?: ICreateFileOptions): Promise { throw new Error('not implemented'); } + + readFolder(_resource: URI) { return Promise.resolve([]); } + + createFolder(_resource: URI): Promise { throw new Error('not implemented'); } + + registerProvider(_scheme: string, _provider) { return { dispose() { } }; } + + activateProvider(_scheme: string): Promise { return Promise.resolve(undefined); } + + canHandleResource(resource: URI): boolean { return resource.scheme === 'file'; } + + del(_resource: URI, _options?: { useTrash?: boolean, recursive?: boolean }): Promise { return Promise.resolve(); } + + watchFileChanges(_resource: URI): void { } + + unwatchFileChanges(_resource: URI): void { } + + getWriteEncoding(_resource: URI): string { return 'utf8'; } + + dispose(): void { } +} + +function initFakeFileSystem(): void { + + function createFile(parent: IFileStat, name: string, content: string): void { + const file: IFileStat = { + resource: joinPath(parent.resource, name), + etag: Date.now().toString(), + mtime: Date.now(), + isDirectory: false, + name + }; + + parent.children.push(file); + + fileMap.set(file.resource, file); + + contentMap.set(file.resource, { + resource: joinPath(parent.resource, name), + etag: Date.now().toString(), + mtime: Date.now(), + value: content, + encoding: 'utf8', + name + } as IContent); + } + + function createFolder(parent: IFileStat, name: string): IFileStat { + const folder: IFileStat = { + resource: joinPath(parent.resource, name), + etag: Date.now().toString(), + mtime: Date.now(), + isDirectory: true, + name, + children: [] + }; + + parent.children.push(folder); + + fileMap.set(folder.resource, folder); + + return folder; + } + + const root: IFileStat = { + resource: workspaceResource, + etag: Date.now().toString(), + mtime: Date.now(), + isDirectory: true, + name: basename(workspaceResource.fsPath), + children: [] + }; + + fileMap.set(root.resource, root); + + createFile(root, '.gitignore', `out +node_modules +.vscode-test/ +*.vsix +`); + createFile(root, '.vscodeignore', `.vscode/** +.vscode-test/** +out/test/** +src/** +.gitignore +vsc-extension-quickstart.md +**/tsconfig.json +**/tslint.json +**/*.map +**/*.ts`); + createFile(root, 'CHANGELOG.md', `# Change Log +All notable changes to the "test-ts" extension will be documented in this file. + +Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. + +## [Unreleased] +- Initial release`); + createFile(root, 'package.json', `{ + "name": "test-ts", + "displayName": "test-ts", + "description": "", + "version": "0.0.1", + "engines": { + "vscode": "^1.31.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [ + "onCommand:extension.helloWorld" + ], + "main": "./out/extension.js", + "contributes": { + "commands": [ + { + "command": "extension.helloWorld", + "title": "Hello World" + } + ] + }, + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -p ./", + "watch": "tsc -watch -p ./", + "postinstall": "node ./node_modules/vscode/bin/install", + "test": "npm run compile && node ./node_modules/vscode/bin/test" + }, + "devDependencies": { + "typescript": "^3.3.1", + "vscode": "^1.1.28", + "tslint": "^5.12.1", + "@types/node": "^8.10.25", + "@types/mocha": "^2.2.42" + } +} +`); + createFile(root, 'tsconfig.json', `{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "out", + "lib": [ + "es6" + ], + "sourceMap": true, + "rootDir": "src", + "strict": true /* enable all strict type-checking options */ + /* Additional Checks */ + // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + }, + "exclude": [ + "node_modules", + ".vscode-test" + ] +} +`); + createFile(root, 'tslint.json', `{ + "rules": { + "no-string-throw": true, + "no-unused-expression": true, + "no-duplicate-variable": true, + "curly": true, + "class-name": true, + "semicolon": [ + true, + "always" + ], + "triple-equals": true + }, + "defaultSeverity": "warning" +} +`); + + const src = createFolder(root, 'src'); + createFile(src, 'extension.ts', `// The module 'vscode' contains the VS Code extensibility API +// Import the module and reference it with the alias vscode in your code below +import * as vscode from 'vscode'; + +// this method is called when your extension is activated +// your extension is activated the very first time the command is executed +export function activate(context: vscode.ExtensionContext) { + + // Use the console to output diagnostic information (console.log) and errors (console.error) + // This line of code will only be executed once when your extension is activated + console.log('Congratulations, your extension "test-ts" is now active!'); + + // The command has been defined in the package.json file + // Now provide the implementation of the command with registerCommand + // The commandId parameter must match the command field in package.json + let disposable = vscode.commands.registerCommand('extension.helloWorld', () => { + // The code you place here will be executed every time your command is executed + + // Display a message box to the user + vscode.window.showInformationMessage('Hello World!'); + }); + + context.subscriptions.push(disposable); +} + +// this method is called when your extension is deactivated +export function deactivate() {} +`); + + const test = createFolder(src, 'test'); + + createFile(test, 'extension.test.ts', `// +// Note: This example test is leveraging the Mocha test framework. +// Please refer to their documentation on https://mochajs.org/ for help. +// + +// The module 'assert' provides assertion methods from node +import * as assert from 'assert'; + +// You can import and use all API from the 'vscode' module +// as well as import your extension to test it +// import * as vscode from 'vscode'; +// import * as myExtension from '../extension'; + +// Defines a Mocha test suite to group tests of similar kind together +suite("Extension Tests", function () { + + // Defines a Mocha unit test + test("Something 1", function() { + assert.equal(-1, [1, 2, 3].indexOf(5)); + assert.equal(-1, [1, 2, 3].indexOf(0)); + }); +});`); + + createFile(test, 'index.ts', `// +// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING +// +// This file is providing the test runner to use when running extension tests. +// By default the test runner in use is Mocha based. +// +// You can provide your own test runner if you want to override it by exporting +// a function run(testRoot: string, clb: (error:Error) => void) that the extension +// host can call to run the tests. The test runner is expected to use console.log +// to report the results back to the caller. When the tests are finished, return +// a possible error to the callback or null if none. + +import * as testRunner from 'vscode/lib/testrunner'; + +// You can directly control Mocha options by configuring the test runner below +// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options +// for more info +testRunner.configure({ + ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.) + useColors: true // colored output from test results +}); + +module.exports = testRunner;`); +} + +registerSingleton(IFileService, SimpleRemoteFileService); + +//#endregion + +//#region Request + +export const IRequestService = createDecorator('requestService2'); + +export interface IRequestService { + _serviceBrand: any; + + request(options, token: CancellationToken): Promise; +} + +export class SimpleRequestService implements IRequestService { + + _serviceBrand: any; + + request(options, token: CancellationToken): Promise { + return Promise.resolve(Object.create(null)); + } +} + +//#endregion + +//#region Search + +export class SimpleSearchService implements ISearchService { + + _serviceBrand: any; + + constructor( + @IModelService private modelService: IModelService, + @IEditorService private editorService: IEditorService, + @IUntitledEditorService private untitledEditorService: IUntitledEditorService + ) { + + } + + textSearch(query: ITextQueryProps, token?: CancellationToken, onProgress?: (result: ISearchProgressItem) => void): Promise { + // Get local results from dirty/untitled + const localResults = this.getLocalResults(query); + + if (onProgress) { + coalesce(localResults.values()).forEach(onProgress); + } + + return Promise.resolve(undefined); + } + + fileSearch(query: IFileQueryProps, token?: CancellationToken): Promise { + return Promise.resolve(undefined); + } + + clearCache(cacheKey: string): Promise { + return Promise.resolve(undefined); + } + + registerSearchResultProvider(scheme: string, type: SearchProviderType, provider: ISearchResultProvider): IDisposable { + return Disposable.None; + } + + private getLocalResults(query: ITextQuery): ResourceMap { + const localResults = new ResourceMap(); + + if (query.type === QueryType.Text) { + const models = this.modelService.getModels(); + models.forEach((model) => { + const resource = model.uri; + if (!resource) { + return; + } + + if (!this.editorService.isOpen({ resource })) { + return; + } + + // Support untitled files + if (resource.scheme === Schemas.untitled) { + if (!this.untitledEditorService.exists(resource)) { + return; + } + } + + // Don't support other resource schemes than files for now + // todo@remote + // why is that? we should search for resources from other + // schemes + else if (resource.scheme !== Schemas.file) { + return; + } + + if (!this.matches(resource, query)) { + return; // respect user filters + } + + // Use editor API to find matches + const matches = model.findMatches(query.contentPattern.pattern, false, query.contentPattern.isRegExp, query.contentPattern.isCaseSensitive, query.contentPattern.isWordMatch ? query.contentPattern.wordSeparators : null, false, query.maxResults); + if (matches.length) { + const fileMatch = new FileMatch(resource); + localResults.set(resource, fileMatch); + + const textSearchResults = editorMatchesToTextSearchResults(matches, model, query.previewOptions); + fileMatch.results = addContextToEditorMatches(textSearchResults, model, query); + } else { + localResults.set(resource, null); + } + }); + } + + return localResults; + } + + private matches(resource: URI, query: ITextQuery): boolean { + // includes + if (query.includePattern) { + if (resource.scheme !== Schemas.file) { + return false; // if we match on file patterns, we have to ignore non file resources + } + } + + return pathIncludedInQuery(query, resource.fsPath); + } +} + +registerSingleton(ISearchService, SimpleSearchService, true); + +//#endregion + +//#region Storage + +export class SimpleStorageService extends InMemoryStorageService { } + +registerSingleton(IStorageService, SimpleStorageService); + +//#endregion + +//#region Telemetry + +export class SimpleTelemetryService implements ITelemetryService { + + _serviceBrand: undefined; + + isOptedIn: true; + + publicLog(eventName: string, data?: ITelemetryData) { + return Promise.resolve(undefined); + } + + getTelemetryInfo(): Promise { + return Promise.resolve({ + instanceId: 'someValue.instanceId', + sessionId: 'someValue.sessionId', + machineId: 'someValue.machineId' + }); + } +} + +registerSingleton(ITelemetryService, SimpleTelemetryService); + +//#endregion + +//#region Textmate + +export class SimpleTextMateService implements ITextMateService { + + _serviceBrand: any; + + readonly onDidEncounterLanguage: Event = Event.None; + + createGrammar(modeId: string): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(ITextMateService, SimpleTextMateService, true); + +//#endregion + +//#region Text Resource Properties + +export class SimpleTextResourcePropertiesService extends SimpleResourcePropertiesService { } + +registerSingleton(ITextResourcePropertiesService, SimpleTextResourcePropertiesService); + +//#endregion + +//#region Update + +export class SimpleUpdateService implements IUpdateService { + + _serviceBrand: any; + + onStateChange = Event.None; + state: State; + + checkForUpdates(context: any): Promise { + return Promise.resolve(undefined); + } + + downloadUpdate(): Promise { + return Promise.resolve(undefined); + } + + applyUpdate(): Promise { + return Promise.resolve(undefined); + } + + quitAndInstall(): Promise { + return Promise.resolve(undefined); + } + + isLatestVersion(): Promise { + return Promise.resolve(true); + } +} + +registerSingleton(IUpdateService, SimpleUpdateService); + +//#endregion + +//#region URL + +export class SimpleURLService implements IURLService { + _serviceBrand: any; + + open(url: URI): Promise { + return Promise.resolve(false); + } + + registerHandler(handler: IURLHandler): IDisposable { + return Disposable.None; + } +} + +registerSingleton(IURLService, SimpleURLService); + +//#endregion + +//#region Window + +export class SimpleWindowConfiguration implements IWindowConfiguration { + _: any[]; + machineId: string; + windowId: number; + logLevel: LogLevel; + + mainPid: number; + + appRoot: string; + execPath: string; + isInitialStartup?: boolean; + + userEnv: IProcessEnvironment; + nodeCachedDataDir?: string; + + backupPath?: string; + + workspace?: IWorkspaceIdentifier; + folderUri?: ISingleFolderWorkspaceIdentifier; + + remoteAuthority?: string; + + zoomLevel?: number; + fullscreen?: boolean; + maximized?: boolean; + highContrast?: boolean; + frameless?: boolean; + accessibilitySupport?: boolean; + partsSplashPath?: string; + + perfStartTime?: number; + perfAppReady?: number; + perfWindowLoadTime?: number; + perfEntries: ExportData; + + filesToOpen?: IPath[]; + filesToCreate?: IPath[]; + filesToDiff?: IPath[]; + filesToWait?: IPathsToWaitFor; + termProgram?: string; +} + +export class SimpleWindowService implements IWindowService { + + _serviceBrand: any; + + readonly onDidChangeFocus: Event = Event.None; + readonly onDidChangeMaximize: Event = Event.None; + + hasFocus = true; + + private configuration: IWindowConfiguration = new SimpleWindowConfiguration(); + + isFocused(): Promise { + return Promise.resolve(false); + } + + isMaximized(): Promise { + return Promise.resolve(false); + } + + getConfiguration(): IWindowConfiguration { + return this.configuration; + } + + getCurrentWindowId(): number { + return 0; + } + + pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise { + return Promise.resolve(); + } + + pickFileAndOpen(_options: INativeOpenDialogOptions): Promise { + return Promise.resolve(); + } + + pickFolderAndOpen(_options: INativeOpenDialogOptions): Promise { + return Promise.resolve(); + } + + pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise { + return Promise.resolve(); + } + + reloadWindow(): Promise { + return Promise.resolve(); + } + + openDevTools(): Promise { + return Promise.resolve(); + } + + toggleDevTools(): Promise { + return Promise.resolve(); + } + + closeWorkspace(): Promise { + return Promise.resolve(); + } + + enterWorkspace(_path: URI): Promise { + return Promise.resolve(undefined); + } + + toggleFullScreen(): Promise { + return Promise.resolve(); + } + + setRepresentedFilename(_fileName: string): Promise { + return Promise.resolve(); + } + + getRecentlyOpened(): Promise { + return Promise.resolve({ + workspaces: [], + files: [] + }); + } + + focusWindow(): Promise { + return Promise.resolve(); + } + + maximizeWindow(): Promise { + return Promise.resolve(); + } + + unmaximizeWindow(): Promise { + return Promise.resolve(); + } + + minimizeWindow(): Promise { + return Promise.resolve(); + } + + openWindow(_uris: IURIToOpen[], _options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean, forceOpenWorkspaceAsFile?: boolean }): Promise { + return Promise.resolve(); + } + + closeWindow(): Promise { + return Promise.resolve(); + } + + setDocumentEdited(_flag: boolean): Promise { + return Promise.resolve(); + } + + onWindowTitleDoubleClick(): Promise { + return Promise.resolve(); + } + + show(): Promise { + return Promise.resolve(); + } + + showMessageBox(_options: Electron.MessageBoxOptions): Promise { + return Promise.resolve({ button: 0 }); + } + + showSaveDialog(_options: Electron.SaveDialogOptions): Promise { + throw new Error('not implemented'); + } + + showOpenDialog(_options: Electron.OpenDialogOptions): Promise { + throw new Error('not implemented'); + } + + updateTouchBar(_items: ISerializableCommandAction[][]): Promise { + return Promise.resolve(); + } + + resolveProxy(url: string): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(IWindowService, SimpleWindowService); + +//#endregion + +//#region Window + +export class SimpleWindowsService implements IWindowsService { + _serviceBrand: any; + + windowCount = 1; + + readonly onWindowOpen: Event = Event.None; + readonly onWindowFocus: Event = Event.None; + readonly onWindowBlur: Event = Event.None; + readonly onWindowMaximize: Event = Event.None; + readonly onWindowUnmaximize: Event = Event.None; + readonly onRecentlyOpenedChange: Event = Event.None; + + isFocused(_windowId: number): Promise { + return Promise.resolve(false); + } + + pickFileFolderAndOpen(_options: INativeOpenDialogOptions): Promise { + return Promise.resolve(); + } + + pickFileAndOpen(_options: INativeOpenDialogOptions): Promise { + return Promise.resolve(); + } + + pickFolderAndOpen(_options: INativeOpenDialogOptions): Promise { + return Promise.resolve(); + } + + pickWorkspaceAndOpen(_options: INativeOpenDialogOptions): Promise { + return Promise.resolve(); + } + + reloadWindow(_windowId: number): Promise { + return Promise.resolve(); + } + + openDevTools(_windowId: number): Promise { + return Promise.resolve(); + } + + toggleDevTools(_windowId: number): Promise { + return Promise.resolve(); + } + + closeWorkspace(_windowId: number): Promise { + return Promise.resolve(); + } + + enterWorkspace(_windowId: number, _path: URI): Promise { + return Promise.resolve(undefined); + } + + toggleFullScreen(_windowId: number): Promise { + return Promise.resolve(); + } + + setRepresentedFilename(_windowId: number, _fileName: string): Promise { + return Promise.resolve(); + } + + addRecentlyOpened(recents: IRecent[]): Promise { + return Promise.resolve(); + } + + removeFromRecentlyOpened(_paths: URI[]): Promise { + return Promise.resolve(); + } + + clearRecentlyOpened(): Promise { + return Promise.resolve(); + } + + getRecentlyOpened(_windowId: number): Promise { + return Promise.resolve({ + workspaces: [], + files: [] + }); + } + + focusWindow(_windowId: number): Promise { + return Promise.resolve(); + } + + closeWindow(_windowId: number): Promise { + return Promise.resolve(); + } + + isMaximized(_windowId: number): Promise { + return Promise.resolve(false); + } + + maximizeWindow(_windowId: number): Promise { + return Promise.resolve(); + } + + minimizeWindow(_windowId: number): Promise { + return Promise.resolve(); + } + + unmaximizeWindow(_windowId: number): Promise { + return Promise.resolve(); + } + + onWindowTitleDoubleClick(_windowId: number): Promise { + return Promise.resolve(); + } + + setDocumentEdited(_windowId: number, _flag: boolean): Promise { + return Promise.resolve(); + } + + quit(): Promise { + return Promise.resolve(); + } + + relaunch(_options: { addArgs?: string[], removeArgs?: string[] }): Promise { + return Promise.resolve(); + } + + whenSharedProcessReady(): Promise { + return Promise.resolve(); + } + + toggleSharedProcess(): Promise { + return Promise.resolve(); + } + + // Global methods + openWindow(_windowId: number, _uris: IURIToOpen[], _options?: { forceNewWindow?: boolean, forceReuseWindow?: boolean, forceOpenWorkspaceAsFile?: boolean }): Promise { + return Promise.resolve(); + } + + openNewWindow(): Promise { + return Promise.resolve(); + } + + showWindow(_windowId: number): Promise { + return Promise.resolve(); + } + + getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> { + throw new Error('not implemented'); + } + + getWindowCount(): Promise { + return Promise.resolve(this.windowCount); + } + + log(_severity: string, ..._messages: string[]): Promise { + return Promise.resolve(); + } + + showItemInFolder(_path: URI): Promise { + return Promise.resolve(); + } + + newWindowTab(): Promise { + return Promise.resolve(); + } + + showPreviousWindowTab(): Promise { + return Promise.resolve(); + } + + showNextWindowTab(): Promise { + return Promise.resolve(); + } + + moveWindowTabToNewWindow(): Promise { + return Promise.resolve(); + } + + mergeAllWindowTabs(): Promise { + return Promise.resolve(); + } + + toggleWindowTabsBar(): Promise { + return Promise.resolve(); + } + + updateTouchBar(_windowId: number, _items: ISerializableCommandAction[][]): Promise { + return Promise.resolve(); + } + + getActiveWindowId(): Promise { + return Promise.resolve(undefined); + } + + // This needs to be handled from browser process to prevent + // foreground ordering issues on Windows + openExternal(_url: string): Promise { + return Promise.resolve(true); + } + + // TODO: this is a bit backwards + startCrashReporter(_config: Electron.CrashReporterStartOptions): Promise { + return Promise.resolve(); + } + + showMessageBox(_windowId: number, _options: Electron.MessageBoxOptions): Promise { + throw new Error('not implemented'); + } + + showSaveDialog(_windowId: number, _options: Electron.SaveDialogOptions): Promise { + throw new Error('not implemented'); + } + + showOpenDialog(_windowId: number, _options: Electron.OpenDialogOptions): Promise { + throw new Error('not implemented'); + } + + openAboutDialog(): Promise { + return Promise.resolve(); + } + + resolveProxy(windowId: number, url: string): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(IWindowsService, SimpleWindowsService); + +//#endregion + +//#region Workspace Editing + +export class SimpleWorkspaceEditingService implements IWorkspaceEditingService { + + _serviceBrand: any; + + addFolders(folders: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): Promise { + return Promise.resolve(undefined); + } + + removeFolders(folders: URI[], donotNotifyError?: boolean): Promise { + return Promise.resolve(undefined); + } + + updateFolders(index: number, deleteCount?: number, foldersToAdd?: IWorkspaceFolderCreationData[], donotNotifyError?: boolean): Promise { + return Promise.resolve(undefined); + } + + enterWorkspace(path: URI): Promise { + return Promise.resolve(undefined); + } + + createAndEnterWorkspace(folders: IWorkspaceFolderCreationData[], path?: URI): Promise { + return Promise.resolve(undefined); + } + + saveAndEnterWorkspace(path: URI): Promise { + return Promise.resolve(undefined); + } + + copyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier): Promise { + return Promise.resolve(undefined); + } + + pickNewWorkspacePath(): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(IWorkspaceEditingService, SimpleWorkspaceEditingService, true); + +//#endregion + +//#region Workspace + +export class SimpleWorkspaceService implements IWorkspaceContextService { + _serviceBrand: any; + + private workspace: Workspace; + + readonly onDidChangeWorkspaceName = Event.None; + readonly onDidChangeWorkspaceFolders = Event.None; + readonly onDidChangeWorkbenchState = Event.None; + + constructor() { + this.workspace = new Workspace( + workspaceResource.toString(), + toWorkspaceFolders([{ path: workspaceResource.fsPath }]) + ); + } + + getFolders(): IWorkspaceFolder[] { + return this.workspace ? this.workspace.folders : []; + } + + getWorkbenchState(): WorkbenchState { + if (this.workspace.configuration) { + return WorkbenchState.WORKSPACE; + } + + if (this.workspace.folders.length) { + return WorkbenchState.FOLDER; + } + + return WorkbenchState.EMPTY; + } + + getCompleteWorkspace(): Promise { + return Promise.resolve(this.getWorkspace()); + } + + getWorkspace(): IWorkspace { + return this.workspace; + } + + getWorkspaceFolder(resource: URI): IWorkspaceFolder | null { + return this.workspace.getFolder(resource); + } + + isInsideWorkspace(resource: URI): boolean { + if (resource && this.workspace) { + return isEqualOrParent(resource, this.workspace.folders[0].uri); + } + + return false; + } + + isCurrentWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): boolean { + return isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && isEqual(this.workspace.folders[0].uri, workspaceIdentifier); + } +} + +registerSingleton(IWorkspaceContextService, SimpleWorkspaceService); + +//#endregion + +//#region Workspaces + +export class SimpleWorkspacesService implements IWorkspacesService { + + _serviceBrand: any; + + createUntitledWorkspace(folders?: IWorkspaceFolderCreationData[]): Promise { + return Promise.resolve(undefined); + } + + deleteUntitledWorkspace(workspace: IWorkspaceIdentifier): Promise { + return Promise.resolve(undefined); + } + + getWorkspaceIdentifier(workspacePath: URI): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(IWorkspacesService, SimpleWorkspacesService); + +//#endregion \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts index 4aa2e7e3f93..e06e38cde64 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsCenter.ts @@ -57,6 +57,7 @@ export class NotificationsCenter extends Themable { private registerListeners(): void { this._register(this.model.onDidNotificationChange(e => this.onDidNotificationChange(e))); + this._register(this.layoutService.onLayout(dimension => this.layout(dimension))); } get isVisible(): boolean { diff --git a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts index 37335d97545..8d8f6d5edd8 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsToasts.ts @@ -79,6 +79,9 @@ export class NotificationsToasts extends Themable { private registerListeners(): void { + // Layout + this._register(this.layoutService.onLayout(dimension => this.layout(dimension))); + // Delay some tasks until after we can show notifications this.onCanShowNotifications().then(() => { diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index ed88665fd55..1140bc96018 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -24,7 +24,6 @@ import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart'; import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart'; import { IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs/workbench/browser/actions'; import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel'; -import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet'; import { getServices } from 'vs/platform/instantiation/common/extensions'; import { Position, Parts, IWorkbenchLayoutService, ILayoutOptions } from 'vs/workbench/services/layout/browser/layoutService'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -61,6 +60,8 @@ import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; +import { coalesce } from 'vs/base/common/arrays'; +import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; export interface IWorkbenchOptions { hasInitialFilesToOpen: boolean; @@ -90,8 +91,6 @@ enum Storage { export class Workbench extends Disposable implements IWorkbenchLayoutService { - //#region workbench - _serviceBrand: ServiceIdentifier; private readonly _onShutdown = this._register(new Emitter()); @@ -100,47 +99,19 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { private readonly _onWillShutdown = this._register(new Emitter()); get onWillShutdown(): Event { return this._onWillShutdown.event; } - private previousErrorValue: string; - private previousErrorTime = 0; - - private workbench: HTMLElement; - - private restored: boolean; - private disposed: boolean; - - private instantiationService: IInstantiationService; - private contextService: IWorkspaceContextService; - private storageService: IStorageService; - private configurationService: IConfigurationService; - private environmentService: IEnvironmentService; - private logService: ILogService; - - private parts: Map = new Map(); + private workbench: HTMLElement = document.createElement('div'); constructor( - private parent: HTMLElement, - private options: IWorkbenchOptions, - private serviceCollection: ServiceCollection, - @IInstantiationService instantiationService: IInstantiationService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IStorageService storageService: IStorageService, - @IConfigurationService configurationService: IConfigurationService, - @IEnvironmentService environmentService: IEnvironmentService, - @ILogService logService: ILogService + private readonly parent: HTMLElement, + private readonly serviceCollection: ServiceCollection, + logService: ILogService ) { super(); - this.instantiationService = instantiationService; - this.contextService = contextService; - this.storageService = storageService; - this.configurationService = configurationService; - this.environmentService = environmentService; - this.logService = logService; - - this.registerErrorHandler(); + this.registerErrorHandler(logService); } - private registerErrorHandler(): void { + private registerErrorHandler(logService: ILogService): void { // Listen on unhandled rejection events window.addEventListener('unhandledrejection', (event: PromiseRejectionEvent) => { @@ -153,7 +124,7 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { }); // Install handler for unexpected errors - setUnexpectedErrorHandler(error => this.handleUnexpectedError(error)); + setUnexpectedErrorHandler(error => this.handleUnexpectedError(error, logService)); // Inform user about loading issues from the loader (self).require.config({ @@ -165,117 +136,107 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { }); } - private handleUnexpectedError(error: any): void { - const errorMsg = toErrorMessage(error, true); - if (!errorMsg) { + private previousUnexpectedError: { message: string, time: number } = { message: undefined, time: 0 }; + private handleUnexpectedError(error: any, logService: ILogService): void { + const message = toErrorMessage(error, true); + if (!message) { return; } const now = Date.now(); - if (errorMsg === this.previousErrorValue && now - this.previousErrorTime <= 1000) { + if (message === this.previousUnexpectedError.message && now - this.previousUnexpectedError.time <= 1000) { return; // Return if error message identical to previous and shorter than 1 second } - this.previousErrorTime = now; - this.previousErrorValue = errorMsg; + this.previousUnexpectedError.time = now; + this.previousUnexpectedError.message = message; // Log it - this.logService.error(errorMsg); + logService.error(message); } - startup(): void { + startup(): IInstantiationService { try { - this.doStartup().then(undefined, error => this.logService.error(toErrorMessage(error, true))); + + // Configure emitter leak warning threshold + setGlobalLeakWarningThreshold(175); + + // Setup Intl for comparers + setFileNameComparer(new IdleValue(() => { + const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); + return { + collator: collator, + collatorIsNumeric: collator.resolvedOptions().numeric + }; + })); + + // ARIA + setARIAContainer(document.body); + + // Services + const instantiationService = this.initServices(this.serviceCollection); + + instantiationService.invokeFunction(accessor => { + const lifecycleService = accessor.get(ILifecycleService); + const storageService = accessor.get(IStorageService); + const configurationService = accessor.get(IConfigurationService); + + // Layout + this.initLayout(accessor); + + // Registries + this.initRegistries(accessor); + + // Context Keys + this._register(instantiationService.createInstance(WorkbenchContextKeysHandler)); + + // Register Listeners + this.registerListeners(lifecycleService, storageService, configurationService); + + // Render Workbench + this.renderWorkbench(instantiationService, accessor.get(INotificationService) as NotificationService, storageService, configurationService); + + // Workbench Layout + this.createWorkbenchLayout(instantiationService); + + // Layout + this.layout(); + + // Restore + this.restoreWorkbench(accessor.get(IEditorService), accessor.get(IEditorGroupsService), accessor.get(IViewletService), accessor.get(IPanelService), accessor.get(ILogService), lifecycleService).then(undefined, error => onUnexpectedError(error)); + }); + + return instantiationService; } catch (error) { - this.logService.error(toErrorMessage(error, true)); + onUnexpectedError(error); throw error; // rethrow because this is a critical issue we cannot handle properly here } } - private doStartup(): Promise { - - // Configure emitter leak warning threshold - setGlobalLeakWarningThreshold(175); - - // Setup Intl for comparers - setFileNameComparer(new IdleValue(() => { - const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); - return { - collator: collator, - collatorIsNumeric: collator.resolvedOptions().numeric - }; - })); - - // ARIA - setARIAContainer(document.body); - - // Warm up font cache information before building up too many dom elements - restoreFontInfo(this.storageService); - readFontInfo(BareFontInfo.createFromRawSettings(this.configurationService.getValue('editor'), getZoomLevel())); - - // Create Workbench Container - this.createWorkbenchContainer(); - - // Services - this.initServices(this.serviceCollection); - - // Registries - this.startRegistries(); - - // Context Keys - this._register(this.instantiationService.createInstance(WorkbenchContextKeysHandler)); - - // Register Listeners - this.instantiationService.invokeFunction(accessor => { - this.registerListeners(accessor); - this.registerLayoutListeners(accessor); - }); - - // Layout State - this.instantiationService.invokeFunction(accessor => this.initLayoutState(accessor)); - - // Render Workbench - this.renderWorkbench(); - - // Workbench Layout - this.createWorkbenchLayout(); - - // Layout - this.layout(); - - // Restore - return this.instantiationService.invokeFunction(accessor => this.restoreWorkbench(accessor)); - } - - private createWorkbenchContainer(): void { - this.workbench = document.createElement('div'); - - const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac'; - - addClasses(this.workbench, 'monaco-workbench', platformClass); - addClasses(document.body, platformClass); // used by our fonts - } - - private initServices(serviceCollection: ServiceCollection): void { + private initServices(serviceCollection: ServiceCollection): IInstantiationService { // Layout Service serviceCollection.set(IWorkbenchLayoutService, this); + // + // NOTE: DO NOT ADD ANY OTHER SERVICE INTO THE COLLECTION HERE. + // INSTEAD, CONTRIBUTE IT VIA WORKBENCH.MAIN.TS + // + // All Contributed Services const contributedServices = getServices(); for (let contributedService of contributedServices) { serviceCollection.set(contributedService.id, contributedService.descriptor); } + const instantationServie = new InstantiationService(serviceCollection, true); + // Wrap up - this.instantiationService.invokeFunction(accessor => { - - // Signal to lifecycle that services are set + instantationServie.invokeFunction(accessor => { const lifecycleService = accessor.get(ILifecycleService); - lifecycleService.phase = LifecyclePhase.Ready; - // TODO@Sandeep TODO@Martin debt around cyclic dependencies + // TODO@Ben TODO@Sandeep TODO@Martin debt around cyclic dependencies const fileService = accessor.get(IFileService); const instantiationService = accessor.get(IInstantiationService); const configurationService = accessor.get(IConfigurationService) as any; @@ -292,21 +253,25 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { if (typeof themeService.acquireFileService === 'function') { themeService.acquireFileService(fileService); } + + // Signal to lifecycle that services are set + lifecycleService.phase = LifecyclePhase.Ready; }); + + return instantationServie; } - private startRegistries(): void { - this.instantiationService.invokeFunction(accessor => { - Registry.as(ActionBarExtensions.Actionbar).start(accessor); - Registry.as(WorkbenchExtensions.Workbench).start(accessor); - Registry.as(EditorExtensions.EditorInputFactories).start(accessor); - }); + private initRegistries(accessor: ServicesAccessor): void { + Registry.as(ActionBarExtensions.Actionbar).start(accessor); + Registry.as(WorkbenchExtensions.Workbench).start(accessor); + Registry.as(EditorExtensions.EditorInputFactories).start(accessor); } - private registerListeners(accessor: ServicesAccessor): void { - const lifecycleService = accessor.get(ILifecycleService); - const storageService = accessor.get(IStorageService); - const configurationService = accessor.get(IConfigurationService); + private registerListeners( + lifecycleService: ILifecycleService, + storageService: IStorageService, + configurationService: IConfigurationService + ): void { // Lifecycle this._register(lifecycleService.onWillShutdown(event => this._onWillShutdown.fire(event))); @@ -316,15 +281,15 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { })); // Storage - this._register(storageService.onWillSaveState(e => this.saveState(e))); + this._register(storageService.onWillSaveState(() => saveFontInfo(storageService))); // Configuration changes - this._register(configurationService.onDidChangeConfiguration(() => this.setFontAliasing())); + this._register(configurationService.onDidChangeConfiguration(() => this.setFontAliasing(configurationService))); } private fontAliasing: 'default' | 'antialiased' | 'none' | 'auto'; - private setFontAliasing() { - const aliasing = this.configurationService.getValue<'default' | 'antialiased' | 'none' | 'auto'>(Settings.FONT_ALIASING); + private setFontAliasing(configurationService: IConfigurationService) { + const aliasing = configurationService.getValue<'default' | 'antialiased' | 'none' | 'auto'>(Settings.FONT_ALIASING); if (this.fontAliasing === aliasing) { return; } @@ -341,100 +306,73 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { } } - private renderWorkbench(): void { - if (this.state.sideBar.hidden) { - addClass(this.workbench, 'nosidebar'); - } + private renderWorkbench(instantiationService: IInstantiationService, notificationService: NotificationService, storageService: IStorageService, configurationService: IConfigurationService): void { - if (this.state.panel.hidden) { - addClass(this.workbench, 'nopanel'); - } + // State specific classes + const platformClass = isWindows ? 'windows' : isLinux ? 'linux' : 'mac'; + const workbenchClasses = coalesce([ + 'monaco-workbench', + platformClass, + this.state.sideBar.hidden ? 'nosidebar' : undefined, + this.state.panel.hidden ? 'nopanel' : undefined, + this.state.statusBar.hidden ? 'nostatusbar' : undefined, + this.state.fullscreen ? 'fullscreen' : undefined + ]); - if (this.state.statusBar.hidden) { - addClass(this.workbench, 'nostatusbar'); - } - - if (this.state.fullscreen) { - addClass(this.workbench, 'fullscreen'); - } + addClasses(this.workbench, ...workbenchClasses); + addClasses(document.body, platformClass); // used by our fonts // Apply font aliasing - this.setFontAliasing(); + this.setFontAliasing(configurationService); + + // Warm up font cache information before building up too many dom elements + restoreFontInfo(storageService); + readFontInfo(BareFontInfo.createFromRawSettings(configurationService.getValue('editor'), getZoomLevel())); // Create Parts - this.createTitlebarPart(); - this.createActivityBarPart(); - this.createSidebarPart(); - this.createEditorPart(); - this.createPanelPart(); - this.createStatusbarPart(); + [ + { id: Parts.TITLEBAR_PART, role: 'contentinfo', classes: ['titlebar'] }, + { id: Parts.ACTIVITYBAR_PART, role: 'navigation', classes: ['activitybar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] }, + { id: Parts.SIDEBAR_PART, role: 'complementary', classes: ['sidebar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'] }, + { id: Parts.PANEL_PART, role: 'complementary', classes: ['panel', this.state.panel.position === Position.BOTTOM ? 'bottom' : 'right'] }, + { id: Parts.EDITOR_PART, role: 'main', classes: ['editor'], options: { restorePreviousState: this.state.editor.restoreEditors } }, + { id: Parts.STATUSBAR_PART, role: 'contentinfo', classes: ['statusbar'] } + ].forEach(({ id, role, classes, options }) => { + const partContainer = this.createPart(id, role, classes); + + if (!configurationService.getValue('workbench.useExperimentalGridLayout')) { + // TODO@Ben cleanup once moved to grid + // Insert all workbench parts at the beginning. Issue #52531 + // This is primarily for the title bar to allow overriding -webkit-app-region + this.workbench.insertBefore(partContainer, this.workbench.lastChild); + } + + this.parts.get(id).create(partContainer, options); + }); // Notification Handlers - this.instantiationService.invokeFunction(accessor => this.createNotificationsHandlers(accessor)); + this.createNotificationsHandlers(instantiationService, notificationService); // Add Workbench to DOM this.parent.appendChild(this.workbench); } - private createTitlebarPart(): void { - const titlebarContainer = this.createPart(Parts.TITLEBAR_PART, 'contentinfo', 'titlebar'); - - this.parts.get(Parts.TITLEBAR_PART).create(titlebarContainer); - } - - private createActivityBarPart(): void { - const activitybarPartContainer = this.createPart(Parts.ACTIVITYBAR_PART, 'navigation', 'activitybar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'); - - this.parts.get(Parts.ACTIVITYBAR_PART).create(activitybarPartContainer); - } - - private createSidebarPart(): void { - const sidebarPartContainer = this.createPart(Parts.SIDEBAR_PART, 'complementary', 'sidebar', this.state.sideBar.position === Position.LEFT ? 'left' : 'right'); - - this.parts.get(Parts.SIDEBAR_PART).create(sidebarPartContainer); - } - - private createPanelPart(): void { - const panelPartContainer = this.createPart(Parts.PANEL_PART, 'complementary', 'panel', this.state.panel.position === Position.BOTTOM ? 'bottom' : 'right'); - - this.parts.get(Parts.PANEL_PART).create(panelPartContainer); - } - - private createEditorPart(): void { - const editorContainer = this.createPart(Parts.EDITOR_PART, 'main', 'editor'); - - this.parts.get(Parts.EDITOR_PART).create(editorContainer, { restorePreviousState: !this.options.hasInitialFilesToOpen }); - } - - private createStatusbarPart(): void { - const statusbarContainer = this.createPart(Parts.STATUSBAR_PART, 'contentinfo', 'statusbar'); - - this.parts.get(Parts.STATUSBAR_PART).create(statusbarContainer); - } - - private createPart(id: string, role: string, ...classes: string[]): HTMLElement { + private createPart(id: string, role: string, classes: string[]): HTMLElement { const part = document.createElement('div'); addClasses(part, 'part', ...classes); part.id = id; part.setAttribute('role', role); - if (!this.configurationService.getValue('workbench.useExperimentalGridLayout')) { - // Insert all workbench parts at the beginning. Issue #52531 - // This is primarily for the title bar to allow overriding -webkit-app-region - this.workbench.insertBefore(part, this.workbench.lastChild); - } - return part; } - private createNotificationsHandlers(accessor: ServicesAccessor): void { - const notificationService = accessor.get(INotificationService) as NotificationService; + private createNotificationsHandlers(instantiationService: IInstantiationService, notificationService: NotificationService): void { // Instantiate Notification components - const notificationsCenter = this._register(this.instantiationService.createInstance(NotificationsCenter, this.workbench, notificationService.model)); - const notificationsToasts = this._register(this.instantiationService.createInstance(NotificationsToasts, this.workbench, notificationService.model)); - this._register(this.instantiationService.createInstance(NotificationsAlerts, notificationService.model)); - const notificationsStatus = this.instantiationService.createInstance(NotificationsStatus, notificationService.model); + const notificationsCenter = this._register(instantiationService.createInstance(NotificationsCenter, this.workbench, notificationService.model)); + const notificationsToasts = this._register(instantiationService.createInstance(NotificationsToasts, this.workbench, notificationService.model)); + this._register(instantiationService.createInstance(NotificationsAlerts, notificationService.model)); + const notificationsStatus = instantiationService.createInstance(NotificationsStatus, notificationService.model); // Visibility this._register(notificationsCenter.onDidChangeVisibility(() => { @@ -442,23 +380,18 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { notificationsToasts.update(notificationsCenter.isVisible); })); - // Layout - this._register(this.onLayout(dimension => { - notificationsCenter.layout(dimension); - notificationsToasts.layout(dimension); - })); - // Register Commands registerNotificationCommands(notificationsCenter, notificationsToasts); } - private restoreWorkbench(accessor: ServicesAccessor): Promise { - const editorService = accessor.get(IEditorService); - const editorGroupService = accessor.get(IEditorGroupsService); - const viewletService = accessor.get(IViewletService); - const panelService = accessor.get(IPanelService); - const logService = accessor.get(ILogService); - + private restoreWorkbench( + editorService: IEditorService, + editorGroupService: IEditorGroupsService, + viewletService: IViewletService, + panelService: IPanelService, + logService: ILogService, + lifecycleService: ILifecycleService + ): Promise { const restorePromises: Promise[] = []; // Restore editors @@ -514,52 +447,26 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { // Emit a warning after 10s if restore does not complete const restoreTimeoutHandle = setTimeout(() => logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.'), 10000); - let error: Error; return Promise.all(restorePromises) .then(() => clearTimeout(restoreTimeoutHandle)) - .catch(err => error = err) - .finally(() => this.instantiationService.invokeFunction(accessor => this.whenRestored(accessor, error))); + .catch(error => onUnexpectedError(error)) + .finally(() => { + // Set lifecycle phase to `Restored` + lifecycleService.phase = LifecyclePhase.Restored; + + // Set lifecycle phase to `Eventually` after a short delay and when idle (min 2.5sec, max 5sec) + setTimeout(() => { + this._register(runWhenIdle(() => { + lifecycleService.phase = LifecyclePhase.Eventually; + }, 2500)); + }, 2500); + + // Telemetry: startup metrics + mark('didStartWorkbench'); + }); } - private whenRestored(accessor: ServicesAccessor, error?: Error): void { - const lifecycleService = accessor.get(ILifecycleService); - - this.restored = true; - - // Set lifecycle phase to `Restored` - lifecycleService.phase = LifecyclePhase.Restored; - - // Set lifecycle phase to `Eventually` after a short delay and when - // idle (min 2.5sec, max 5sec) - setTimeout(() => { - this._register(runWhenIdle(() => { - lifecycleService.phase = LifecyclePhase.Eventually; - }, 2500)); - }, 2500); - - if (error) { - onUnexpectedError(error); - } - - // Telemetry: startup metrics - mark('didStartWorkbench'); - } - - private saveState(e: IWillSaveStateEvent): void { - - // Font info - saveFontInfo(this.storageService); - } - - dispose(): void { - super.dispose(); - - this.disposed = true; - } - - //#endregion - //#region ILayoutService private readonly _onTitleBarVisibilityChange: Emitter = this._register(new Emitter()); @@ -576,8 +483,12 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { get container(): HTMLElement { return this.workbench; } + private parts: Map = new Map(); + private workbenchGrid: Grid | WorkbenchLegacyLayout; + private disposed: boolean; + private titleBarPartView: View; private activityBarPartView: View; private sideBarPartView: View; @@ -585,11 +496,18 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { private editorPartView: View; private statusBarPartView: View; + private environmentService: IEnvironmentService; + private configurationService: IConfigurationService; + private lifecycleService: ILifecycleService; + private storageService: IStorageService; private windowService: IWindowService; private editorService: IEditorService; private editorGroupService: IEditorGroupsService; private panelService: IPanelService; + private titleService: ITitleService; private viewletService: IViewletService; + private contextService: IWorkspaceContextService; + private backupFileService: IBackupFileService; private readonly state = { fullscreen: false, @@ -614,6 +532,7 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { hidden: false, centered: false, restoreCentered: false, + restoreEditors: false, editorsToOpen: undefined as Promise | IResourceEditor[] }, @@ -640,41 +559,57 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { } }; - registerPart(part: Part): void { - this.parts.set(part.getId(), part); + private initLayout(accessor: ServicesAccessor) { + + // Services + this.environmentService = accessor.get(IEnvironmentService); + this.configurationService = accessor.get(IConfigurationService); + this.lifecycleService = accessor.get(ILifecycleService); + this.windowService = accessor.get(IWindowService); + this.contextService = accessor.get(IWorkspaceContextService); + this.storageService = accessor.get(IStorageService); + + // Parts + this.editorService = accessor.get(IEditorService); + this.editorGroupService = accessor.get(IEditorGroupsService); + this.panelService = accessor.get(IPanelService); + this.viewletService = accessor.get(IViewletService); + this.titleService = accessor.get(ITitleService); + accessor.get(IStatusbarService); // not used, but called to ensure instantiated + accessor.get(IActivityBarService); // not used, but called to ensure instantiated + + // Listeners + this.registerLayoutListeners(); + + // State + this.initLayoutState(accessor.get(ILifecycleService)); } - private registerLayoutListeners(accessor: ServicesAccessor): void { - const storageService = accessor.get(IStorageService); - const editorService = accessor.get(IEditorService); - const configurationService = accessor.get(IConfigurationService); - const editorGroupService = accessor.get(IEditorGroupsService); - const titleService = accessor.get(ITitleService); - const environmentService = accessor.get(IEnvironmentService); + private registerLayoutListeners(): void { // Storage - this._register(storageService.onWillSaveState(e => this.saveLayoutState(e))); + this._register(this.storageService.onWillSaveState(e => this.saveLayoutState(e))); // Restore editor if hidden and it changes - this._register(editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false))); - this._register(editorGroupService.onDidActivateGroup(() => this.setEditorHidden(false))); + this._register(this.editorService.onDidVisibleEditorsChange(() => this.setEditorHidden(false))); + this._register(this.editorGroupService.onDidActivateGroup(() => this.setEditorHidden(false))); // Configuration changes - this._register(configurationService.onDidChangeConfiguration(() => this.doUpdateLayoutConfiguration())); + this._register(this.configurationService.onDidChangeConfiguration(() => this.doUpdateLayoutConfiguration())); // Fullscreen changes this._register(onDidChangeFullscreen(() => this.onFullscreenChanged())); // Group changes - this._register(editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.state.editor.centered))); - this._register(editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.state.editor.centered))); + this._register(this.editorGroupService.onDidAddGroup(() => this.centerEditorLayout(this.state.editor.centered))); + this._register(this.editorGroupService.onDidRemoveGroup(() => this.centerEditorLayout(this.state.editor.centered))); // Prevent workbench from scrolling #55456 this._register(addDisposableListener(this.workbench, EventType.SCROLL, () => this.workbench.scrollTop = 0)); // Menubar visibility changes - if ((isWindows || isLinux) && getTitleBarStyle(configurationService, environmentService) === 'custom') { - this._register(titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible))); + if ((isWindows || isLinux) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { + this._register(this.titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible))); } } @@ -784,49 +719,32 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { } } - private initLayoutState(accessor: ServicesAccessor): void { - const configurationService = accessor.get(IConfigurationService); - const storageService = accessor.get(IStorageService); - const lifecycleService = accessor.get(ILifecycleService); - const contextService = accessor.get(IWorkspaceContextService); - const environmentService = accessor.get(IEnvironmentService); - - this.windowService = accessor.get(IWindowService); - - // Ensure all part services are created (TODO@ben revisit this requirement) - this.editorService = accessor.get(IEditorService); - this.editorGroupService = accessor.get(IEditorGroupsService); - this.panelService = accessor.get(IPanelService); - this.viewletService = accessor.get(IViewletService); - accessor.get(IStatusbarService); - accessor.get(ITitleService); - accessor.get(IActivityBarService); + private initLayoutState(lifecycleService: ILifecycleService): void { // Fullscreen this.state.fullscreen = isFullscreen(); // Menubar visibility - this.state.menuBar.visibility = configurationService.getValue(Settings.MENUBAR_VISIBLE); + this.state.menuBar.visibility = this.configurationService.getValue(Settings.MENUBAR_VISIBLE); // Activity bar visibility - this.state.activityBar.hidden = !configurationService.getValue(Settings.ACTIVITYBAR_VISIBLE); + this.state.activityBar.hidden = !this.configurationService.getValue(Settings.ACTIVITYBAR_VISIBLE); // Sidebar visibility - this.state.sideBar.hidden = storageService.getBoolean(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE, contextService.getWorkbenchState() === WorkbenchState.EMPTY); + this.state.sideBar.hidden = this.storageService.getBoolean(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE, this.contextService.getWorkbenchState() === WorkbenchState.EMPTY); // Sidebar position - this.state.sideBar.position = (configurationService.getValue(Settings.SIDEBAR_POSITION) === 'right') ? Position.RIGHT : Position.LEFT; + this.state.sideBar.position = (this.configurationService.getValue(Settings.SIDEBAR_POSITION) === 'right') ? Position.RIGHT : Position.LEFT; // Sidebar viewlet if (!this.state.sideBar.hidden) { - const viewletRegistry = Registry.as(ViewletExtensions.Viewlets); // Only restore last viewlet if window was reloaded or we are in development mode let viewletToRestore: string; - if (!environmentService.isBuilt || lifecycleService.startupKind === StartupKind.ReloadedWindow) { - viewletToRestore = storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, viewletRegistry.getDefaultViewletId()); + if (!this.environmentService.isBuilt || lifecycleService.startupKind === StartupKind.ReloadedWindow) { + viewletToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE, this.viewletService.getDefaultViewletId()); } else { - viewletToRestore = viewletRegistry.getDefaultViewletId(); + viewletToRestore = this.viewletService.getDefaultViewletId(); } if (viewletToRestore) { @@ -837,13 +755,13 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { } // Editor centered layout - this.state.editor.restoreCentered = storageService.getBoolean(Storage.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false); + this.state.editor.restoreCentered = this.storageService.getBoolean(Storage.CENTERED_LAYOUT_ENABLED, StorageScope.WORKSPACE, false); // Editors to open - this.state.editor.editorsToOpen = this.resolveEditorsToOpen(accessor); + this.state.editor.editorsToOpen = this.resolveEditorsToOpen(); // Panel visibility - this.state.panel.hidden = storageService.getBoolean(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE, true); + this.state.panel.hidden = this.storageService.getBoolean(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE, true); // Panel position this.updatePanelPosition(); @@ -852,7 +770,7 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { if (!this.state.panel.hidden) { const panelRegistry = Registry.as(PanelExtensions.Panels); - let panelToRestore = storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId()); + let panelToRestore = this.storageService.get(PanelPart.activePanelSettingsKey, StorageScope.WORKSPACE, panelRegistry.getDefaultPanelId()); if (!panelRegistry.hasPanel(panelToRestore)) { panelToRestore = panelRegistry.getDefaultPanelId(); // fallback to default if panel is unknown } @@ -865,21 +783,21 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { } // Statusbar visibility - this.state.statusBar.hidden = !configurationService.getValue(Settings.STATUSBAR_VISIBLE); + this.state.statusBar.hidden = !this.configurationService.getValue(Settings.STATUSBAR_VISIBLE); // Zen mode enablement - this.state.zenMode.restore = storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && configurationService.getValue(Settings.ZEN_MODE_RESTORE); + this.state.zenMode.restore = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE); } - private resolveEditorsToOpen(accessor: ServicesAccessor): Promise | IResourceEditor[] { - const configuration = accessor.get(IWindowService).getConfiguration(); - const configurationService = accessor.get(IConfigurationService); - const contextService = accessor.get(IWorkspaceContextService); - const editorGroupService = accessor.get(IEditorGroupsService); - const backupFileService = accessor.get(IBackupFileService); + private resolveEditorsToOpen(): Promise | IResourceEditor[] { + const configuration = this.windowService.getConfiguration(); + const hasInitialFilesToOpen = this.hasInitialFilesToOpen(); + + // Only restore editors if we are not instructed to open files initially + this.state.editor.restoreEditors = !hasInitialFilesToOpen; // Files to open, diff or create - if (this.options.hasInitialFilesToOpen) { + if (hasInitialFilesToOpen) { // Files to diff is exclusive const filesToDiff = this.toInputs(configuration.filesToDiff, false); @@ -900,13 +818,13 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { } // Empty workbench - else if (contextService.getWorkbenchState() === WorkbenchState.EMPTY && configurationService.inspect('workbench.startupEditor').value === 'newUntitledFile') { - const isEmpty = editorGroupService.count === 1 && editorGroupService.activeGroup.count === 0; + else if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && this.configurationService.inspect('workbench.startupEditor').value === 'newUntitledFile') { + const isEmpty = this.editorGroupService.count === 1 && this.editorGroupService.activeGroup.count === 0; if (!isEmpty) { return []; // do not open any empty untitled file if we restored editors from previous session } - return backupFileService.hasBackups().then(hasBackups => { + return this.backupFileService.hasBackups().then(hasBackups => { if (hasBackups) { return []; // do not open any empty untitled file if we have backups to restore } @@ -918,6 +836,15 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { return []; } + private hasInitialFilesToOpen(): boolean { + const configuration = this.windowService.getConfiguration(); + + return !!( + (configuration.filesToCreate && configuration.filesToCreate.length > 0) || + (configuration.filesToOpen && configuration.filesToOpen.length > 0) || + (configuration.filesToDiff && configuration.filesToDiff.length > 0)); + } + private toInputs(paths: IPath[] | undefined, isNew: boolean): Array { if (!paths || !paths.length) { return []; @@ -950,8 +877,12 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { this.state.panel.position = (panelPosition === 'right') ? Position.RIGHT : Position.BOTTOM; } + registerPart(part: Part): void { + this.parts.set(part.getId(), part); + } + isRestored(): boolean { - return this.restored; + return this.lifecycleService.phase >= LifecyclePhase.Restored; } hasFocus(part: Parts): boolean { @@ -1145,7 +1076,7 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { } } - private createWorkbenchLayout(): void { + private createWorkbenchLayout(instantiationService: IInstantiationService): void { const titleBar = this.parts.get(Parts.TITLEBAR_PART); const editorPart = this.parts.get(Parts.EDITOR_PART); const activityBar = this.parts.get(Parts.ACTIVITYBAR_PART); @@ -1167,7 +1098,7 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { this.workbench.prepend(this.workbenchGrid.element); } else { - this.workbenchGrid = this.instantiationService.createInstance( + this.workbenchGrid = instantiationService.createInstance( WorkbenchLegacyLayout, this.parent, this.workbench, @@ -1590,5 +1521,11 @@ export class Workbench extends Disposable implements IWorkbenchLayoutService { } } + dispose(): void { + super.dispose(); + + this.disposed = true; + } + //#endregion } diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index f400b092c73..61fa611b160 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -33,11 +33,11 @@ import { IWindowService } from 'vs/platform/windows/common/windows'; import { URLService } from 'vs/platform/url/common/urlService'; import { URI } from 'vs/base/common/uri'; import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; -import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService'; +import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { ExtensionIdentifier, IExtensionContributions, ExtensionType } from 'vs/platform/extensions/common/extensions'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; suite('ExtensionsActions Test', () => { diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts index 5775cdded2a..245fc390378 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsTipsService.test.ts @@ -48,7 +48,7 @@ import { IExperimentService } from 'vs/workbench/contrib/experiments/node/experi import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; const mockExtensionGallery: IGalleryExtension[] = [ aGalleryExtension('MockExtension1', { diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index 98546f36e97..a00cc90eebf 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -37,9 +37,9 @@ import { SinonStub } from 'sinon'; import { IExperimentService, ExperimentService, ExperimentState, ExperimentActionType } from 'vs/workbench/contrib/experiments/node/experimentService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; -import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService'; +import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; import { ExtensionIdentifier, ExtensionType } from 'vs/platform/extensions/common/extensions'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; suite('ExtensionsListView Tests', () => { diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 9fc9cfbb567..bd310e41d61 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -37,10 +37,10 @@ import { URLService } from 'vs/platform/url/common/urlService'; import { URI } from 'vs/base/common/uri'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; -import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/node/extensionManagementServerService'; +import { ExtensionManagementServerService } from 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; suite('ExtensionsWorkbenchServiceTest', () => { diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 99229a99bff..713fc06017c 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -7,7 +7,7 @@ import * as fs from 'fs'; import * as gracefulFs from 'graceful-fs'; import { createHash } from 'crypto'; import { importEntries, mark } from 'vs/base/common/performance'; -import { Workbench, IWorkbenchOptions } from 'vs/workbench/browser/workbench'; +import { Workbench } from 'vs/workbench/browser/workbench'; import { ElectronWindow } from 'vs/workbench/electron-browser/window'; import { setZoomLevel, setZoomFactor, setFullscreen } from 'vs/base/browser/browser'; import { domContentLoaded, addDisposableListener, EventType, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; @@ -20,27 +20,15 @@ import { ServiceCollection } from 'vs/platform/instantiation/common/serviceColle import { stat } from 'vs/base/node/pfs'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; -import { IWindowConfiguration, IWindowsService, IWindowService } from 'vs/platform/windows/common/windows'; +import { IWindowConfiguration, IWindowService } from 'vs/platform/windows/common/windows'; import { WindowService } from 'vs/platform/windows/electron-browser/windowService'; -import { WindowsChannelClient } from 'vs/platform/windows/node/windowsIpc'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { Client as ElectronIPCClient } from 'vs/base/parts/ipc/electron-browser/ipc.electron-browser'; import { webFrame } from 'electron'; -import { UpdateChannelClient } from 'vs/platform/update/node/updateIpc'; -import { IUpdateService } from 'vs/platform/update/common/update'; -import { URLHandlerChannel, URLServiceChannelClient } from 'vs/platform/url/node/urlIpc'; -import { IURLService } from 'vs/platform/url/common/url'; -import { WorkspacesChannelClient } from 'vs/platform/workspaces/node/workspacesIpc'; -import { IWorkspacesService, ISingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, IMultiFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { ISingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, IMultiFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ConsoleLogService, MultiplexLogService, ILogService } from 'vs/platform/log/common/log'; import { StorageService } from 'vs/platform/storage/node/storageService'; -import { IssueChannelClient } from 'vs/platform/issue/node/issueIpc'; -import { IIssueService } from 'vs/platform/issue/common/issue'; import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc'; -import { RelayURLService } from 'vs/platform/url/common/urlService'; -import { MenubarChannelClient } from 'vs/platform/menubar/node/menubarIpc'; -import { IMenubarService } from 'vs/platform/menubar/common/menubar'; import { Schemas } from 'vs/base/common/network'; import { sanitizeFilePath } from 'vs/base/node/extfs'; import { basename } from 'vs/base/common/path'; @@ -48,9 +36,9 @@ import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/sto import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IStorageService } from 'vs/platform/storage/common/storage'; -import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { Disposable } from 'vs/base/common/lifecycle'; import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver'; +import { IMainProcessService, MainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; class CodeRendererMain extends Disposable { @@ -102,47 +90,31 @@ class CodeRendererMain extends Disposable { }); } - private hasInitialFilesToOpen(): boolean { - return !!( - (this.configuration.filesToCreate && this.configuration.filesToCreate.length > 0) || - (this.configuration.filesToOpen && this.configuration.filesToOpen.length > 0) || - (this.configuration.filesToDiff && this.configuration.filesToDiff.length > 0)); - } - open(): Promise { - const electronMainClient = this._register(new ElectronIPCClient(`window:${this.configuration.windowId}`)); - - return this.initServices(electronMainClient).then(services => { + return this.initServices().then(services => { return domContentLoaded().then(() => { mark('willStartWorkbench'); - const instantiationService = new InstantiationService(services, true); - // Create Workbench - this.workbench = instantiationService.createInstance( - Workbench, - document.body, - { hasInitialFilesToOpen: this.hasInitialFilesToOpen() } as IWorkbenchOptions, - services - ); + this.workbench = new Workbench(document.body, services.serviceCollection, services.logService); // Layout this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true))); // Workbench Lifecycle this._register(this.workbench.onShutdown(() => this.dispose())); - this._register(this.workbench.onWillShutdown(event => event.join((services.get(IStorageService) as StorageService).close()))); + this._register(this.workbench.onWillShutdown(event => event.join(services.storageService.close()))); // Startup - this.workbench.startup(); + const instantiationService = this.workbench.startup(); // Window this._register(instantiationService.createInstance(ElectronWindow)); // Driver if (this.configuration.driver) { - registerWindowDriver(electronMainClient, this.configuration.windowId, instantiationService).then(disposable => this._register(disposable)); + instantiationService.invokeFunction(accessor => registerWindowDriver(accessor).then(disposable => this._register(disposable))); } // Config Exporter @@ -151,12 +123,12 @@ class CodeRendererMain extends Disposable { } // Logging - instantiationService.invokeFunction(accessor => accessor.get(ILogService).trace('workbench configuration', JSON.stringify(this.configuration))); + services.logService.trace('workbench configuration', JSON.stringify(this.configuration)); }); }); } - private onWindowResize(e: any, retry: boolean): void { + private onWindowResize(e: Event, retry: boolean): void { if (e.target === window) { if (window.document && window.document.body && window.document.body.clientWidth === 0) { // TODO@Ben this is an electron issue on macOS when simple fullscreen is enabled @@ -174,68 +146,44 @@ class CodeRendererMain extends Disposable { } } - private initServices(electronMainClient: ElectronIPCClient): Promise { + private initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: StorageService }> { const serviceCollection = new ServiceCollection(); - // Windows Service - const windowsChannel = electronMainClient.getChannel('windows'); - serviceCollection.set(IWindowsService, new WindowsChannelClient(windowsChannel)); + // Main Process + const mainProcessService = this._register(new MainProcessService(this.configuration.windowId)); + serviceCollection.set(IMainProcessService, mainProcessService); // Window serviceCollection.set(IWindowService, new SyncDescriptor(WindowService, [this.configuration])); - // Update Service - const updateChannel = electronMainClient.getChannel('update'); - serviceCollection.set(IUpdateService, new SyncDescriptor(UpdateChannelClient, [updateChannel])); - - // URL Service - const urlChannel = electronMainClient.getChannel('url'); - const mainUrlService = new URLServiceChannelClient(urlChannel); - const urlService = new RelayURLService(mainUrlService); - serviceCollection.set(IURLService, urlService); - - // URLHandler Service - const urlHandlerChannel = new URLHandlerChannel(urlService); - electronMainClient.registerChannel('urlHandler', urlHandlerChannel); - - // Issue Service - const issueChannel = electronMainClient.getChannel('issue'); - serviceCollection.set(IIssueService, new SyncDescriptor(IssueChannelClient, [issueChannel])); - - // Menubar Service - const menubarChannel = electronMainClient.getChannel('menubar'); - serviceCollection.set(IMenubarService, new SyncDescriptor(MenubarChannelClient, [menubarChannel])); - - // Workspaces Service - const workspacesChannel = electronMainClient.getChannel('workspaces'); - serviceCollection.set(IWorkspacesService, new WorkspacesChannelClient(workspacesChannel)); - // Environment const environmentService = new EnvironmentService(this.configuration, this.configuration.execPath); serviceCollection.set(IEnvironmentService, environmentService); // Log - const logService = this._register(this.createLogService(electronMainClient, environmentService)); + const logService = this._register(this.createLogService(mainProcessService, environmentService)); serviceCollection.set(ILogService, logService); - // Resolve a workspace payload that we can get the workspace ID from - return this.resolveWorkspaceInitializationPayload(environmentService).then(payload => { + return this.resolveWorkspaceInitializationPayload(environmentService).then(payload => Promise.all([ + this.createWorkspaceService(payload, environmentService, logService).then(service => { - return Promise.all([ + // Workspace + serviceCollection.set(IWorkspaceContextService, service); - // Create and initialize workspace/configuration service - this.createWorkspaceService(payload, environmentService, logService), + // Configuration + serviceCollection.set(IConfigurationService, service); - // Create and initialize storage service - this.createStorageService(payload, environmentService, logService, electronMainClient) - ]).then(services => { - serviceCollection.set(IWorkspaceContextService, services[0]); - serviceCollection.set(IConfigurationService, services[0]); - serviceCollection.set(IStorageService, services[1]); + return service; + }), - return serviceCollection; - }); - }); + this.createStorageService(payload, environmentService, logService, mainProcessService).then(service => { + + // Storage + serviceCollection.set(IStorageService, service); + + return service; + }) + ]).then(services => ({ serviceCollection, logService, storageService: services[1] }))); } private resolveWorkspaceInitializationPayload(environmentService: EnvironmentService): Promise { @@ -319,8 +267,8 @@ class CodeRendererMain extends Disposable { }); } - private createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, logService: ILogService, electronMainClient: ElectronIPCClient): Promise { - const globalStorageDatabase = new GlobalStorageDatabaseChannelClient(electronMainClient.getChannel('storage')); + private createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IEnvironmentService, logService: ILogService, mainProcessService: IMainProcessService): Promise { + const globalStorageDatabase = new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')); const storageService = new StorageService(globalStorageDatabase, logService, environmentService); return storageService.initialize(payload).then(() => storageService, error => { @@ -331,11 +279,11 @@ class CodeRendererMain extends Disposable { }); } - private createLogService(electronMainClient: ElectronIPCClient, environmentService: IEnvironmentService): ILogService { + private createLogService(mainProcessService: IMainProcessService, environmentService: IEnvironmentService): ILogService { const spdlogService = createSpdLogService(`renderer${this.configuration.windowId}`, this.configuration.logLevel, environmentService.logsPath); const consoleLogService = new ConsoleLogService(this.configuration.logLevel); const logService = new MultiplexLogService([consoleLogService, spdlogService]); - const logLevelClient = new LogLevelSetterChannelClient(electronMainClient.getChannel('loglevel')); + const logLevelClient = new LogLevelSetterChannelClient(mainProcessService.getChannel('loglevel')); return new FollowerLogService(logLevelClient, logService); } diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 0ca278cc10b..1d808a3caec 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -22,7 +22,7 @@ import * as browser from 'vs/base/browser/browser'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; -import { ipcRenderer as ipc, webFrame, crashReporter } from 'electron'; +import { ipcRenderer as ipc, webFrame, crashReporter, Event } from 'electron'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -57,8 +57,6 @@ const TextInputActions: IAction[] = [ export class ElectronWindow extends Disposable { - private static readonly closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty'; - private touchBarMenu?: IMenu; private touchBarUpdater: RunOnceScheduler; private touchBarDisposables: IDisposable[]; @@ -116,7 +114,7 @@ export class ElectronWindow extends Disposable { }); // Support runAction event - ipc.on('vscode:runAction', (event: any, request: IRunActionInWindowRequest) => { + ipc.on('vscode:runAction', (event: Event, request: IRunActionInWindowRequest) => { const args: any[] = request.args || []; // If we run an action from the touchbar, we fill in the currently active resource @@ -147,29 +145,27 @@ export class ElectronWindow extends Disposable { }); // Support runKeybinding event - ipc.on('vscode:runKeybinding', (event: any, request: IRunKeybindingInWindowRequest) => { + ipc.on('vscode:runKeybinding', (event: Event, request: IRunKeybindingInWindowRequest) => { if (document.activeElement) { this.keybindingService.dispatchByUserSettingsLabel(request.userSettingsLabel, document.activeElement); } }); // Error reporting from main - ipc.on('vscode:reportError', (event: any, error: string) => { + ipc.on('vscode:reportError', (event: Event, error: string) => { if (error) { - const errorParsed = JSON.parse(error); - errorParsed.mainProcess = true; - errors.onUnexpectedError(errorParsed); + errors.onUnexpectedError(JSON.parse(error)); } }); // Support openFiles event for existing and new files - ipc.on('vscode:openFiles', (event: any, request: IOpenFileRequest) => this.onOpenFiles(request)); + ipc.on('vscode:openFiles', (event: Event, request: IOpenFileRequest) => this.onOpenFiles(request)); // Support addFolders event if we have a workspace opened - ipc.on('vscode:addFolders', (event: any, request: IAddFoldersRequest) => this.onAddFoldersRequest(request)); + ipc.on('vscode:addFolders', (event: Event, request: IAddFoldersRequest) => this.onAddFoldersRequest(request)); // Message support - ipc.on('vscode:showInfoMessage', (event: any, message: string) => { + ipc.on('vscode:showInfoMessage', (event: Event, message: string) => { this.notificationService.info(message); }); @@ -211,7 +207,7 @@ export class ElectronWindow extends Disposable { }); // keyboard layout changed event - ipc.on('vscode:accessibilitySupportChanged', (event: any, accessibilitySupportEnabled: boolean) => { + ipc.on('vscode:accessibilitySupportChanged', (event: Event, accessibilitySupportEnabled: boolean) => { this.accessibilityService.setAccessibilitySupport(accessibilitySupportEnabled ? AccessibilitySupport.Enabled : AccessibilitySupport.Disabled); }); @@ -247,7 +243,7 @@ export class ElectronWindow extends Disposable { // or setting is disabled. Also enabled when running with --wait from the command line. const visibleEditors = this.editorService.visibleControls; if (visibleEditors.length === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) { - const closeWhenEmpty = this.configurationService.getValue(ElectronWindow.closeWhenEmptyConfigurationKey); + const closeWhenEmpty = this.configurationService.getValue('window.closeWhenEmpty'); if (closeWhenEmpty || this.environmentService.args.wait) { this.closeEmptyWindowScheduler.schedule(); } @@ -316,7 +312,7 @@ export class ElectronWindow extends Disposable { // Handle window.open() calls const $this = this; - (window).open = function (url: string, target: string, features: string, replace: boolean): any { + window.open = function (url: string, target: string, features: string, replace: boolean): Window | null { $this.windowsService.openExternal(url); return null; diff --git a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index 08e5eab334a..2629d18f3e3 100644 --- a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -25,6 +25,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ContextMenuService as HTMLContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; export class ContextMenuService extends Disposable implements IContextMenuService { @@ -41,13 +42,14 @@ export class ContextMenuService extends Disposable implements IContextMenuServic @IConfigurationService configurationService: IConfigurationService, @IEnvironmentService environmentService: IEnvironmentService, @IContextViewService contextViewService: IContextViewService, - @IThemeService themeService: IThemeService + @IThemeService themeService: IThemeService, + @ILayoutService layoutService: ILayoutService ) { super(); // Custom context menu: Linux/Windows if custom title is enabled if (!isMacintosh && getTitleBarStyle(configurationService, environmentService) === 'custom') { - this.impl = new HTMLContextMenuService(null, telemetryService, notificationService, contextViewService, keybindingService, themeService); + this.impl = new HTMLContextMenuService(layoutService, telemetryService, notificationService, contextViewService, keybindingService, themeService); } // Native context menu: otherwise diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 5ea8fcd17fb..71c66bf9209 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -23,7 +23,7 @@ import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { DialogChannel } from 'vs/platform/dialogs/node/dialogIpc'; interface IMassagedMessageBoxOptions { diff --git a/src/vs/workbench/services/extensions/node/extensionManagementServerService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts similarity index 96% rename from src/vs/workbench/services/extensions/node/extensionManagementServerService.ts rename to src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts index 6bcf6a8075c..8b1011377b7 100644 --- a/src/vs/workbench/services/extensions/node/extensionManagementServerService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts @@ -11,7 +11,7 @@ import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagemen import { IRemoteAgentService } from 'vs/workbench/services/remote/node/remoteAgentService'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { IChannel } from 'vs/base/parts/ipc/node/ipc'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; const localExtensionManagementServerAuthority: string = 'vscode-local'; diff --git a/src/vs/workbench/services/hash/common/hashService.ts b/src/vs/workbench/services/hash/common/hashService.ts index 85a90230d33..304afc4e309 100644 --- a/src/vs/workbench/services/hash/common/hashService.ts +++ b/src/vs/workbench/services/hash/common/hashService.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { computeSHA1Hash } from 'vs/base/common/hash'; export const IHashService = createDecorator('hashService'); @@ -14,4 +16,15 @@ export interface IHashService { * Produce a SHA1 hash of the provided content. */ createSHA1(content: string): string; -} \ No newline at end of file +} + +export class HashService implements IHashService { + + _serviceBrand: any; + + createSHA1(content: string): string { + return computeSHA1Hash(content); + } +} + +registerSingleton(IHashService, HashService, true); \ No newline at end of file diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 3b11eb9b74d..15de1617f81 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -81,7 +81,7 @@ import { Part } from 'vs/workbench/browser/part'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IPanel } from 'vs/workbench/common/panel'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; -import { ISharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { return instantiationService.createInstance(FileEditorInput, resource, undefined); diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 00ec860a12b..e64a09824fa 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -22,7 +22,7 @@ import 'vs/workbench/electron-browser/main'; import 'vs/workbench/browser/actions/layoutActions'; import 'vs/workbench/browser/actions/listCommands'; import 'vs/workbench/browser/actions/navigationActions'; -import 'vs/workbench/browser/parts/quickopen/quickopenActions'; +import 'vs/workbench/browser/parts/quickopen/quickOpenActions'; import 'vs/workbench/browser/parts/quickinput/quickInputActions'; //#endregion @@ -72,12 +72,26 @@ import { RequestService } from 'vs/platform/request/electron-browser/requestServ import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -import { LocalizationsChannelClient } from 'vs/platform/localizations/node/localizationsIpc'; -import { ISharedProcessService, SharedProcessService } from 'vs/platform/sharedProcess/node/sharedProcessService'; +import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService'; +import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { TelemetryService } from 'vs/platform/telemetry/node/telemetryService'; +import { TelemetryService } from 'vs/platform/telemetry/electron-browser/telemetryService'; +import { IProductService } from 'vs/platform/product/common/product'; +import { ProductService } from 'vs/platform/product/node/productService'; +import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; +import { IUpdateService } from 'vs/platform/update/common/update'; +import { UpdateService } from 'vs/platform/update/electron-browser/updateService'; +import { IIssueService } from 'vs/platform/issue/common/issue'; +import { IssueService } from 'vs/platform/issue/electron-browser/issueService'; +import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { WorkspacesService } from 'vs/platform/workspaces/electron-browser/workspacesService'; +import { IMenubarService } from 'vs/platform/menubar/common/menubar'; +import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService'; +import { IURLService } from 'vs/platform/url/common/url'; +import { RelayURLService } from 'vs/platform/url/electron-browser/urlService'; import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; import 'vs/workbench/services/integrity/node/integrityService'; @@ -114,7 +128,7 @@ import 'vs/workbench/services/extensions/electron-browser/extensionService'; import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; import 'vs/workbench/services/extensionManagement/node/multiExtensionManagement'; import 'vs/workbench/services/label/common/labelService'; -import 'vs/workbench/services/extensions/node/extensionManagementServerService'; +import 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import 'vs/workbench/services/notification/common/notificationService'; @@ -135,11 +149,17 @@ registerSingleton(IContextViewService, ContextViewService, true); registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); registerSingleton(IRequestService, RequestService, true); registerSingleton(ILifecycleService, LifecycleService); -registerSingleton(ILocalizationsService, LocalizationsChannelClient); +registerSingleton(ILocalizationsService, LocalizationsService); registerSingleton(ISharedProcessService, SharedProcessService, true); registerSingleton(IRemoteAuthorityResolverService, RemoteAuthorityResolverService, true); registerSingleton(ITelemetryService, TelemetryService); registerSingleton(IProductService, ProductService, true); +registerSingleton(IWindowsService, WindowsService); +registerSingleton(IUpdateService, UpdateService); +registerSingleton(IIssueService, IssueService); +registerSingleton(IWorkspacesService, WorkspacesService); +registerSingleton(IMenubarService, MenubarService); +registerSingleton(IURLService, RelayURLService); //#endregion @@ -296,7 +316,5 @@ import 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution'; // Issues import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; -import { IProductService } from 'vs/platform/product/common/product'; -import { ProductService } from 'vs/platform/product/node/productService'; //#endregion diff --git a/src/vs/workbench/workbench.nodeless.main.css b/src/vs/workbench/workbench.nodeless.main.css new file mode 100644 index 00000000000..06ed8a197b2 --- /dev/null +++ b/src/vs/workbench/workbench.nodeless.main.css @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/* NOTE: THIS FILE WILL BE OVERWRITTEN DURING BUILD TIME, DO NOT EDIT */ + +div.monaco.main.css { +} \ No newline at end of file diff --git a/src/vs/workbench/workbench.nodeless.main.nls.js b/src/vs/workbench/workbench.nodeless.main.nls.js new file mode 100644 index 00000000000..d6a8b487eaf --- /dev/null +++ b/src/vs/workbench/workbench.nodeless.main.nls.js @@ -0,0 +1,8 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// NOTE: THIS FILE WILL BE OVERWRITTEN DURING BUILD TIME, DO NOT EDIT + +define([], {}); \ No newline at end of file diff --git a/src/vs/workbench/workbench.nodeless.main.ts b/src/vs/workbench/workbench.nodeless.main.ts new file mode 100644 index 00000000000..7b4f28c2a9f --- /dev/null +++ b/src/vs/workbench/workbench.nodeless.main.ts @@ -0,0 +1,325 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//#region --- workbench/editor core + +import 'vs/editor/editor.all'; + +// import 'vs/workbench/api/electron-browser/extensionHost.contribution'; + +// import 'vs/workbench/electron-browser/main.contribution'; +import 'vs/workbench/browser/workbench.contribution'; + +import 'vs/workbench/browser/nodeless.main'; + +//#endregion + + +//#region --- workbench actions + +import 'vs/workbench/browser/actions/layoutActions'; +import 'vs/workbench/browser/actions/listCommands'; +import 'vs/workbench/browser/actions/navigationActions'; +import 'vs/workbench/browser/parts/quickopen/quickOpenActions'; +import 'vs/workbench/browser/parts/quickinput/quickInputActions'; + +//#endregion + + +//#region --- API Extension Points + +import 'vs/workbench/api/common/menusExtensionPoint'; +import 'vs/workbench/api/common/configurationExtensionPoint'; +import 'vs/workbench/api/browser/viewsExtensionPoint'; + +//#endregion + + +//#region --- workbench services +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IMenuService } from 'vs/platform/actions/common/actions'; +import { MenuService } from 'vs/platform/actions/common/menuService'; +import { IListService, ListService } from 'vs/platform/list/browser/listService'; +import { OpenerService } from 'vs/editor/browser/services/openerService'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; +import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl'; +import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl'; +import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; +import { IMarkerService } from 'vs/platform/markers/common/markers'; +import { MarkerService } from 'vs/platform/markers/common/markerService'; +// import { IDownloadService } from 'vs/platform/download/common/download'; +// import { DownloadService } from 'vs/platform/download/node/downloadService'; +// import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +// import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; +import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; +import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionEnablementService'; +import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; +import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; +// import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +// import { IRequestService } from 'vs/platform/request/node/request'; +// import { RequestService } from 'vs/platform/request/electron-browser/requestService'; +// import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; +// import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +// import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +// import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService'; +// import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +// import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; +// import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; +// import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +// import { TelemetryService } from 'vs/platform/telemetry/electron-browser/telemetryService'; +// import { IProductService } from 'vs/platform/product/common/product'; +// import { ProductService } from 'vs/platform/product/node/productService'; +// import { IWindowsService } from 'vs/platform/windows/common/windows'; +// import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; +// import { IUpdateService } from 'vs/platform/update/common/update'; +// import { UpdateService } from 'vs/platform/update/electron-browser/updateService'; +// import { IIssueService } from 'vs/platform/issue/common/issue'; +// import { IssueService } from 'vs/platform/issue/electron-browser/issueService'; +// import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +// import { WorkspacesService } from 'vs/platform/workspaces/electron-browser/workspacesService'; +// import { IMenubarService } from 'vs/platform/menubar/common/menubar'; +// import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService'; +// import { IURLService } from 'vs/platform/url/common/url'; +// import { RelayURLService } from 'vs/platform/url/electron-browser/urlService'; + +import 'vs/workbench/browser/nodeless.simpleservices'; + +import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; +// import 'vs/workbench/services/integrity/node/integrityService'; +import 'vs/workbench/services/keybinding/common/keybindingEditing'; +import 'vs/workbench/services/hash/common/hashService'; +// import 'vs/workbench/services/textMate/electron-browser/textMateService'; +import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; +// import 'vs/workbench/services/workspace/node/workspaceEditingService'; +// import 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler'; +import 'vs/workbench/services/decorations/browser/decorationsService'; +// import 'vs/workbench/services/search/node/searchService'; +import 'vs/workbench/services/progress/browser/progressService2'; +import 'vs/workbench/services/editor/browser/codeEditorService'; +// import 'vs/workbench/services/broadcast/electron-browser/broadcastService'; +import 'vs/workbench/services/preferences/browser/preferencesService'; +// import 'vs/workbench/services/output/node/outputChannelModelService'; +// import 'vs/workbench/services/configuration/node/jsonEditingService'; +import 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; +import 'vs/workbench/services/textfile/common/textFileService'; +// import 'vs/workbench/services/dialogs/electron-browser/dialogService'; +// import 'vs/workbench/services/backup/node/backupFileService'; +import 'vs/workbench/services/editor/browser/editorService'; +import 'vs/workbench/services/history/browser/history'; +// import 'vs/workbench/services/files/node/remoteFileService'; +import 'vs/workbench/services/activity/browser/activityService'; +import 'vs/workbench/browser/parts/views/views'; +// import 'vs/workbench/services/keybinding/electron-browser/keybindingService'; +import 'vs/workbench/services/untitled/common/untitledEditorService'; +// import 'vs/workbench/services/textfile/node/textResourcePropertiesService'; +import 'vs/workbench/services/mode/common/workbenchModeService'; +import 'vs/workbench/services/commands/common/commandService'; +import 'vs/workbench/services/themes/browser/workbenchThemeService'; +// import 'vs/workbench/services/extensions/electron-browser/extensionService'; +// import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; +// import 'vs/workbench/services/extensionManagement/node/multiExtensionManagement'; +import 'vs/workbench/services/label/common/labelService'; +// import 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; +// import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; +import 'vs/workbench/services/notification/common/notificationService'; + +registerSingleton(IMenuService, MenuService, true); +registerSingleton(IListService, ListService, true); +registerSingleton(IOpenerService, OpenerService, true); +registerSingleton(IEditorWorkerService, EditorWorkerServiceImpl); +registerSingleton(IMarkerDecorationsService, MarkerDecorationsService); +registerSingleton(IMarkerService, MarkerService, true); +// registerSingleton(IDownloadService, DownloadService, true); +// registerSingleton(IClipboardService, ClipboardService, true); +registerSingleton(IContextKeyService, ContextKeyService); +registerSingleton(IModelService, ModelServiceImpl, true); +registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationService); +registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); +registerSingleton(IExtensionEnablementService, ExtensionEnablementService, true); +registerSingleton(IContextViewService, ContextViewService, true); +// registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); +// registerSingleton(IRequestService, RequestService, true); +// registerSingleton(ILifecycleService, LifecycleService); +// registerSingleton(ILocalizationsService, LocalizationsService); +// registerSingleton(ISharedProcessService, SharedProcessService, true); +// registerSingleton(IRemoteAuthorityResolverService, RemoteAuthorityResolverService, true); +// registerSingleton(ITelemetryService, TelemetryService); +// registerSingleton(IProductService, ProductService, true); +// registerSingleton(IWindowsService, WindowsService); +// registerSingleton(IUpdateService, UpdateService); +// registerSingleton(IIssueService, IssueService); +// registerSingleton(IWorkspacesService, WorkspacesService); +// registerSingleton(IMenubarService, MenubarService); +// registerSingleton(IURLService, RelayURLService); + +registerSingleton(IContextMenuService, ContextMenuService); + +//#endregion + +//#region --- workbench parts + +import 'vs/workbench/browser/parts/quickinput/quickInput'; +import 'vs/workbench/browser/parts/quickopen/quickOpenController'; +import 'vs/workbench/browser/parts/titlebar/titlebarPart'; +import 'vs/workbench/browser/parts/editor/editorPart'; +import 'vs/workbench/browser/parts/activitybar/activitybarPart'; +import 'vs/workbench/browser/parts/panel/panelPart'; +import 'vs/workbench/browser/parts/sidebar/sidebarPart'; +import 'vs/workbench/browser/parts/statusbar/statusbarPart'; + +//#endregion + +//#region --- workbench contributions + +// Telemetry +import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution'; + +// Localizations +// import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; + +// Preferences +// import 'vs/workbench/contrib/preferences/electron-browser/preferences.contribution'; +import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution'; + +// Logs +import 'vs/workbench/contrib/logs/common/logs.contribution'; + +// Quick Open Handlers +import 'vs/workbench/contrib/quickopen/browser/quickopen.contribution'; + +// Explorer +import 'vs/workbench/contrib/files/browser/explorerViewlet'; +import 'vs/workbench/contrib/files/browser/fileActions.contribution'; +import 'vs/workbench/contrib/files/browser/files.contribution'; + +// Backup +import 'vs/workbench/contrib/backup/common/backup.contribution'; + +// Stats +// import 'vs/workbench/contrib/stats/node/stats.contribution'; + +// Rapid Render Splash +// import 'vs/workbench/contrib/splash/electron-browser/partsSplash.contribution'; + +// Search +import 'vs/workbench/contrib/search/browser/search.contribution'; +import 'vs/workbench/contrib/search/browser/searchView'; +import 'vs/workbench/contrib/search/browser/openAnythingHandler'; + +// SCM +import 'vs/workbench/contrib/scm/browser/scm.contribution'; +import 'vs/workbench/contrib/scm/browser/scmViewlet'; + +// Debug +// import 'vs/workbench/contrib/debug/electron-browser/debug.contribution'; +// import 'vs/workbench/contrib/debug/browser/debugQuickOpen'; +// import 'vs/workbench/contrib/debug/electron-browser/repl'; +// import 'vs/workbench/contrib/debug/browser/debugViewlet'; + +// Markers +import 'vs/workbench/contrib/markers/browser/markers.contribution'; + +// Comments +// import 'vs/workbench/contrib/comments/electron-browser/comments.contribution'; + +// URL Support +import 'vs/workbench/contrib/url/common/url.contribution'; + +// Webview +// import 'vs/workbench/contrib/webview/electron-browser/webview.contribution'; + +// Extensions Management +// import 'vs/workbench/contrib/extensions/electron-browser/extensions.contribution'; +// import 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; +// import 'vs/workbench/contrib/extensions/electron-browser/extensionsViewlet'; + +// Output Panel +import 'vs/workbench/contrib/output/browser/output.contribution'; +import 'vs/workbench/contrib/output/browser/outputPanel'; + +// Terminal +// import 'vs/workbench/contrib/terminal/browser/terminal.contribution'; +// import 'vs/workbench/contrib/terminal/electron-browser/terminal.contribution'; +// import 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; +// import 'vs/workbench/contrib/terminal/browser/terminalPanel'; + +// Relauncher +// import 'vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution'; + +// Tasks +// import 'vs/workbench/contrib/tasks/electron-browser/task.contribution'; + +// Emmet +import 'vs/workbench/contrib/emmet/browser/emmet.contribution'; + +// CodeEditor Contributions +import 'vs/workbench/contrib/codeEditor/browser/codeEditor.contribution'; +// import 'vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution'; + +// Execution +// import 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution'; + +// Snippets +import 'vs/workbench/contrib/snippets/browser/snippets.contribution'; +import 'vs/workbench/contrib/snippets/browser/snippetsService'; +import 'vs/workbench/contrib/snippets/browser/insertSnippet'; +import 'vs/workbench/contrib/snippets/browser/configureSnippets'; +import 'vs/workbench/contrib/snippets/browser/tabCompletion'; + +// Formatter Help +import 'vs/workbench/contrib/format/browser/format.contribution'; + +// Send a Smile +// import 'vs/workbench/contrib/feedback/electron-browser/feedback.contribution'; + +// Update +// import 'vs/workbench/contrib/update/electron-browser/update.contribution'; + +// Surveys +// import 'vs/workbench/contrib/surveys/electron-browser/nps.contribution'; +// import 'vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution'; + +// Performance +// import 'vs/workbench/contrib/performance/electron-browser/performance.contribution'; + +// CLI +// import 'vs/workbench/contrib/cli/node/cli.contribution'; + +// Themes Support +import 'vs/workbench/contrib/themes/browser/themes.contribution'; +// import 'vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution'; + +// Watermark +import 'vs/workbench/contrib/watermark/browser/watermark'; + +// Welcome +import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; +// import 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution'; +import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; +import 'vs/workbench/contrib/welcome/page/browser/welcomePage.contribution'; + +// Outline +import 'vs/workbench/contrib/outline/browser/outline.contribution'; + +// Experiments +// import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; + +// Code Insets +// import 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution'; + +// Issues +// import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; + +//#endregion