diff --git a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts index a38def022ff62718a304dcb7cc5373829e11d0e9..57ef2e8a6a6ea1cad8c75f5df942e2605daaed2c 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/extensions.contribution.ts @@ -38,10 +38,12 @@ import { areSameExtensions } from 'vs/platform/extensionManagement/common/extens import { GalleryExtensionsHandler, ExtensionsHandler } from 'vs/workbench/parts/extensions/browser/extensionsQuickOpen'; import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import { RuntimeExtensionsEditor, ShowRuntimeExtensionsAction, IExtensionHostProfileService } from 'vs/workbench/parts/extensions/electron-browser/runtimeExtensionsEditor'; -import { EditorInput, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions } from 'vs/workbench/common/editor'; +import { RuntimeExtensionsEditor, ShowRuntimeExtensionsAction, IExtensionHostProfileService, DebugExtensionHostAction, StartExtensionHostProfileAction, StopExtensionHostProfileAction, CONTEXT_PROFILE_SESSION_STATE, SaveExtensionHostProfileAction, CONTEXT_EXTENSION_HOST_PROFILE_RECORDED } from 'vs/workbench/parts/extensions/electron-browser/runtimeExtensionsEditor'; +import { EditorInput, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, ActiveEditorContext } from 'vs/workbench/common/editor'; import { ExtensionHostProfileService } from 'vs/workbench/parts/extensions/electron-browser/extensionProfileService'; import { RuntimeExtensionsInput } from 'vs/workbench/services/extensions/electron-browser/runtimeExtensionsInput'; +import { URI } from 'vs/base/common/uri'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; // Singletons registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); @@ -258,6 +260,26 @@ CommandsRegistry.registerCommand('extension.open', (accessor: ServicesAccessor, }); }); +CommandsRegistry.registerCommand(DebugExtensionHostAction.ID, (accessor: ServicesAccessor) => { + const instantationService = accessor.get(IInstantiationService); + instantationService.createInstance(DebugExtensionHostAction).run(); +}); + +CommandsRegistry.registerCommand(StartExtensionHostProfileAction.ID, (accessor: ServicesAccessor) => { + const instantationService = accessor.get(IInstantiationService); + instantationService.createInstance(StartExtensionHostProfileAction, StartExtensionHostProfileAction.ID, StartExtensionHostProfileAction.LABEL).run(); +}); + +CommandsRegistry.registerCommand(StopExtensionHostProfileAction.ID, (accessor: ServicesAccessor) => { + const instantationService = accessor.get(IInstantiationService); + instantationService.createInstance(StopExtensionHostProfileAction, StopExtensionHostProfileAction.ID, StopExtensionHostProfileAction.LABEL).run(); +}); + +CommandsRegistry.registerCommand(SaveExtensionHostProfileAction.ID, (accessor: ServicesAccessor) => { + const instantationService = accessor.get(IInstantiationService); + instantationService.createInstance(SaveExtensionHostProfileAction, SaveExtensionHostProfileAction.ID, SaveExtensionHostProfileAction.LABEL).run(); +}); + // File menu registration MenuRegistry.appendMenuItem(MenuId.MenubarPreferencesMenu, { @@ -288,3 +310,58 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { }, order: 5 }); + +// Running extensions + +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { + command: { + id: DebugExtensionHostAction.ID, + title: DebugExtensionHostAction.LABEL, + iconLocation: { + dark: URI.parse(require.toUrl(`vs/workbench/parts/extensions/electron-browser/media/start-inverse.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/parts/extensions/electron-browser/media/start.svg`)), + } + }, + group: 'navigation', + when: ActiveEditorContext.isEqualTo(RuntimeExtensionsEditor.ID) +}); + +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { + command: { + id: StartExtensionHostProfileAction.ID, + title: StartExtensionHostProfileAction.LABEL, + iconLocation: { + dark: URI.parse(require.toUrl(`vs/workbench/parts/extensions/electron-browser/media/profile-start-inverse.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/parts/extensions/electron-browser/media/profile-start.svg`)), + } + }, + group: 'navigation', + when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(RuntimeExtensionsEditor.ID), CONTEXT_PROFILE_SESSION_STATE.notEqualsTo('running')) +}); + +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { + command: { + id: StopExtensionHostProfileAction.ID, + title: StopExtensionHostProfileAction.LABEL, + iconLocation: { + dark: URI.parse(require.toUrl(`vs/workbench/parts/extensions/electron-browser/media/profile-stop-inverse.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/parts/extensions/electron-browser/media/profile-stop.svg`)), + } + }, + group: 'navigation', + when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(RuntimeExtensionsEditor.ID), CONTEXT_PROFILE_SESSION_STATE.isEqualTo('running')) +}); + +MenuRegistry.appendMenuItem(MenuId.EditorTitle, { + command: { + id: SaveExtensionHostProfileAction.ID, + title: SaveExtensionHostProfileAction.LABEL, + iconLocation: { + dark: URI.parse(require.toUrl(`vs/workbench/parts/extensions/electron-browser/media/save-inverse.svg`)), + light: URI.parse(require.toUrl(`vs/workbench/parts/extensions/electron-browser/media/save.svg`)), + }, + precondition: CONTEXT_EXTENSION_HOST_PROFILE_RECORDED + }, + group: 'navigation', + when: ContextKeyExpr.and(ActiveEditorContext.isEqualTo(RuntimeExtensionsEditor.ID)) +}); diff --git a/src/vs/workbench/parts/extensions/electron-browser/media/runtimeExtensionsEditor.css b/src/vs/workbench/parts/extensions/electron-browser/media/runtimeExtensionsEditor.css index b5e7fb0d46eb7ec8b6c0eb318f7d02a22f3facaf..063dd6229bedf66ebb4b72282e79295814a19bba 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/media/runtimeExtensionsEditor.css +++ b/src/vs/workbench/parts/extensions/electron-browser/media/runtimeExtensionsEditor.css @@ -53,42 +53,6 @@ padding: 10px 14px 10px 0; } -.monaco-action-bar .debug-extension-host { - background: url('start.svg') center center no-repeat; -} -.vs-dark .monaco-action-bar .debug-extension-host, -.hc-black .monaco-action-bar .debug-extension-host { - background: url('start-inverse.svg') center center no-repeat; -} - -.monaco-action-bar .extension-host-profile-start { - background: url('profile-start.svg') center center no-repeat; -} - -.monaco-action-bar .extension-host-profile-stop { - background: url('profile-stop.svg') center center no-repeat; -} - -.vs-dark .monaco-action-bar .extension-host-profile-start, -.hc-black .monaco-action-bar .extension-host-profile-start { - background: url('profile-start-inverse.svg') center center no-repeat; -} - -.vs-dark .monaco-action-bar .extension-host-profile-stop, -.hc-black .monaco-action-bar .extension-host-profile-stop { - background: url('profile-stop-inverse.svg') center center no-repeat; - animation:fade 1000ms infinite; -} - -.monaco-action-bar .save-extension-host-profile { - background: url('save.svg') center center no-repeat; -} - -.vs-dark .monaco-action-bar .save-extension-host-profile, -.hc-black .monaco-action-bar .save-extension-host-profile { - background: url('save-inverse.svg') center center no-repeat; -} - .runtime-extensions-editor .monaco-action-bar { padding-top: 21px; flex-shrink: 0; @@ -114,4 +78,4 @@ from { opacity: 1.0; } 50% { opacity: 0.5; } to { opacity: 1.0; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/parts/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/parts/extensions/electron-browser/runtimeExtensionsEditor.ts index fb9af88c96edba2b87f88787cedda9d681d96e4c..9efdd992c2c841dec656a8940d071699d4df9609 100644 --- a/src/vs/workbench/parts/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/parts/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -40,10 +40,13 @@ import { RuntimeExtensionsInput } from 'vs/workbench/services/extensions/electro import { IDebugService } from 'vs/workbench/parts/debug/common/debug'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { randomPort } from 'vs/base/node/ports'; +import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; export const IExtensionHostProfileService = createDecorator('extensionHostProfileService'); +export const CONTEXT_PROFILE_SESSION_STATE = new RawContextKey('profileSessionState', 'none'); +export const CONTEXT_EXTENSION_HOST_PROFILE_RECORDED = new RawContextKey('extensionHostProfileRecorded', false); -export const enum ProfileSessionState { +export enum ProfileSessionState { None = 0, Starting = 1, Running = 2, @@ -89,7 +92,7 @@ interface IRuntimeExtension { export class RuntimeExtensionsEditor extends BaseEditor { - static readonly ID: string = 'workbench.editor.runtimeExtensions'; + public static readonly ID: string = 'workbench.editor.runtimeExtensions'; private _list: WorkbenchList; private _profileInfo: IExtensionHostProfile; @@ -97,10 +100,13 @@ export class RuntimeExtensionsEditor extends BaseEditor { private _elements: IRuntimeExtension[]; private _extensionsDescriptions: IExtensionDescription[]; private _updateSoon: RunOnceScheduler; + private _profileSessionState: IContextKey; + private _extensionsHostRecoded: IContextKey; constructor( @ITelemetryService telemetryService: ITelemetryService, @IThemeService themeService: IThemeService, + @IContextKeyService contextKeyService: IContextKeyService, @IExtensionsWorkbenchService private readonly _extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionService private readonly _extensionService: IExtensionService, @INotificationService private readonly _notificationService: INotificationService, @@ -114,14 +120,23 @@ export class RuntimeExtensionsEditor extends BaseEditor { this._profileInfo = this._extensionHostProfileService.lastProfile; this._register(this._extensionHostProfileService.onDidChangeLastProfile(() => { this._profileInfo = this._extensionHostProfileService.lastProfile; + this._extensionsHostRecoded.set(!!this._profileInfo); this._updateExtensions(); })); + this._extensionHostProfileService.onDidChangeState(() => { + const state = this._extensionHostProfileService.state; + + this._profileSessionState.set(ProfileSessionState[state].toLowerCase()); + }); this._elements = null; this._extensionsDescriptions = []; this._updateExtensions(); + this._profileSessionState = CONTEXT_PROFILE_SESSION_STATE.bindTo(contextKeyService); + this._extensionsHostRecoded = CONTEXT_EXTENSION_HOST_PROFILE_RECORDED.bindTo(contextKeyService); + this._updateSoon = this._register(new RunOnceScheduler(() => this._updateExtensions(), 200)); this._extensionService.getExtensions().then((extensions) => { @@ -401,7 +416,13 @@ export class RuntimeExtensionsEditor extends BaseEditor { actions.forEach((a: DisableForWorkspaceAction | DisableGloballyAction) => a.extension = e.element.marketplaceInfo); actions.push(new Separator()); } - actions.push(this.extensionHostProfileAction, this.saveExtensionHostProfileAction); + const state = this._extensionHostProfileService.state; + if (state === ProfileSessionState.Running) { + actions.push(this._instantiationService.createInstance(StopExtensionHostProfileAction, StopExtensionHostProfileAction.ID, StopExtensionHostProfileAction.LABEL)); + } else { + actions.push(this._instantiationService.createInstance(StartExtensionHostProfileAction, StartExtensionHostProfileAction.ID, StartExtensionHostProfileAction.LABEL)); + } + actions.push(this.saveExtensionHostProfileAction); this._contextMenuService.showContextMenu({ getAnchor: () => e.anchor, @@ -410,24 +431,6 @@ export class RuntimeExtensionsEditor extends BaseEditor { }); } - public getActions(): IAction[] { - return [ - this.debugExtensionHostAction, - this.saveExtensionHostProfileAction, - this.extensionHostProfileAction - ]; - } - - @memoize - private get debugExtensionHostAction(): IAction { - return this._instantiationService.createInstance(DebugExtensionHostAction); - } - - @memoize - private get extensionHostProfileAction(): IAction { - return this._instantiationService.createInstance(ExtensionHostProfileAction, ExtensionHostProfileAction.ID, ExtensionHostProfileAction.LABEL_START); - } - @memoize private get saveExtensionHostProfileAction(): IAction { return this._instantiationService.createInstance(SaveExtensionHostProfileAction, SaveExtensionHostProfileAction.ID, SaveExtensionHostProfileAction.LABEL); @@ -493,7 +496,7 @@ class ReportExtensionIssueAction extends Action { } } -class DebugExtensionHostAction extends Action { +export class DebugExtensionHostAction extends Action { static readonly ID = 'workbench.extensions.action.debugExtensionHost'; static LABEL = nls.localize('debugExtensionHost', "Start Debugging Extension Host"); static CSS_CLASS = 'debug-extension-host'; @@ -532,48 +535,41 @@ class DebugExtensionHostAction extends Action { } } -class ExtensionHostProfileAction extends Action { +export class StartExtensionHostProfileAction extends Action { static readonly ID = 'workbench.extensions.action.extensionHostProfile'; - static LABEL_START = nls.localize('extensionHostProfileStart', "Start Extension Host Profile"); - static LABEL_STOP = nls.localize('extensionHostProfileStop', "Stop Extension Host Profile"); - static STOP_CSS_CLASS = 'extension-host-profile-stop'; - static START_CSS_CLASS = 'extension-host-profile-start'; + static LABEL = nls.localize('extensionHostProfileStart', "Start Extension Host Profile"); constructor( - id: string = ExtensionHostProfileAction.ID, label: string = ExtensionHostProfileAction.LABEL_START, + id: string = StartExtensionHostProfileAction.ID, label: string = StartExtensionHostProfileAction.LABEL, @IExtensionHostProfileService private readonly _extensionHostProfileService: IExtensionHostProfileService, ) { - super(id, label, ExtensionHostProfileAction.START_CSS_CLASS); + super(id, label); + } - this._extensionHostProfileService.onDidChangeState(() => this._update()); + run(): TPromise { + this._extensionHostProfileService.startProfiling(); + return TPromise.as(null); } +} - private _update(): void { - const state = this._extensionHostProfileService.state; +export class StopExtensionHostProfileAction extends Action { + static readonly ID = 'workbench.extensions.action.stopExtensionHostProfile'; + static LABEL = nls.localize('stopExtensionHostProfileStart', "Stop Extension Host Profile"); - if (state === ProfileSessionState.Running) { - this.class = ExtensionHostProfileAction.STOP_CSS_CLASS; - this.label = ExtensionHostProfileAction.LABEL_STOP; - } else { - this.class = ExtensionHostProfileAction.START_CSS_CLASS; - this.label = ExtensionHostProfileAction.LABEL_START; - } + constructor( + id: string = StartExtensionHostProfileAction.ID, label: string = StartExtensionHostProfileAction.LABEL, + @IExtensionHostProfileService private readonly _extensionHostProfileService: IExtensionHostProfileService, + ) { + super(id, label); } run(): TPromise { - const state = this._extensionHostProfileService.state; - - if (state === ProfileSessionState.Running) { - this._extensionHostProfileService.stopProfiling(); - } else if (state === ProfileSessionState.None) { - this._extensionHostProfileService.startProfiling(); - } - + this._extensionHostProfileService.stopProfiling(); return TPromise.as(null); } } -class SaveExtensionHostProfileAction extends Action { +export class SaveExtensionHostProfileAction extends Action { static LABEL = nls.localize('saveExtensionHostProfile', "Save Extension Host Profile"); static readonly ID = 'workbench.extensions.action.saveExtensionHostProfile'; @@ -584,8 +580,7 @@ class SaveExtensionHostProfileAction extends Action { @IEnvironmentService private readonly _environmentService: IEnvironmentService, @IExtensionHostProfileService private readonly _extensionHostProfileService: IExtensionHostProfileService, ) { - super(id, label, 'save-extension-host-profile', false); - this.enabled = (this._extensionHostProfileService.lastProfile !== null); + super(id, label, undefined, false); this._extensionHostProfileService.onDidChangeLastProfile(() => { this.enabled = (this._extensionHostProfileService.lastProfile !== null); });