reword custom progress location, show language status progress with item, with dedicated item, and in roll up item
This commit is contained in:
parent
0ee22a1bd6
commit
20d68ffb68
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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[] {
|
||||
|
|
|
@ -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}`);
|
||||
|
|
Loading…
Reference in a new issue