Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/common/contextkeys.ts
5241 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { DisposableStore } from '../../base/common/lifecycle.js';
7
import { URI } from '../../base/common/uri.js';
8
import { localize } from '../../nls.js';
9
import { IContextKeyService, IContextKey, RawContextKey } from '../../platform/contextkey/common/contextkey.js';
10
import { basename, dirname, extname, isEqual } from '../../base/common/resources.js';
11
import { ILanguageService } from '../../editor/common/languages/language.js';
12
import { IFileService } from '../../platform/files/common/files.js';
13
import { IModelService } from '../../editor/common/services/model.js';
14
import { Schemas } from '../../base/common/network.js';
15
import { EditorInput } from './editor/editorInput.js';
16
import { IEditorResolverService } from '../services/editor/common/editorResolverService.js';
17
import { DEFAULT_EDITOR_ASSOCIATION } from './editor.js';
18
import { DiffEditorInput } from './editor/diffEditorInput.js';
19
20
//#region < --- Workbench --- >
21
22
export const WorkbenchStateContext = new RawContextKey<string>('workbenchState', undefined, { type: 'string', description: localize('workbenchState', "The kind of workspace opened in the window, either 'empty' (no workspace), 'folder' (single folder) or 'workspace' (multi-root workspace)") });
23
export const WorkspaceFolderCountContext = new RawContextKey<number>('workspaceFolderCount', 0, localize('workspaceFolderCount', "The number of root folders in the workspace"));
24
25
export const OpenFolderWorkspaceSupportContext = new RawContextKey<boolean>('openFolderWorkspaceSupport', true, true);
26
export const EnterMultiRootWorkspaceSupportContext = new RawContextKey<boolean>('enterMultiRootWorkspaceSupport', true, true);
27
export const EmptyWorkspaceSupportContext = new RawContextKey<boolean>('emptyWorkspaceSupport', true, true);
28
29
export const DirtyWorkingCopiesContext = new RawContextKey<boolean>('dirtyWorkingCopies', false, localize('dirtyWorkingCopies', "Whether there are any working copies with unsaved changes"));
30
31
export const RemoteNameContext = new RawContextKey<string>('remoteName', '', localize('remoteName', "The name of the remote the window is connected to or an empty string if not connected to any remote"));
32
33
export const VirtualWorkspaceContext = new RawContextKey<string>('virtualWorkspace', '', localize('virtualWorkspace', "The scheme of the current workspace is from a virtual file system or an empty string."));
34
export const TemporaryWorkspaceContext = new RawContextKey<boolean>('temporaryWorkspace', false, localize('temporaryWorkspace', "The scheme of the current workspace is from a temporary file system."));
35
36
export const IsAgentSessionsWorkspaceContext = new RawContextKey<boolean>('isAgentSessionsWorkspace', false, localize('isAgentSessionsWorkspace', "Whether the current workspace is the agent sessions workspace."));
37
38
export const WorkbenchModeContext = new RawContextKey<string>('workbenchMode', '', localize('workbenchMode', "The current workbench mode."));
39
40
export const HasWebFileSystemAccess = new RawContextKey<boolean>('hasWebFileSystemAccess', false, true); // Support for FileSystemAccess web APIs (https://wicg.github.io/file-system-access)
41
42
export const EmbedderIdentifierContext = new RawContextKey<string | undefined>('embedderIdentifier', undefined, localize('embedderIdentifier', 'The identifier of the embedder according to the product service, if one is defined'));
43
44
export const InAutomationContext = new RawContextKey<boolean>('inAutomation', false, localize('inAutomation', "Whether VS Code is running under automation/smoke test"));
45
46
//#endregion
47
48
//#region < --- Window --- >
49
50
export const IsMainWindowFullscreenContext = new RawContextKey<boolean>('isFullscreen', false, localize('isFullscreen', "Whether the main window is in fullscreen mode"));
51
export const IsAuxiliaryWindowFocusedContext = new RawContextKey<boolean>('isAuxiliaryWindowFocusedContext', false, localize('isAuxiliaryWindowFocusedContext', "Whether an auxiliary window is focused"));
52
53
export const IsWindowAlwaysOnTopContext = new RawContextKey<boolean>('isWindowAlwaysOnTop', false, localize('isWindowAlwaysOnTop', "Whether the window is always on top"));
54
55
export const IsAuxiliaryWindowContext = new RawContextKey<boolean>('isAuxiliaryWindow', false, localize('isAuxiliaryWindow', "Window is an auxiliary window"));
56
57
58
//#endregion
59
60
61
//#region < --- Editor --- >
62
63
// Editor State Context Keys
64
export const ActiveEditorDirtyContext = new RawContextKey<boolean>('activeEditorIsDirty', false, localize('activeEditorIsDirty', "Whether the active editor has unsaved changes"));
65
export const ActiveEditorPinnedContext = new RawContextKey<boolean>('activeEditorIsNotPreview', false, localize('activeEditorIsNotPreview', "Whether the active editor is not in preview mode"));
66
export const ActiveEditorFirstInGroupContext = new RawContextKey<boolean>('activeEditorIsFirstInGroup', false, localize('activeEditorIsFirstInGroup', "Whether the active editor is the first one in its group"));
67
export const ActiveEditorLastInGroupContext = new RawContextKey<boolean>('activeEditorIsLastInGroup', false, localize('activeEditorIsLastInGroup', "Whether the active editor is the last one in its group"));
68
export const ActiveEditorStickyContext = new RawContextKey<boolean>('activeEditorIsPinned', false, localize('activeEditorIsPinned', "Whether the active editor is pinned"));
69
export const ActiveEditorReadonlyContext = new RawContextKey<boolean>('activeEditorIsReadonly', false, localize('activeEditorIsReadonly', "Whether the active editor is read-only"));
70
export const ActiveCompareEditorCanSwapContext = new RawContextKey<boolean>('activeCompareEditorCanSwap', false, localize('activeCompareEditorCanSwap', "Whether the active compare editor can swap sides"));
71
export const ActiveEditorCanToggleReadonlyContext = new RawContextKey<boolean>('activeEditorCanToggleReadonly', true, localize('activeEditorCanToggleReadonly', "Whether the active editor can toggle between being read-only or writeable"));
72
export const ActiveEditorCanRevertContext = new RawContextKey<boolean>('activeEditorCanRevert', false, localize('activeEditorCanRevert', "Whether the active editor can revert"));
73
export const ActiveEditorCanSplitInGroupContext = new RawContextKey<boolean>('activeEditorCanSplitInGroup', true);
74
75
// Editor Kind Context Keys
76
export const ActiveEditorContext = new RawContextKey<string | null>('activeEditor', null, { type: 'string', description: localize('activeEditor', "The identifier of the active editor") });
77
export const ActiveEditorAvailableEditorIdsContext = new RawContextKey<string>('activeEditorAvailableEditorIds', '', localize('activeEditorAvailableEditorIds', "The available editor identifiers that are usable for the active editor"));
78
export const TextCompareEditorVisibleContext = new RawContextKey<boolean>('textCompareEditorVisible', false, localize('textCompareEditorVisible', "Whether a text compare editor is visible"));
79
export const TextCompareEditorActiveContext = new RawContextKey<boolean>('textCompareEditorActive', false, localize('textCompareEditorActive', "Whether a text compare editor is active"));
80
export const SideBySideEditorActiveContext = new RawContextKey<boolean>('sideBySideEditorActive', false, localize('sideBySideEditorActive', "Whether a side by side editor is active"));
81
82
// Editor Group Context Keys
83
export const EditorGroupEditorsCountContext = new RawContextKey<number>('groupEditorsCount', 0, localize('groupEditorsCount', "The number of opened editor groups"));
84
export const ActiveEditorGroupEmptyContext = new RawContextKey<boolean>('activeEditorGroupEmpty', false, localize('activeEditorGroupEmpty', "Whether the active editor group is empty"));
85
export const ActiveEditorGroupIndexContext = new RawContextKey<number>('activeEditorGroupIndex', 0, localize('activeEditorGroupIndex', "The index of the active editor group"));
86
export const ActiveEditorGroupLastContext = new RawContextKey<boolean>('activeEditorGroupLast', false, localize('activeEditorGroupLast', "Whether the active editor group is the last group"));
87
export const ActiveEditorGroupLockedContext = new RawContextKey<boolean>('activeEditorGroupLocked', false, localize('activeEditorGroupLocked', "Whether the active editor group is locked"));
88
export const MultipleEditorGroupsContext = new RawContextKey<boolean>('multipleEditorGroups', false, localize('multipleEditorGroups', "Whether there are multiple editor groups opened"));
89
export const SingleEditorGroupsContext = MultipleEditorGroupsContext.toNegated();
90
export const MultipleEditorsSelectedInGroupContext = new RawContextKey<boolean>('multipleEditorsSelectedInGroup', false, localize('multipleEditorsSelectedInGroup', "Whether multiple editors have been selected in an editor group"));
91
export const TwoEditorsSelectedInGroupContext = new RawContextKey<boolean>('twoEditorsSelectedInGroup', false, localize('twoEditorsSelectedInGroup', "Whether exactly two editors have been selected in an editor group"));
92
export const SelectedEditorsInGroupFileOrUntitledResourceContextKey = new RawContextKey<boolean>('SelectedEditorsInGroupFileOrUntitledResourceContextKey', true, localize('SelectedEditorsInGroupFileOrUntitledResourceContextKey', "Whether all selected editors in a group have a file or untitled resource associated"));
93
94
// Editor Part Context Keys
95
export const EditorPartMultipleEditorGroupsContext = new RawContextKey<boolean>('editorPartMultipleEditorGroups', false, localize('editorPartMultipleEditorGroups', "Whether there are multiple editor groups opened in an editor part"));
96
export const EditorPartSingleEditorGroupsContext = EditorPartMultipleEditorGroupsContext.toNegated();
97
export const EditorPartMaximizedEditorGroupContext = new RawContextKey<boolean>('editorPartMaximizedEditorGroup', false, localize('editorPartEditorGroupMaximized', "Editor Part has a maximized group"));
98
export const EditorPartModalContext = new RawContextKey<boolean>('editorPartModal', false, localize('editorPartModal', "Whether focus is in a modal editor part"));
99
100
// Editor Layout Context Keys
101
export const EditorsVisibleContext = new RawContextKey<boolean>('editorIsOpen', false, localize('editorIsOpen', "Whether an editor is open"));
102
export const InEditorZenModeContext = new RawContextKey<boolean>('inZenMode', false, localize('inZenMode', "Whether Zen mode is enabled"));
103
export const IsMainEditorCenteredLayoutContext = new RawContextKey<boolean>('isCenteredLayout', false, localize('isMainEditorCenteredLayout', "Whether centered layout is enabled for the main editor"));
104
export const SplitEditorsVertically = new RawContextKey<boolean>('splitEditorsVertically', false, localize('splitEditorsVertically', "Whether editors split vertically"));
105
export const MainEditorAreaVisibleContext = new RawContextKey<boolean>('mainEditorAreaVisible', true, localize('mainEditorAreaVisible', "Whether the editor area in the main window is visible"));
106
export const EditorTabsVisibleContext = new RawContextKey<boolean>('editorTabsVisible', true, localize('editorTabsVisible', "Whether editor tabs are visible"));
107
108
//#endregion
109
110
111
//#region < --- Side Bar --- >
112
113
export const SideBarVisibleContext = new RawContextKey<boolean>('sideBarVisible', false, localize('sideBarVisible', "Whether the sidebar is visible"));
114
export const SidebarFocusContext = new RawContextKey<boolean>('sideBarFocus', false, localize('sideBarFocus', "Whether the sidebar has keyboard focus"));
115
export const ActiveViewletContext = new RawContextKey<string>('activeViewlet', '', localize('activeViewlet', "The identifier of the active viewlet"));
116
117
//#endregion
118
119
120
//#region < --- Status Bar --- >
121
122
export const StatusBarFocused = new RawContextKey<boolean>('statusBarFocused', false, localize('statusBarFocused', "Whether the status bar has keyboard focus"));
123
124
//#endregion
125
126
//#region < --- Title Bar --- >
127
128
export const TitleBarStyleContext = new RawContextKey<string>('titleBarStyle', 'custom', localize('titleBarStyle', "Style of the window title bar"));
129
export const TitleBarVisibleContext = new RawContextKey<boolean>('titleBarVisible', false, localize('titleBarVisible', "Whether the title bar is visible"));
130
export const IsCompactTitleBarContext = new RawContextKey<boolean>('isCompactTitleBar', false, localize('isCompactTitleBar', "Title bar is in compact mode"));
131
132
//#endregion
133
134
135
//#region < --- Banner --- >
136
137
export const BannerFocused = new RawContextKey<boolean>('bannerFocused', false, localize('bannerFocused', "Whether the banner has keyboard focus"));
138
139
//#endregion
140
141
142
//#region < --- Notifications --- >
143
144
export const NotificationFocusedContext = new RawContextKey<boolean>('notificationFocus', true, localize('notificationFocus', "Whether a notification has keyboard focus"));
145
export const NotificationsCenterVisibleContext = new RawContextKey<boolean>('notificationCenterVisible', false, localize('notificationCenterVisible', "Whether the notifications center is visible"));
146
export const NotificationsToastsVisibleContext = new RawContextKey<boolean>('notificationToastsVisible', false, localize('notificationToastsVisible', "Whether a notification toast is visible"));
147
148
//#endregion
149
150
151
//#region < --- Auxiliary Bar --- >
152
153
export const ActiveAuxiliaryContext = new RawContextKey<string>('activeAuxiliary', '', localize('activeAuxiliary', "The identifier of the active auxiliary panel"));
154
export const AuxiliaryBarFocusContext = new RawContextKey<boolean>('auxiliaryBarFocus', false, localize('auxiliaryBarFocus', "Whether the auxiliary bar has keyboard focus"));
155
export const AuxiliaryBarVisibleContext = new RawContextKey<boolean>('auxiliaryBarVisible', false, localize('auxiliaryBarVisible', "Whether the auxiliary bar is visible"));
156
export const AuxiliaryBarMaximizedContext = new RawContextKey<boolean>('auxiliaryBarMaximized', false, localize('auxiliaryBarMaximized', "Whether the auxiliary bar is maximized"));
157
158
//#endregion
159
160
161
//#region < --- Panel --- >
162
163
export const ActivePanelContext = new RawContextKey<string>('activePanel', '', localize('activePanel', "The identifier of the active panel"));
164
export const PanelFocusContext = new RawContextKey<boolean>('panelFocus', false, localize('panelFocus', "Whether the panel has keyboard focus"));
165
export const PanelPositionContext = new RawContextKey<string>('panelPosition', 'bottom', localize('panelPosition', "The position of the panel, always 'bottom'"));
166
export const PanelAlignmentContext = new RawContextKey<string>('panelAlignment', 'center', localize('panelAlignment', "The alignment of the panel, either 'center', 'left', 'right' or 'justify'"));
167
export const PanelVisibleContext = new RawContextKey<boolean>('panelVisible', false, localize('panelVisible', "Whether the panel is visible"));
168
export const PanelMaximizedContext = new RawContextKey<boolean>('panelMaximized', false, localize('panelMaximized', "Whether the panel is maximized"));
169
170
//#endregion
171
172
173
//#region < --- Views --- >
174
175
export const FocusedViewContext = new RawContextKey<string>('focusedView', '', localize('focusedView', "The identifier of the view that has keyboard focus"));
176
export function getVisbileViewContextKey(viewId: string): string { return `view.${viewId}.visible`; }
177
178
//#endregion
179
180
181
//#region < --- Resources --- >
182
183
abstract class AbstractResourceContextKey {
184
185
// NOTE: DO NOT CHANGE THE DEFAULT VALUE TO ANYTHING BUT
186
// UNDEFINED! IT IS IMPORTANT THAT DEFAULTS ARE INHERITED
187
// FROM THE PARENT CONTEXT AND ONLY UNDEFINED DOES THIS
188
189
static readonly Scheme = new RawContextKey<string>('resourceScheme', undefined, { type: 'string', description: localize('resourceScheme', "The scheme of the resource") });
190
static readonly Filename = new RawContextKey<string>('resourceFilename', undefined, { type: 'string', description: localize('resourceFilename', "The file name of the resource") });
191
static readonly Dirname = new RawContextKey<string>('resourceDirname', undefined, { type: 'string', description: localize('resourceDirname', "The folder name the resource is contained in") });
192
static readonly Path = new RawContextKey<string>('resourcePath', undefined, { type: 'string', description: localize('resourcePath', "The full path of the resource") });
193
static readonly LangId = new RawContextKey<string>('resourceLangId', undefined, { type: 'string', description: localize('resourceLangId', "The language identifier of the resource") });
194
static readonly Resource = new RawContextKey<string>('resource', undefined, { type: 'URI', description: localize('resource', "The full value of the resource including scheme and path") });
195
static readonly Extension = new RawContextKey<string>('resourceExtname', undefined, { type: 'string', description: localize('resourceExtname', "The extension name of the resource") });
196
static readonly HasResource = new RawContextKey<boolean>('resourceSet', undefined, { type: 'boolean', description: localize('resourceSet', "Whether a resource is present or not") });
197
static readonly IsFileSystemResource = new RawContextKey<boolean>('isFileSystemResource', undefined, { type: 'boolean', description: localize('isFileSystemResource', "Whether the resource is backed by a file system provider") });
198
199
protected _value: URI | undefined;
200
protected readonly _resourceKey: IContextKey<string | null>;
201
protected readonly _schemeKey: IContextKey<string | null>;
202
protected readonly _filenameKey: IContextKey<string | null>;
203
protected readonly _dirnameKey: IContextKey<string | null>;
204
protected readonly _pathKey: IContextKey<string | null>;
205
protected readonly _langIdKey: IContextKey<string | null>;
206
protected readonly _extensionKey: IContextKey<string | null>;
207
protected readonly _hasResource: IContextKey<boolean>;
208
protected readonly _isFileSystemResource: IContextKey<boolean>;
209
210
constructor(
211
@IContextKeyService protected readonly _contextKeyService: IContextKeyService,
212
@IFileService protected readonly _fileService: IFileService,
213
@ILanguageService protected readonly _languageService: ILanguageService,
214
@IModelService protected readonly _modelService: IModelService
215
) {
216
this._schemeKey = AbstractResourceContextKey.Scheme.bindTo(this._contextKeyService);
217
this._filenameKey = AbstractResourceContextKey.Filename.bindTo(this._contextKeyService);
218
this._dirnameKey = AbstractResourceContextKey.Dirname.bindTo(this._contextKeyService);
219
this._pathKey = AbstractResourceContextKey.Path.bindTo(this._contextKeyService);
220
this._langIdKey = AbstractResourceContextKey.LangId.bindTo(this._contextKeyService);
221
this._resourceKey = AbstractResourceContextKey.Resource.bindTo(this._contextKeyService);
222
this._extensionKey = AbstractResourceContextKey.Extension.bindTo(this._contextKeyService);
223
this._hasResource = AbstractResourceContextKey.HasResource.bindTo(this._contextKeyService);
224
this._isFileSystemResource = AbstractResourceContextKey.IsFileSystemResource.bindTo(this._contextKeyService);
225
}
226
227
protected _setLangId(): void {
228
const value = this.get();
229
if (!value) {
230
this._langIdKey.set(null);
231
return;
232
}
233
const langId = this._modelService.getModel(value)?.getLanguageId() ?? this._languageService.guessLanguageIdByFilepathOrFirstLine(value);
234
this._langIdKey.set(langId);
235
}
236
237
set(value: URI | null | undefined) {
238
value = value ?? undefined;
239
if (isEqual(this._value, value)) {
240
return;
241
}
242
this._value = value;
243
this._contextKeyService.bufferChangeEvents(() => {
244
this._resourceKey.set(value ? value.toString() : null);
245
this._schemeKey.set(value ? value.scheme : null);
246
this._filenameKey.set(value ? basename(value) : null);
247
this._dirnameKey.set(value ? this.uriToPath(dirname(value)) : null);
248
this._pathKey.set(value ? this.uriToPath(value) : null);
249
this._setLangId();
250
this._extensionKey.set(value ? extname(value) : null);
251
this._hasResource.set(Boolean(value));
252
this._isFileSystemResource.set(value ? this._fileService.hasProvider(value) : false);
253
});
254
}
255
256
protected uriToPath(uri: URI): string {
257
if (uri.scheme === Schemas.file) {
258
return uri.fsPath;
259
}
260
return uri.path;
261
}
262
263
reset(): void {
264
this._value = undefined;
265
this._contextKeyService.bufferChangeEvents(() => {
266
this._resourceKey.reset();
267
this._schemeKey.reset();
268
this._filenameKey.reset();
269
this._dirnameKey.reset();
270
this._pathKey.reset();
271
this._langIdKey.reset();
272
this._extensionKey.reset();
273
this._hasResource.reset();
274
this._isFileSystemResource.reset();
275
});
276
}
277
278
get(): URI | undefined {
279
return this._value;
280
}
281
}
282
283
export class ResourceContextKey extends AbstractResourceContextKey {
284
285
private readonly _disposables = new DisposableStore();
286
287
constructor(
288
@IContextKeyService contextKeyService: IContextKeyService,
289
@IFileService fileService: IFileService,
290
@ILanguageService languageService: ILanguageService,
291
@IModelService modelService: IModelService
292
) {
293
super(contextKeyService, fileService, languageService, modelService);
294
this._disposables.add(fileService.onDidChangeFileSystemProviderRegistrations(() => {
295
const resource = this.get();
296
this._isFileSystemResource.set(Boolean(resource && fileService.hasProvider(resource)));
297
}));
298
this._disposables.add(modelService.onModelAdded(model => {
299
if (isEqual(model.uri, this.get())) {
300
this._setLangId();
301
}
302
}));
303
this._disposables.add(modelService.onModelLanguageChanged(e => {
304
if (isEqual(e.model.uri, this.get())) {
305
this._setLangId();
306
}
307
}));
308
}
309
310
dispose(): void {
311
this._disposables.dispose();
312
}
313
}
314
315
/**
316
* This is a version of ResourceContextKey that is not disposable and has no listeners for model change events.
317
* It will configure itself for the state/presence of a model only when created and not update.
318
*/
319
export class StaticResourceContextKey extends AbstractResourceContextKey { }
320
321
322
//#endregion
323
324
export function applyAvailableEditorIds(contextKey: IContextKey<string>, editor: EditorInput | undefined | null, editorResolverService: IEditorResolverService): void {
325
if (!editor) {
326
contextKey.set('');
327
return;
328
}
329
330
const editors = getAvailableEditorIds(editor, editorResolverService);
331
contextKey.set(editors.join(','));
332
}
333
334
function getAvailableEditorIds(editor: EditorInput, editorResolverService: IEditorResolverService): string[] {
335
// Non text editor untitled files cannot be easily serialized between
336
// extensions so instead we disable this context key to prevent common
337
// commands that act on the active editor.
338
if (editor.resource?.scheme === Schemas.untitled && editor.editorId !== DEFAULT_EDITOR_ASSOCIATION.id) {
339
return [];
340
}
341
342
// Diff editors. The original and modified resources of a diff editor
343
// *should* be the same, but calculate the set intersection just to be safe.
344
if (editor instanceof DiffEditorInput) {
345
const original = getAvailableEditorIds(editor.original, editorResolverService);
346
const modified = new Set(getAvailableEditorIds(editor.modified, editorResolverService));
347
return original.filter(editor => modified.has(editor));
348
}
349
350
// Normal editors.
351
if (editor.resource) {
352
return editorResolverService.getEditors(editor.resource).map(editor => editor.id);
353
}
354
355
return [];
356
}
357
358