reword custom progress location, show language status progress with item, with dedicated item, and in roll up item

This commit is contained in:
Johannes Rieken 2021-11-26 09:49:43 +01:00
parent 0ee22a1bd6
commit 20d68ffb68
No known key found for this signature in database
GPG key ID: 96634B5AF12F8798
5 changed files with 73 additions and 26 deletions

View file

@ -27,11 +27,9 @@ export interface IProgressService {
registerProgressLocation(location: string, handle: ICustomProgressLocation): IDisposable;
}
export type ICustomProgressLocation = <R>(
options: IProgressOptions | IProgressDialogOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions,
task: (progress: IProgress<IProgressStep>) => Promise<R>,
onDidCancel?: (choice?: number) => void
) => Promise<R>;
export interface ICustomProgressLocation {
startProgress(): { progress: IProgress<IProgressStep>, token?: CancellationToken, stop(): void };
}
export interface IProgressIndicator {

View file

@ -15,9 +15,9 @@ import { onUnexpectedExternalError } from 'vs/base/common/errors';
export class ExtHostProgress implements ExtHostProgressShape {
private _proxy: MainThreadProgressShape;
private readonly _proxy: MainThreadProgressShape;
private readonly _mapHandleToCancellationSource = new Map<number, CancellationTokenSource>();
private _handles: number = 0;
private _mapHandleToCancellationSource: Map<number, CancellationTokenSource> = new Map();
constructor(proxy: MainThreadProgressShape) {
this._proxy = proxy;
@ -42,9 +42,7 @@ export class ExtHostProgress implements ExtHostProgressShape {
const progressEnd = (handle: number): void => {
this._proxy.$progressEnd(handle);
this._mapHandleToCancellationSource.delete(handle);
if (source) {
source.dispose();
}
source?.dispose();
};
let p: Thenable<R>;
@ -56,7 +54,7 @@ export class ExtHostProgress implements ExtHostProgressShape {
throw err;
}
p.then(result => progressEnd(handle), err => progressEnd(handle));
Promise.resolve(p).finally(() => progressEnd(handle));
return p;
}

View file

@ -66,8 +66,9 @@ class EditorStatusContribution implements IWorkbenchContribution {
_storageService.onDidChangeValue(this._handleStorageChange, this, this._disposables);
this._restoreState();
_languageStatusService.onDidChange(this._update, this, this._disposables);
_editorService.onDidActiveEditorChange(this._update, this, this._disposables);
_editorService.onDidActiveEditorChange(() => this._update(), this, this._disposables);
_languageStatusService.onDidChange(() => this._update(), this, this._disposables);
_languageStatusService.onDidChangeBusy(() => this._update(true), this, this._disposables);
this._update();
_statusBarService.onDidChangeEntryVisibility(e => {
@ -136,11 +137,11 @@ class EditorStatusContribution implements IWorkbenchContribution {
return new LanguageStatusViewModel(combined, dedicated);
}
private _update(): void {
private _update(force?: boolean): void {
const model = this._createViewModel();
if (this._model?.isEqual(model)) {
if (this._model?.isEqual(model) && !force) {
return;
}
@ -160,18 +161,21 @@ class EditorStatusContribution implements IWorkbenchContribution {
const showSeverity = first.severity >= Severity.Warning;
const text = EditorStatusContribution._severityToComboCodicon(first.severity);
let isBusy = false;
const ariaLabels: string[] = [];
const element = document.createElement('div');
for (const status of model.combined) {
element.appendChild(this._renderStatus(status, showSeverity, this._renderDisposables));
const thisIsBusy = this._languageStatusService.isBusy(status);
element.appendChild(this._renderStatus(status, showSeverity, thisIsBusy, this._renderDisposables));
ariaLabels.push(this._asAriaLabel(status));
isBusy = isBusy || thisIsBusy;
}
const props: IStatusbarEntry = {
name: localize('langStatus.name', "Editor Language Status"),
ariaLabel: localize('langStatus.aria', "Editor Language Status: {0}", ariaLabels.join(', next: ')),
tooltip: element,
command: ShowTooltipCommand,
text,
text: isBusy ? `${text}\u00A0\u00A0$(loading~spin)` : text,
};
if (!this._combinedEntry) {
this._combinedEntry = this._statusBarService.addEntry(props, EditorStatusContribution._id, StatusbarAlignment.RIGHT, { id: 'status.editor.mode', alignment: StatusbarAlignment.LEFT, compact: true });
@ -183,7 +187,7 @@ class EditorStatusContribution implements IWorkbenchContribution {
// dedicated status bar items are shows as-is in the status bar
const newDedicatedEntries = new Map<string, IStatusbarEntryAccessor>();
for (const status of model.dedicated) {
const props = EditorStatusContribution._asStatusbarEntry(status);
const props = EditorStatusContribution._asStatusbarEntry(status, this._languageStatusService.isBusy(status));
let entry = this._dedicatedEntries.get(status.id);
if (!entry) {
entry = this._statusBarService.addEntry(props, status.id, StatusbarAlignment.RIGHT, 100.09999);
@ -197,7 +201,7 @@ class EditorStatusContribution implements IWorkbenchContribution {
this._dedicatedEntries = newDedicatedEntries;
}
private _renderStatus(status: ILanguageStatus, showSeverity: boolean, store: DisposableStore): HTMLElement {
private _renderStatus(status: ILanguageStatus, showSeverity: boolean, isBusy: boolean, store: DisposableStore): HTMLElement {
const parent = document.createElement('div');
parent.classList.add('hover-language-status');
@ -219,6 +223,9 @@ class EditorStatusContribution implements IWorkbenchContribution {
const label = document.createElement('span');
label.classList.add('label');
if (isBusy) {
dom.append(label, ...renderLabelWithIcons('$(loading~spin)\u00A0\u00A0'));
}
dom.append(label, ...renderLabelWithIcons(status.label));
left.appendChild(label);
@ -297,7 +304,7 @@ class EditorStatusContribution implements IWorkbenchContribution {
// ---
private static _asStatusbarEntry(item: ILanguageStatus): IStatusbarEntry {
private static _asStatusbarEntry(item: ILanguageStatus, isBusy: boolean): IStatusbarEntry {
let color: ThemeColor | undefined;
let backgroundColor: ThemeColor | undefined;
@ -311,7 +318,7 @@ class EditorStatusContribution implements IWorkbenchContribution {
return {
name: localize('name.pattern', '{0} (Language Status)', item.name),
text: item.label,
text: isBusy ? `${item.label}\u00A0\u00A0$(loading~spin)` : item.label,
ariaLabel: item.accessibilityInfo?.label ?? item.label,
role: item.accessibilityInfo?.role,
tooltip: item.command?.tooltip || new MarkdownString(item.detail, true),

View file

@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vs/base/common/cancellation';
import { Event } from 'vs/base/common/event';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { combinedDisposable, IDisposable } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
import { compare } from 'vs/base/common/strings';
import { ITextModel } from 'vs/editor/common/model';
@ -15,6 +15,7 @@ import { LanguageSelector } from 'vs/editor/common/modes/languageSelector';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IProgressService, Progress } from 'vs/platform/progress/common/progress';
export interface ILanguageStatus {
readonly id: string;
@ -40,9 +41,13 @@ export interface ILanguageStatusService {
onDidChange: Event<void>;
onDidChangeBusy: Event<ILanguageStatus>;
addStatus(status: ILanguageStatus): IDisposable;
getLanguageStatus(model: ITextModel): ILanguageStatus[];
isBusy(status: ILanguageStatus): boolean;
}
@ -51,11 +56,47 @@ class LanguageStatusServiceImpl implements ILanguageStatusService {
declare _serviceBrand: undefined;
private readonly _provider = new LanguageFeatureRegistry<ILanguageStatus>();
readonly onDidChange: Event<any> = this._provider.onDidChange;
private readonly _busyStatus = new Map<ILanguageStatus, number>();
private readonly _onDidChangeBusy = new Emitter<ILanguageStatus>();
readonly onDidChangeBusy: Event<ILanguageStatus> = this._onDidChangeBusy.event;
constructor(@IProgressService private readonly _progressService: IProgressService) { }
isBusy(status: ILanguageStatus): boolean {
return (this._busyStatus.get(status) ?? 0) > 0;
}
addStatus(status: ILanguageStatus): IDisposable {
return this._provider.register(status.selector, status);
const d1 = this._provider.register(status.selector, status);
const d2 = this._progressService.registerProgressLocation(status.id, {
startProgress: () => {
let value = this._busyStatus.get(status);
if (value === undefined) {
this._busyStatus.set(status, 1);
this._onDidChangeBusy.fire(status);
} else {
this._busyStatus.set(status, value + 1);
}
return {
progress: new Progress(_data => { }),
stop: () => {
let value = this._busyStatus.get(status);
if (value !== undefined) {
if (value === 1) {
this._busyStatus.delete(status);
this._onDidChangeBusy.fire(status);
} else {
this._busyStatus.set(status, value - 1);
}
}
}
};
}
});
return combinedDisposable(d1, d2);
}
getLanguageStatus(model: ITextModel): ILanguageStatus[] {

View file

@ -72,7 +72,10 @@ export class ProgressService implements IProgressService {
const customLocation = this.customProgessLocations.get(location);
if (customLocation) {
return customLocation<R>(options, task, onDidCancel);
const obj = customLocation.startProgress();
const promise = task(obj.progress);
promise.finally(() => obj.stop());
return promise;
}
throw new Error(`Bad progress location: ${location}`);