debt - convert profile status to status item

This commit is contained in:
Benjamin Pasero
2019-06-03 11:15:39 +02:00
parent c9344059ca
commit ca35e2c8d7
2 changed files with 51 additions and 103 deletions
@@ -5,14 +5,11 @@
import * as nls from 'vs/nls';
import { Event, Emitter } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { append, $, addDisposableListener } from 'vs/base/browser/dom';
import { IStatusbarRegistry, StatusbarItemDescriptor, Extensions, IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { Registry } from 'vs/platform/registry/common/platform';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWindowsService } from 'vs/platform/windows/common/windows';
@@ -22,10 +19,11 @@ import product from 'vs/platform/product/node/product';
import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<IExtensionHostProfileService>;
private readonly _onDidChangeState: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidChangeState: Event<void> = this._onDidChangeState.event;
@@ -38,6 +36,9 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
private _profileSession: ProfileSession | null;
private _state: ProfileSessionState;
private profilingStatusBarIndicator: IStatusbarEntryAccessor | undefined;
private profilingStatusBarIndicatorLabelUpdater: IDisposable | undefined;
public get state() { return this._state; }
public get lastProfile() { return this._profile; }
@@ -46,12 +47,18 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
@IEditorService private readonly _editorService: IEditorService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IWindowsService private readonly _windowsService: IWindowsService,
@IDialogService private readonly _dialogService: IDialogService
@IDialogService private readonly _dialogService: IDialogService,
@IStatusbarService private readonly _statusbarService: IStatusbarService,
) {
super();
this._profile = null;
this._profileSession = null;
this._setState(ProfileSessionState.None);
CommandsRegistry.registerCommand('workbench.action.extensionHostProfilder.stop', () => {
this.stopProfiling();
this._editorService.openEditor(this._instantiationService.createInstance(RuntimeExtensionsInput), { revealIfOpened: true });
});
}
private _setState(state: ProfileSessionState): void {
@@ -61,17 +68,48 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
this._state = state;
if (this._state === ProfileSessionState.Running) {
ProfileExtHostStatusbarItem.instance.show(() => {
this.stopProfiling();
this._editorService.openEditor(this._instantiationService.createInstance(RuntimeExtensionsInput), { revealIfOpened: true });
});
this.updateProfilingStatusBarIndicator(true);
} else if (this._state === ProfileSessionState.Stopping) {
ProfileExtHostStatusbarItem.instance.hide();
this.updateProfilingStatusBarIndicator(false);
}
this._onDidChangeState.fire(undefined);
}
private updateProfilingStatusBarIndicator(visible: boolean): void {
if (this.profilingStatusBarIndicatorLabelUpdater) {
this.profilingStatusBarIndicatorLabelUpdater.dispose();
this.profilingStatusBarIndicatorLabelUpdater = undefined;
}
if (visible) {
const indicator: IStatusbarEntry = {
text: nls.localize('profilingExtensionHost', "$(sync~spin) Profiling Extension Host"),
tooltip: nls.localize('selectAndStartDebug', "Click to stop profiling."),
command: 'workbench.action.extensionHostProfilder.stop'
};
const timeStarted = Date.now();
const handle = setInterval(() => {
if (this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator.update({ ...indicator, text: nls.localize('profilingExtensionHostTime', "$(sync~spin) Profiling Extension Host ({0} sec)", Math.round((new Date().getTime() - timeStarted) / 1000)), });
}
}, 1000);
this.profilingStatusBarIndicatorLabelUpdater = toDisposable(() => clearInterval(handle));
if (!this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator = this._statusbarService.addEntry(indicator, StatusbarAlignment.RIGHT);
} else {
this.profilingStatusBarIndicator.update(indicator);
}
} else {
if (this.profilingStatusBarIndicator) {
this.profilingStatusBarIndicator.dispose();
this.profilingStatusBarIndicator = undefined;
}
}
}
public startProfiling(): Promise<any> | null {
if (this._state !== ProfileSessionState.None) {
return null;
@@ -134,76 +172,3 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio
}
}
export class ProfileExtHostStatusbarItem implements IStatusbarItem {
public static instance: ProfileExtHostStatusbarItem;
private toDispose: IDisposable[];
private statusBarItem: HTMLElement;
private label: HTMLElement;
private timeStarted: number;
private labelUpdater: any;
private clickHandler: (() => void) | null;
constructor() {
ProfileExtHostStatusbarItem.instance = this;
this.toDispose = [];
this.timeStarted = 0;
}
public show(clickHandler: () => void) {
this.clickHandler = clickHandler;
if (this.timeStarted === 0) {
this.timeStarted = new Date().getTime();
this.statusBarItem.hidden = false;
this.labelUpdater = setInterval(() => {
this.updateLabel();
}, 1000);
this.updateLabel();
}
}
public hide() {
this.clickHandler = null;
this.statusBarItem.hidden = true;
this.timeStarted = 0;
clearInterval(this.labelUpdater);
this.labelUpdater = null;
}
public render(container: HTMLElement): IDisposable {
if (!this.statusBarItem && container) {
this.statusBarItem = append(container, $('.profileExtHost-statusbar-item'));
this.toDispose.push(addDisposableListener(this.statusBarItem, 'click', () => {
if (this.clickHandler) {
this.clickHandler();
}
}));
this.statusBarItem.title = nls.localize('selectAndStartDebug', "Click to stop profiling.");
const a = append(this.statusBarItem, $('a'));
append(a, $('.icon'));
this.label = append(a, $('span.label'));
this.updateLabel();
this.statusBarItem.hidden = true;
}
return this;
}
private updateLabel() {
let label = 'Profiling Extension Host';
if (this.timeStarted > 0) {
let secondsRecoreded = (new Date().getTime() - this.timeStarted) / 1000;
label = `Profiling Extension Host (${Math.round(secondsRecoreded)} sec)`;
}
this.label.textContent = label;
}
public dispose(): void {
this.toDispose = dispose(this.toDispose);
}
}
Registry.as<IStatusbarRegistry>(Extensions.Statusbar).registerStatusbarItem(
new StatusbarItemDescriptor(ProfileExtHostStatusbarItem, StatusbarAlignment.RIGHT)
);
@@ -36,20 +36,3 @@
.runtime-extensions-editor .monaco-action-bar .actions-container {
justify-content: left;
}
.monaco-workbench .part.statusbar .profileExtHost-statusbar-item .icon {
background: url('profile-stop.svg') no-repeat;
display: inline-block;
padding-right: 2px;
padding-bottom: 2px;
width: 16px;
height: 16px;
vertical-align: middle;
animation:fade 1000ms infinite;
}
@keyframes fade {
from { opacity: 1.0; }
50% { opacity: 0.5; }
to { opacity: 1.0; }
}