diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 772f12ef04b1023395d750845e91c6bbc2341485..259482681a1eba7712bfc956add05ebaf8903f49 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -167,3 +167,41 @@ export function hasClipboardSupport() { return true; } + +//#region -- run on idle tricks ------------ + +export interface IdleDeadline { + readonly didTimeout: boolean; + timeRemaining(): DOMHighResTimeStamp; +} +/** + * Execute the callback the next time the browser is idle + */ +export let runWhenIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable; + +declare module self { + export function requestIdleCallback(callback: (args: IdleDeadline) => void, options?: { timeout: number }): number; + export function cancelIdleCallback(handle: number): void; +} +(function () { + if (typeof self === 'undefined' || !self.requestIdleCallback || !self.cancelIdleCallback) { + let warned = false; + runWhenIdle = (runner, timeout?) => { + if (!warned) { + console.warn('requestIdleCallback not available. using fallback'); + warned = true; + } + let handle = setTimeout(() => runner({ didTimeout: true, timeRemaining() { return Number.MAX_VALUE; } }), timeout); + return { dispose() { clearTimeout(handle); } }; + }; + } else { + runWhenIdle = (runner, timeout?) => { + let handle = self.requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined); + return { dispose() { self.cancelIdleCallback(handle); } }; + }; + } +})(); + + + +//#endregion diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 5cffb44856147d01f3a6ecde05937e06dff6bf30..f6a2fee985eeedd34eb360d1e726141de832b714 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -8,7 +8,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { ErrorCallback, TPromise, ValueCallback } from 'vs/base/common/winjs.base'; @@ -692,36 +692,3 @@ export function ninvoke(thisArg: any, fn: Function, ...args: any[]): TPromise export function ninvoke(thisArg: any, fn: Function, ...args: any[]): any { return new TPromise((c, e) => fn.call(thisArg, ...args, (err: any, result: any) => err ? e(err) : c(result))); } - - -export interface IdleDeadline { - readonly didTimeout: boolean; - timeRemaining(): DOMHighResTimeStamp; -} -/** - * Execute the callback the next time the browser is idle - */ -export let runWhenIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable; - -declare module self { - export function requestIdleCallback(callback: (args: IdleDeadline) => void, options?: { timeout: number }): number; - export function cancelIdleCallback(handle: number): void; -} -(function () { - if (typeof self === 'undefined' || !self.requestIdleCallback || !self.cancelIdleCallback) { - let warned = false; - runWhenIdle = (runner, timeout?) => { - if (!warned) { - console.warn('requestIdleCallback not available. using fallback'); - warned = true; - } - let handle = setTimeout(() => runner({ didTimeout: true, timeRemaining() { return Number.MAX_VALUE; } }), timeout); - return { dispose() { clearTimeout(handle); } }; - }; - } else { - runWhenIdle = (runner, timeout?) => { - let handle = self.requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined); - return { dispose() { self.cancelIdleCallback(handle); } }; - }; - } -})(); diff --git a/src/vs/workbench/browser/contributions.ts b/src/vs/workbench/browser/contributions.ts new file mode 100644 index 0000000000000000000000000000000000000000..4d810eb863e5ccd5bcd9bbb6f66342dba06d8bee --- /dev/null +++ b/src/vs/workbench/browser/contributions.ts @@ -0,0 +1,93 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import { Registry } from 'vs/platform/registry/common/platform'; +import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; +import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import { runWhenIdle, IdleDeadline } from 'vs/base/browser/browser'; +import { IWorkbenchContributionsRegistry, IWorkbenchContribution, IWorkbenchContributionSignature, Extensions } from 'vs/workbench/common/contributions'; + +class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry { + private instantiationService: IInstantiationService; + private lifecycleService: ILifecycleService; + + private toBeInstantiated: Map[]> = new Map[]>(); + + registerWorkbenchContribution(ctor: IWorkbenchContributionSignature, phase: LifecyclePhase = LifecyclePhase.Starting): void { + + // Instantiate directly if we are already matching the provided phase + if (this.instantiationService && this.lifecycleService && this.lifecycleService.phase >= phase) { + this.instantiationService.createInstance(ctor); + } + + // Otherwise keep contributions by lifecycle phase + else { + let toBeInstantiated = this.toBeInstantiated.get(phase); + if (!toBeInstantiated) { + toBeInstantiated = []; + this.toBeInstantiated.set(phase, toBeInstantiated); + } + + toBeInstantiated.push(ctor); + } + } + + start(instantiationService: IInstantiationService, lifecycleService: ILifecycleService): void { + this.instantiationService = instantiationService; + this.lifecycleService = lifecycleService; + + [LifecyclePhase.Starting, LifecyclePhase.Restoring, LifecyclePhase.Running, LifecyclePhase.Eventually].forEach(phase => { + this.instantiateByPhase(instantiationService, lifecycleService, phase); + }); + } + + private instantiateByPhase(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, phase: LifecyclePhase): void { + + // Instantiate contributions directly when phase is already reached + if (lifecycleService.phase >= phase) { + this.doInstantiateByPhase(instantiationService, phase); + } + + // Otherwise wait for phase to be reached + else { + lifecycleService.when(phase).then(() => { + this.doInstantiateByPhase(instantiationService, phase); + }); + } + } + + private doInstantiateByPhase(instantiationService: IInstantiationService, phase: LifecyclePhase): void { + const toBeInstantiated = this.toBeInstantiated.get(phase); + if (!toBeInstantiated) { + return; + } + if (phase !== LifecyclePhase.Eventually) { + // instantiate every synchronously and blocking + for (const ctor of toBeInstantiated) { + instantiationService.createInstance(ctor); + } + } else { + // for the Eventually-phase we instantiate contributions + // only when idle. this might take a few idle-busy-cycles + // but will finish within one second + let i = 0; + const instantiateSome = (idle: IdleDeadline) => { + while (i < toBeInstantiated.length) { + const ctor = toBeInstantiated[i++]; + instantiationService.createInstance(ctor); + if (idle.timeRemaining() < 1) { + // time is up -> reschedule + runWhenIdle(instantiateSome, 1000); + break; + } + } + }; + runWhenIdle(instantiateSome, 1000); + } + } +} + +Registry.add(Extensions.Workbench, new WorkbenchContributionsRegistry()); diff --git a/src/vs/workbench/common/contributions.ts b/src/vs/workbench/common/contributions.ts index ab8fdc6b145fedc706bb4f8318fb165af90586c8..2ae0bbec1d4edc0c98941de538697413dc4153ee 100644 --- a/src/vs/workbench/common/contributions.ts +++ b/src/vs/workbench/common/contributions.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { Registry } from 'vs/platform/registry/common/platform'; + import { IInstantiationService, IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { runWhenIdle, IdleDeadline } from 'vs/base/common/async'; // --- Workbench Contribution Registry @@ -39,85 +38,3 @@ export interface IWorkbenchContributionsRegistry { */ start(instantiationService: IInstantiationService, lifecycleService: ILifecycleService): void; } - -export class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry { - private instantiationService: IInstantiationService; - private lifecycleService: ILifecycleService; - - private toBeInstantiated: Map[]> = new Map[]>(); - - registerWorkbenchContribution(ctor: IWorkbenchContributionSignature, phase: LifecyclePhase = LifecyclePhase.Starting): void { - - // Instantiate directly if we are already matching the provided phase - if (this.instantiationService && this.lifecycleService && this.lifecycleService.phase >= phase) { - this.instantiationService.createInstance(ctor); - } - - // Otherwise keep contributions by lifecycle phase - else { - let toBeInstantiated = this.toBeInstantiated.get(phase); - if (!toBeInstantiated) { - toBeInstantiated = []; - this.toBeInstantiated.set(phase, toBeInstantiated); - } - - toBeInstantiated.push(ctor); - } - } - - start(instantiationService: IInstantiationService, lifecycleService: ILifecycleService): void { - this.instantiationService = instantiationService; - this.lifecycleService = lifecycleService; - - [LifecyclePhase.Starting, LifecyclePhase.Restoring, LifecyclePhase.Running, LifecyclePhase.Eventually].forEach(phase => { - this.instantiateByPhase(instantiationService, lifecycleService, phase); - }); - } - - private instantiateByPhase(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, phase: LifecyclePhase): void { - - // Instantiate contributions directly when phase is already reached - if (lifecycleService.phase >= phase) { - this.doInstantiateByPhase(instantiationService, phase); - } - - // Otherwise wait for phase to be reached - else { - lifecycleService.when(phase).then(() => { - this.doInstantiateByPhase(instantiationService, phase); - }); - } - } - - private doInstantiateByPhase(instantiationService: IInstantiationService, phase: LifecyclePhase): void { - const toBeInstantiated = this.toBeInstantiated.get(phase); - if (!toBeInstantiated) { - return; - } - if (phase !== LifecyclePhase.Eventually) { - // instantiate every synchronously and blocking - for (const ctor of toBeInstantiated) { - instantiationService.createInstance(ctor); - } - } else { - // for the Eventually-phase we instantiate contributions - // only when idle. this might take a few idle-busy-cycles - // but will finish within one second - let i = 0; - const instantiateSome = (idle: IdleDeadline) => { - while (i < toBeInstantiated.length) { - const ctor = toBeInstantiated[i++]; - instantiationService.createInstance(ctor); - if (idle.timeRemaining() < 1) { - // time is up -> reschedule - runWhenIdle(instantiateSome, 1000); - break; - } - } - }; - runWhenIdle(instantiateSome, 1000); - } - } -} - -Registry.add(Extensions.Workbench, new WorkbenchContributionsRegistry()); diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 3fe5d68a2194c7daf0c97ee51e07acd7f1734d9b..32e58a8562c1b058cc1b60b5d3041cce8d2ecd51 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -98,7 +98,6 @@ import { ExtensionManagementServerService } from 'vs/workbench/services/extensio import { DefaultURITransformer } from 'vs/base/common/uriIpc'; import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { ILabelService } from 'vs/platform/label/common/label'; -import { runWhenIdle } from 'vs/base/common/async'; import { IDownloadService } from 'vs/platform/download/common/download'; import { DownloadService } from 'vs/platform/download/node/downloadService'; @@ -208,7 +207,7 @@ export class WorkbenchShell extends Disposable { this.logStartupTelemetry(startupInfos); // Set lifecycle phase to `Runnning For A Bit` after a short delay - let eventuallPhaseTimeoutHandle = runWhenIdle(() => { + let eventuallPhaseTimeoutHandle = browser.runWhenIdle(() => { eventuallPhaseTimeoutHandle = void 0; this.lifecycleService.phase = LifecyclePhase.Eventually; }, 5000); diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index ce9193eb9cfa531342fb8481cce12b28811d8ff2..0323cd3034472e7150008da8db97a8e99236f4d7 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -9,6 +9,9 @@ import 'vs/base/common/strings'; import 'vs/base/common/errors'; +// contributions logic +import 'vs/workbench/browser/contributions'; + // Configuration import 'vs/workbench/services/configuration/common/configurationExtensionPoint';