Skip to content

Commit

Permalink
extension provides contextkey
Browse files Browse the repository at this point in the history
  • Loading branch information
benibenj committed Aug 19, 2024
1 parent 25f6ae9 commit 717c95d
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 34 deletions.
87 changes: 56 additions & 31 deletions src/vs/workbench/browser/parts/titlebar/titlebarPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ import { isMacintosh, isWindows, isLinux, isWeb, isNative, platformLocale } from
import { Color } from 'vs/base/common/color';
import { EventType, EventHelper, Dimension, append, $, addDisposableListener, prepend, reset, getWindow, getWindowId, isAncestor, getActiveDocument, isHTMLElement } from 'vs/base/browser/dom';
import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { Emitter, Event } from 'vs/base/common/event';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { Parts, IWorkbenchLayoutService, ActivityBarPosition, LayoutSettings, EditorActionsLocation, EditorTabsMode } from 'vs/workbench/services/layout/browser/layoutService';
import { createActionViewItem, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { Action2, IMenu, IMenuService, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { Codicon } from 'vs/base/common/codicons';
import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry';
Expand Down Expand Up @@ -84,6 +84,11 @@ export interface ITitlebarPart extends IDisposable {
* Adds variables to be supported in the window title.
*/
registerVariables(variables: ITitleVariable[]): void;

/**
* Unregisters variables from being supported in the window title.
*/
unregisterVariables(variableNames: string[]): void;
}

export class BrowserTitleService extends MultiWindowParts<BrowserTitlebarPart> implements ITitleService {
Expand All @@ -95,8 +100,7 @@ export class BrowserTitleService extends MultiWindowParts<BrowserTitlebarPart> i
constructor(
@IInstantiationService protected readonly instantiationService: IInstantiationService,
@IStorageService storageService: IStorageService,
@IThemeService themeService: IThemeService,
@IContextKeyService private readonly contextKeyService: IContextKeyService
@IThemeService themeService: IThemeService
) {
super('workbench.titleService', themeService, storageService);

Expand Down Expand Up @@ -132,26 +136,36 @@ export class BrowserTitleService extends MultiWindowParts<BrowserTitlebarPart> i
}

private registerCommands(): void {
this._register(CommandsRegistry.registerCommand('setWindowTitleVariable', (_, key: string, value: string) => {
this.setWindowTitleVariable(key, value);
this._register(CommandsRegistry.registerCommand({
id: 'registerWindowTitleVariable',
handler: (accessor: ServicesAccessor, name: string, contextKey: string) => {
if (accessor.get(IContextKeyService).getContextKeyValue(contextKey) === undefined) {
console.error(`Unable to register window title variable: Context key '${contextKey}' is not defined.`);
return;
}
this.registerVariables([{ name, contextKey }]);
},
metadata: {
description: 'Registers a new title variable',
args: [
{ name: 'name', schema: { type: 'string' }, description: 'The name of the variable to register' },
{ name: 'contextKey', schema: { type: 'string' }, description: 'The context key to use for the value of the variable' }
]
}
}));
}

private readonly windowTitleVariableContextKeyMap = new Map<string, IContextKey<string>>();

private setWindowTitleVariable(key: string, value: string): void {
const prefixedKey = `windowTitleVariable.${key}`;

let contextKey = this.windowTitleVariableContextKeyMap.get(prefixedKey);
if (!contextKey) {
contextKey = this.contextKeyService.createKey(prefixedKey, value);
this.windowTitleVariableContextKeyMap.set(prefixedKey, contextKey);
this.registerVariables([
{ name: prefixedKey, contextKey: prefixedKey }
]);
} else {
contextKey.set(value);
}
this._register(CommandsRegistry.registerCommand({
id: 'unregisterWindowTitleVariable',
handler: (_, name: string) => {
this.unregisterVariables([name]);
},
metadata: {
description: 'Unregister a title variable',
args: [
{ name: 'name', schema: { type: 'string' }, description: 'The name of the variable to unregister' },
]
}
}));
}

//#region Auxiliary Titlebar Parts
Expand Down Expand Up @@ -208,29 +222,36 @@ export class BrowserTitleService extends MultiWindowParts<BrowserTitlebarPart> i
private variables: ITitleVariable[] = [];

registerVariables(variables: ITitleVariable[]): void {
const existingVariables = new Set(this.variables.map(v => v.contextKey));
const unregisteredVariables: ITitleVariable[] = [];
const duplicateVariables: ITitleVariable[] = [];

// Filter out any variables that are already registered
const existingVariableNames = new Set(this.variables.map(v => v.name));
const existingVariableContexKeys = new Set(this.variables.map(v => v.contextKey));
for (const v of variables) {
if (existingVariables.has(v.contextKey)) {
duplicateVariables.push(v);
if (existingVariableNames.has(v.name)) {
console.error(`A title variable with the name '${v.name}' is already registered.`);
} else if (existingVariableContexKeys.has(v.contextKey)) {
console.error(`A title variable with the context key '${v.contextKey}' is already registered.`);
} else {
unregisteredVariables.push(v);
}
}

if (duplicateVariables.length > 0) {
const duplicateKeys = duplicateVariables.map(v => v.contextKey).join(', ');
throw new Error(`Window title variables already registered: ${duplicateKeys}`);
}

this.variables.push(...unregisteredVariables);

for (const part of this.parts) {
part.registerVariables(unregisteredVariables);
}
}

unregisterVariables(variableNames: string[]): void {
this.variables = this.variables.filter(v => !variableNames.includes(v.name));

for (const part of this.parts) {
part.unregisterVariables(variableNames);
}
}

//#endregion
}

Expand Down Expand Up @@ -442,6 +463,10 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart {
this.windowTitle.registerVariables(variables);
}

unregisterVariables(variableNames: string[]): void {
this.windowTitle.unregisterVariables(variableNames);
}

protected override createContentArea(parent: HTMLElement): HTMLElement {
this.element = parent;
this.rootContainer = append(parent, $('.titlebar-container'));
Expand Down
16 changes: 16 additions & 0 deletions src/vs/workbench/browser/parts/titlebar/windowTitle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,22 @@ export class WindowTitle extends Disposable {
}
}

unregisterVariables(variableNames: string[]): void {
let changed = false;

for (const [contextKey, name] of this.variables) {
if (variableNames.includes(name)) {
this.variables.delete(contextKey);

changed = true;
}
}

if (changed) {
this.titleUpdater.schedule();
}
}

/**
* Possible template values:
*
Expand Down
8 changes: 5 additions & 3 deletions src/vs/workbench/contrib/scm/browser/activity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { localize } from 'vs/nls';
import { basename } from 'vs/base/common/resources';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { VIEW_PANE_ID, ISCMService, ISCMRepository, ISCMViewService } from 'vs/workbench/contrib/scm/common/scm';
import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity';
Expand Down Expand Up @@ -116,10 +116,12 @@ export class SCMActiveRepositoryController extends Disposable implements IWorkbe
this._activeRepositoryNameContextKey = ActiveRepositoryContextKeys.ActiveRepositoryName.bindTo(this.contextKeyService);
this._activeRepositoryBranchNameContextKey = ActiveRepositoryContextKeys.ActiveRepositoryBranchName.bindTo(this.contextKeyService);

this.titleService.registerVariables([
const titleVariables = [
{ name: 'activeRepositoryName', contextKey: ActiveRepositoryContextKeys.ActiveRepositoryName.key },
{ name: 'activeRepositoryBranchName', contextKey: ActiveRepositoryContextKeys.ActiveRepositoryBranchName.key, }
]);
];
this.titleService.registerVariables(titleVariables);
this._register(toDisposable(() => this.titleService.unregisterVariables(titleVariables.map(v => v.name))));

this._register(autorunWithStore((reader, store) => {
this._updateActivityCountBadge(this._countBadge.read(reader), store);
Expand Down

0 comments on commit 717c95d

Please sign in to comment.