Allow to unset any status bar item

fixes https://github.com/microsoft/vscode/issues/183773

also fixes leaking listener
This commit is contained in:
Johannes 2023-06-05 16:31:23 +02:00
parent ea2307487e
commit 93b1636904
No known key found for this signature in database
GPG key ID: 6DEF802A22264FCA
4 changed files with 35 additions and 27 deletions

View file

@ -187,6 +187,8 @@ export function combinedDisposable(...disposables: IDisposable[]): IDisposable {
/**
* Turn a function that implements dispose into an {@link IDisposable}.
*
* @param fn Clean up function, guaranteed to be called only **once**.
*/
export function toDisposable(fn: () => void): IDisposable {
const self = trackDisposable({

View file

@ -6,7 +6,7 @@
import { MainThreadStatusBarShape, MainContext, ExtHostContext, StatusBarItemDto } from '../common/extHost.protocol';
import { ThemeColor } from 'vs/base/common/themables';
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
import { DisposableMap } from 'vs/base/common/lifecycle';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { Command } from 'vs/editor/common/languages';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { IMarkdownString } from 'vs/base/common/htmlContent';
@ -16,7 +16,7 @@ import { IStatusbarEntry, StatusbarAlignment } from 'vs/workbench/services/statu
@extHostNamedCustomer(MainContext.MainThreadStatusBar)
export class MainThreadStatusBar implements MainThreadStatusBarShape {
private readonly entries = new DisposableMap<string>();
private readonly _store = new DisposableStore();
constructor(
extHostContext: IExtHostContext,
@ -32,11 +32,11 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
proxy.$acceptStaticEntries(entries);
statusbarService.onDidChange(e => {
this._store.add(statusbarService.onDidChange(e => {
if (e.added) {
proxy.$acceptStaticEntries([asDto(e.added[0], e.added[1])]);
}
});
}));
function asDto(entryId: string, item: { entry: IStatusbarEntry; alignment: StatusbarAlignment; priority: number }): StatusBarItemDto {
return {
@ -51,17 +51,14 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
}
dispose(): void {
this.entries.dispose();
this._store.dispose();
}
$setEntry(entryId: string, id: string, extensionId: string | undefined, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignLeft: boolean, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined): void {
const dispo = this.statusbarService.setOrUpdateEntry(entryId, id, extensionId, name, text, tooltip, command, color, backgroundColor, alignLeft, priority, accessibilityInformation);
if (!this.entries.has(entryId)) {
this.entries.set(entryId, dispo);
}
this.statusbarService.setOrUpdateEntry(entryId, id, extensionId, name, text, tooltip, command, color, backgroundColor, alignLeft, priority, accessibilityInformation);
}
$disposeEntry(entryId: string) {
this.entries.deleteAndDispose(entryId);
this.statusbarService.unsetEntry(entryId);
}
}

View file

@ -43,7 +43,9 @@ export interface IExtensionStatusBarItemService {
onDidChange: Event<IExtensionStatusBarItemChangeEvent>;
setOrUpdateEntry(id: string, statusId: string, extensionId: string | undefined, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignLeft: boolean, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined): IDisposable;
setOrUpdateEntry(id: string, statusId: string, extensionId: string | undefined, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignLeft: boolean, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined): void;
unsetEntry(id: string): void;
getEntries(): Iterable<ExtensionStatusBarEntry>;
}
@ -53,7 +55,7 @@ class ExtensionStatusBarItemService implements IExtensionStatusBarItemService {
declare readonly _serviceBrand: undefined;
private readonly _entries: Map<string, { accessor: IStatusbarEntryAccessor; entry: IStatusbarEntry; alignment: MainThreadStatusBarAlignment; priority: number }> = new Map();
private readonly _entries: Map<string, { accessor: IStatusbarEntryAccessor; entry: IStatusbarEntry; alignment: MainThreadStatusBarAlignment; priority: number; disposable: IDisposable }> = new Map();
private readonly _onDidChange = new Emitter<IExtensionStatusBarItemChangeEvent>();
readonly onDidChange: Event<IExtensionStatusBarItemChangeEvent> = this._onDidChange.event;
@ -66,7 +68,11 @@ class ExtensionStatusBarItemService implements IExtensionStatusBarItemService {
this._onDidChange.dispose();
}
setOrUpdateEntry(entryId: string, id: string, extensionId: string | undefined, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignLeft: boolean, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined): IDisposable {
setOrUpdateEntry(entryId: string,
id: string, extensionId: string | undefined, name: string, text: string, tooltip: IMarkdownString | string | undefined,
command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined,
alignLeft: boolean, priority: number | undefined, accessibilityInformation: IAccessibilityInformation | undefined
): void {
// if there are icons in the text use the tooltip for the aria label
let ariaLabel: string;
let role: string | undefined = undefined;
@ -109,11 +115,17 @@ class ExtensionStatusBarItemService implements IExtensionStatusBarItemService {
entryPriority = priority;
}
const accessor = this._statusbarService.addEntry(entry, id, alignment, entryPriority);
this._entries.set(entryId, {
accessor: this._statusbarService.addEntry(entry, id, alignment, entryPriority),
accessor,
entry,
alignment,
priority
priority,
disposable: toDisposable(() => {
accessor.dispose();
this._entries.delete(entryId);
this._onDidChange.fire({ removed: entryId });
})
});
this._onDidChange.fire({ added: [entryId, { entry, alignment, priority }] });
@ -123,15 +135,10 @@ class ExtensionStatusBarItemService implements IExtensionStatusBarItemService {
existingEntry.accessor.update(entry);
existingEntry.entry = entry;
}
}
return toDisposable(() => {
const entry = this._entries.get(entryId);
if (entry) {
entry.accessor.dispose();
this._entries.delete(entryId);
this._onDidChange.fire({ removed: entryId });
}
});
unsetEntry(entryId: string): void {
this._entries.get(entryId)?.disposable.dispose();
}
getEntries(): Iterable<[string, { entry: IStatusbarEntry; alignment: MainThreadStatusBarAlignment; priority: number }]> {
@ -236,7 +243,7 @@ export class StatusBarItemsExtensionPoint {
const fullItemId = asStatusBarItemIdentifier(entry.description.identifier, candidate.id);
contributions.add(statusBarItemsService.setOrUpdateEntry(
statusBarItemsService.setOrUpdateEntry(
fullItemId,
fullItemId,
ExtensionIdentifier.toKey(entry.description.identifier),
@ -248,7 +255,9 @@ export class StatusBarItemsExtensionPoint {
candidate.alignment === 'left',
candidate.priority,
undefined
));
);
contributions.add(toDisposable(() => statusBarItemsService.unsetEntry(fullItemId)));
}
}
});

View file

@ -66,9 +66,9 @@ export class ExtHostStatusBarEntry implements vscode.StatusBarItem {
// this can only happen when an item was contributed by an extension
const item = staticItems.get(this._entryId);
if (item) {
alignment = item.alignLeft ? ExtHostStatusBarAlignment.Left : ExtHostStatusBarAlignment.Right;
priority = item.priority;
this._visible = true;
this._alignment = item.alignLeft ? ExtHostStatusBarAlignment.Left : ExtHostStatusBarAlignment.Right;
this._priority = item.priority;
this.name = item.name;
this.text = item.text;
this.command = item.command;