@workbench-kit/shell-react 0.0.2-prototype.0.2.41 → 0.0.2-prototype.0.2.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -2
- package/package.json +13 -10
- package/src/extensions/extension-enablement-controller.ts +40 -9
- package/src/extensions/theme-selection-protection.ts +80 -55
- package/src/field-remap/chrome-labels.ts +18 -0
- package/src/field-remap/convert-note-editor.tsx +30 -24
- package/src/field-remap/convert-palette.tsx +6 -0
- package/src/field-remap/demo.tsx +8 -2
- package/src/field-remap/detail-panel.tsx +225 -192
- package/src/field-remap/drag-payload.ts +48 -0
- package/src/field-remap/flow-adapter.ts +216 -88
- package/src/field-remap/flow-ops.ts +150 -0
- package/src/field-remap/flow.tsx +1055 -162
- package/src/field-remap/index.ts +2 -0
- package/src/field-remap/io-class-browse.tsx +34 -22
- package/src/field-remap/keyboard.ts +16 -0
- package/src/field-remap/modal-detail.tsx +34 -0
- package/src/field-remap/panel.tsx +50 -14
- package/src/field-remap/transform-options-editor.tsx +5 -1
- package/src/field-remap/view.css +61 -42
- package/src/index.ts +7 -0
- package/src/management/keybinding-overrides-storage.ts +48 -23
- package/src/management/keybinding-settings.tsx +10 -1
- package/src/management/use-keybinding-management.ts +69 -19
- package/src/shell/appearance-catalog.ts +453 -0
- package/src/shell/appearance-controller.ts +331 -0
- package/src/shell/appearance-presentation.ts +269 -0
- package/src/shell/provider.tsx +147 -18
- package/src/shell/settings.tsx +282 -153
- package/src/shell/shell.tsx +88 -18
- package/src/workbench/appearance-storage.ts +2 -2
- package/src/workbench/command-host-controller.tsx +223 -0
- package/src/workbench/command-host.tsx +100 -150
- package/src/workbench/keybinding-bridge.ts +84 -38
- package/src/workbench/shell-command-registration.ts +27 -2
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createCommandRegistryFromContributions,
|
|
3
|
-
type CommandRegistry,
|
|
4
|
-
} from '@workbench-kit/platform';
|
|
5
|
-
import {
|
|
6
|
-
WorkbenchCommandPalette,
|
|
7
|
-
WorkbenchQuickOpen,
|
|
8
|
-
WorkbenchShortcutCommandBridge,
|
|
9
2
|
createWorkbenchShellCommands,
|
|
10
3
|
createWorkspaceFilesQuickOpenProvider,
|
|
11
|
-
resolveQuickOpenItemPath,
|
|
12
4
|
type QuickOpenItem,
|
|
13
5
|
type QuickOpenProvider,
|
|
14
6
|
type QuickOpenSelectContext,
|
|
@@ -20,21 +12,23 @@ import {
|
|
|
20
12
|
matchesWorkbenchCommandPaletteShortcut,
|
|
21
13
|
matchesWorkbenchQuickAccessShortcut,
|
|
22
14
|
} from '@workbench-kit/react/workbench/command-ui';
|
|
23
|
-
import {
|
|
15
|
+
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
24
16
|
|
|
25
17
|
import { useContextKeyRevision } from '../commands/use-context-key-revision.js';
|
|
26
18
|
import { useWorkbench } from '../shell/provider.js';
|
|
19
|
+
import { WorkbenchCommandHostController } from './command-host-controller.js';
|
|
27
20
|
import { registerWorkbenchShellCommandHandlers } from './shell-command-registration.js';
|
|
28
21
|
import {
|
|
29
22
|
buildWorkbenchPaletteCommands,
|
|
30
23
|
collectExtensionCommandFeaturesById,
|
|
31
24
|
resolveShellCommandActivities,
|
|
32
25
|
} from './command-palette.js';
|
|
33
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
normalizeExtensionKeybindingCandidates,
|
|
28
|
+
resolveExtensionKeybindingCommand,
|
|
29
|
+
} from './keybinding-bridge.js';
|
|
34
30
|
import { isWorkspaceResourceService, useWorkspaceResourceState } from './workspace-view-state.js';
|
|
35
31
|
|
|
36
|
-
const WORKSPACE_OPEN_COMMAND_ID = 'workspace.open' as const;
|
|
37
|
-
|
|
38
32
|
export interface WorkbenchCommandHostProps {
|
|
39
33
|
additionalCommands?: readonly WorkbenchCommandDescriptor[];
|
|
40
34
|
/** Override command palette close control label (default English). */
|
|
@@ -108,21 +102,55 @@ export function WorkbenchCommandHost({
|
|
|
108
102
|
extensionCatalog,
|
|
109
103
|
keybindings,
|
|
110
104
|
keybindingOverrides,
|
|
105
|
+
keybindingPlatform,
|
|
106
|
+
keybindingProjection,
|
|
111
107
|
layoutService,
|
|
112
108
|
views,
|
|
113
109
|
workspaceHostPort,
|
|
114
110
|
} = useWorkbench();
|
|
115
|
-
const [paletteOpen, setPaletteOpen] = useState(false);
|
|
116
|
-
const [paletteQuery, setPaletteQuery] = useState('');
|
|
117
|
-
const [quickOpenOpen, setQuickOpenOpen] = useState(false);
|
|
118
|
-
const [quickOpenQuery, setQuickOpenQuery] = useState('');
|
|
119
111
|
const [layout, setLayout] = useState(() => layoutService.getState());
|
|
112
|
+
const [extensionKeybindingRevision, setExtensionKeybindingRevision] = useState(
|
|
113
|
+
() => keybindings.revision,
|
|
114
|
+
);
|
|
120
115
|
const shellContextRef = useRef<WorkbenchShellCommandContext | undefined>(undefined);
|
|
121
116
|
const contextKeyRevision = useContextKeyRevision(contextKeyService);
|
|
122
117
|
const contextKeySnapshot = useMemo(
|
|
123
118
|
() => contextKeyService.createSnapshot(),
|
|
124
119
|
[contextKeyRevision, contextKeyService],
|
|
125
120
|
);
|
|
121
|
+
const genericKeybindingCommandIds = useMemo(
|
|
122
|
+
() => new Set(keybindingProjection.defaults.map((binding) => binding.command)),
|
|
123
|
+
[keybindingProjection.defaults],
|
|
124
|
+
);
|
|
125
|
+
useLayoutEffect(() => {
|
|
126
|
+
const disposable = keybindings.onDidChangeKeybindings(() => {
|
|
127
|
+
setExtensionKeybindingRevision(keybindings.revision);
|
|
128
|
+
});
|
|
129
|
+
setExtensionKeybindingRevision(keybindings.revision);
|
|
130
|
+
return () => disposable.dispose();
|
|
131
|
+
}, [keybindings]);
|
|
132
|
+
const extensionOnlyCommandIds = useMemo(() => {
|
|
133
|
+
const commandIds = new Set<string>();
|
|
134
|
+
for (const binding of keybindings.getKeybindings()) {
|
|
135
|
+
if (
|
|
136
|
+
!genericKeybindingCommandIds.has(binding.command) &&
|
|
137
|
+
normalizeExtensionKeybindingCandidates(binding.key, keybindingPlatform, true).length > 0
|
|
138
|
+
) {
|
|
139
|
+
commandIds.add(binding.command);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return commandIds;
|
|
143
|
+
}, [extensionKeybindingRevision, genericKeybindingCommandIds, keybindingPlatform, keybindings]);
|
|
144
|
+
const runtimeKeybindingProjection = useMemo(() => {
|
|
145
|
+
if (!enableExtensionKeybindings) return keybindingProjection;
|
|
146
|
+
|
|
147
|
+
return Object.freeze({
|
|
148
|
+
commands: Object.freeze(
|
|
149
|
+
keybindingProjection.commands.filter((command) => !extensionOnlyCommandIds.has(command.id)),
|
|
150
|
+
),
|
|
151
|
+
defaults: keybindingProjection.defaults,
|
|
152
|
+
});
|
|
153
|
+
}, [enableExtensionKeybindings, extensionOnlyCommandIds, keybindingProjection]);
|
|
126
154
|
|
|
127
155
|
const workspaceService = isWorkspaceResourceService(workspaceHostPort?.service)
|
|
128
156
|
? workspaceHostPort.service
|
|
@@ -176,14 +204,6 @@ export function WorkbenchCommandHost({
|
|
|
176
204
|
[managedShellActivities],
|
|
177
205
|
);
|
|
178
206
|
|
|
179
|
-
const shellCommandRegistry = useMemo(
|
|
180
|
-
() =>
|
|
181
|
-
createCommandRegistryFromContributions<WorkbenchShellCommandContext>([
|
|
182
|
-
{ commands: shellCommandDefinitions },
|
|
183
|
-
]),
|
|
184
|
-
[shellCommandDefinitions],
|
|
185
|
-
);
|
|
186
|
-
|
|
187
207
|
const shellContext = useMemo<WorkbenchShellCommandContext>(
|
|
188
208
|
() => ({
|
|
189
209
|
isFocusModeActive: layoutService.isFocusModeActive(),
|
|
@@ -261,101 +281,16 @@ export function WorkbenchCommandHost({
|
|
|
261
281
|
];
|
|
262
282
|
}, [quickOpenProviders, quickOpenRecentPaths, workspaceService, workspaceState?.files]);
|
|
263
283
|
|
|
264
|
-
const closePalette = useCallback(() => {
|
|
265
|
-
setPaletteOpen(false);
|
|
266
|
-
}, []);
|
|
267
|
-
|
|
268
|
-
const openPalette = useCallback((query = '') => {
|
|
269
|
-
setQuickOpenOpen(false);
|
|
270
|
-
setPaletteQuery(query);
|
|
271
|
-
setPaletteOpen(true);
|
|
272
|
-
}, []);
|
|
273
|
-
|
|
274
|
-
const closeQuickOpen = useCallback(() => {
|
|
275
|
-
setQuickOpenOpen(false);
|
|
276
|
-
}, []);
|
|
277
|
-
|
|
278
|
-
const openQuickOpen = useCallback((query = '') => {
|
|
279
|
-
setPaletteOpen(false);
|
|
280
|
-
setQuickOpenQuery(query);
|
|
281
|
-
setQuickOpenOpen(true);
|
|
282
|
-
}, []);
|
|
283
|
-
|
|
284
|
-
const runPaletteCommand = useCallback(
|
|
285
|
-
(command: WorkbenchCommandDescriptor, context: WorkbenchCommandRunContext) => {
|
|
286
|
-
const finish = () => {
|
|
287
|
-
closePalette();
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
if (onRunCommand?.(command, context)) {
|
|
291
|
-
finish();
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
void executeCommand(command.id).finally(finish);
|
|
296
|
-
},
|
|
297
|
-
[closePalette, executeCommand, onRunCommand],
|
|
298
|
-
);
|
|
299
|
-
|
|
300
|
-
const runQuickOpenItem = useCallback(
|
|
301
|
-
(item: QuickOpenItem, context: QuickOpenSelectContext) => {
|
|
302
|
-
const finish = () => {
|
|
303
|
-
closeQuickOpen();
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
if (onOpenQuickOpenItem?.(item, context)) {
|
|
307
|
-
finish();
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const path = resolveQuickOpenItemPath(item);
|
|
312
|
-
if (!path) {
|
|
313
|
-
finish();
|
|
314
|
-
return;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
void executeCommand(WORKSPACE_OPEN_COMMAND_ID, { path }).finally(finish);
|
|
318
|
-
},
|
|
319
|
-
[closeQuickOpen, executeCommand, onOpenQuickOpenItem],
|
|
320
|
-
);
|
|
321
|
-
|
|
322
284
|
useEffect(() => {
|
|
323
|
-
if (!
|
|
285
|
+
if (!enableExtensionKeybindings) {
|
|
324
286
|
return undefined;
|
|
325
287
|
}
|
|
326
288
|
|
|
327
289
|
const onKeyDown = (event: KeyboardEvent) => {
|
|
328
|
-
if (
|
|
329
|
-
event.preventDefault();
|
|
330
|
-
openPalette('>');
|
|
290
|
+
if (isActiveShortcutCaptureTarget(event)) {
|
|
331
291
|
return;
|
|
332
292
|
}
|
|
333
293
|
|
|
334
|
-
if (matchesWorkbenchQuickAccessShortcut(event)) {
|
|
335
|
-
event.preventDefault();
|
|
336
|
-
if (enableQuickOpen) {
|
|
337
|
-
openQuickOpen();
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
if (enableCommandPalette) {
|
|
342
|
-
openPalette();
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
|
|
347
|
-
window.addEventListener('keydown', onKeyDown);
|
|
348
|
-
return () => {
|
|
349
|
-
window.removeEventListener('keydown', onKeyDown);
|
|
350
|
-
};
|
|
351
|
-
}, [enableCommandPalette, enableQuickOpen, openPalette, openQuickOpen]);
|
|
352
|
-
|
|
353
|
-
useEffect(() => {
|
|
354
|
-
if (!enableExtensionKeybindings) {
|
|
355
|
-
return undefined;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const onKeyDown = (event: KeyboardEvent) => {
|
|
359
294
|
if (
|
|
360
295
|
matchesWorkbenchCommandPaletteShortcut(event) ||
|
|
361
296
|
matchesWorkbenchQuickAccessShortcut(event)
|
|
@@ -363,7 +298,14 @@ export function WorkbenchCommandHost({
|
|
|
363
298
|
return;
|
|
364
299
|
}
|
|
365
300
|
|
|
366
|
-
const match = resolveExtensionKeybindingCommand(
|
|
301
|
+
const match = resolveExtensionKeybindingCommand(
|
|
302
|
+
keybindings,
|
|
303
|
+
event,
|
|
304
|
+
{},
|
|
305
|
+
keybindingOverrides,
|
|
306
|
+
keybindingPlatform,
|
|
307
|
+
genericKeybindingCommandIds,
|
|
308
|
+
);
|
|
367
309
|
if (!match) {
|
|
368
310
|
return;
|
|
369
311
|
}
|
|
@@ -376,45 +318,53 @@ export function WorkbenchCommandHost({
|
|
|
376
318
|
return () => {
|
|
377
319
|
window.removeEventListener('keydown', onKeyDown);
|
|
378
320
|
};
|
|
379
|
-
}, [
|
|
321
|
+
}, [
|
|
322
|
+
enableExtensionKeybindings,
|
|
323
|
+
executeCommand,
|
|
324
|
+
genericKeybindingCommandIds,
|
|
325
|
+
keybindings,
|
|
326
|
+
keybindingOverrides,
|
|
327
|
+
keybindingPlatform,
|
|
328
|
+
]);
|
|
329
|
+
|
|
330
|
+
return (
|
|
331
|
+
<WorkbenchCommandHostController
|
|
332
|
+
commandPaletteCloseLabel={commandPaletteCloseLabel}
|
|
333
|
+
commandPaletteEmptyLabel={commandPaletteEmptyLabel}
|
|
334
|
+
commandPalettePlaceholder={commandPalettePlaceholder}
|
|
335
|
+
commandPaletteTitle={commandPaletteTitle}
|
|
336
|
+
commands={paletteCommands}
|
|
337
|
+
enableCommandPalette={enableCommandPalette}
|
|
338
|
+
enableQuickOpen={enableQuickOpen}
|
|
339
|
+
executeCommand={executeCommand}
|
|
340
|
+
quickOpenCloseLabel={quickOpenCloseLabel}
|
|
341
|
+
quickOpenEmptyLabel={quickOpenEmptyLabel}
|
|
342
|
+
quickOpenPlaceholder={quickOpenPlaceholder}
|
|
343
|
+
quickOpenProviders={resolvedQuickOpenProviders}
|
|
344
|
+
quickOpenTitle={quickOpenTitle}
|
|
345
|
+
shortcutBridge={
|
|
346
|
+
enableShortcutBridge
|
|
347
|
+
? {
|
|
348
|
+
context: undefined,
|
|
349
|
+
keybindingOverrides,
|
|
350
|
+
keybindingProjection: runtimeKeybindingProjection,
|
|
351
|
+
platform: keybindingPlatform,
|
|
352
|
+
preventDefault: true,
|
|
353
|
+
registry: commands,
|
|
354
|
+
}
|
|
355
|
+
: false
|
|
356
|
+
}
|
|
357
|
+
{...(onOpenQuickOpenItem === undefined ? {} : { onOpenQuickOpenItem })}
|
|
358
|
+
{...(onRunCommand === undefined ? {} : { onRunCommand })}
|
|
359
|
+
/>
|
|
360
|
+
);
|
|
361
|
+
}
|
|
380
362
|
|
|
363
|
+
function isActiveShortcutCaptureTarget(event: Event): boolean {
|
|
364
|
+
const target = event.target;
|
|
381
365
|
return (
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
context={shellContext}
|
|
386
|
-
preventDefault
|
|
387
|
-
registry={shellCommandRegistry as CommandRegistry<WorkbenchShellCommandContext>}
|
|
388
|
-
/>
|
|
389
|
-
) : null}
|
|
390
|
-
{enableCommandPalette ? (
|
|
391
|
-
<WorkbenchCommandPalette
|
|
392
|
-
closeLabel={commandPaletteCloseLabel}
|
|
393
|
-
commands={paletteCommands}
|
|
394
|
-
emptyLabel={commandPaletteEmptyLabel}
|
|
395
|
-
open={paletteOpen}
|
|
396
|
-
placeholder={commandPalettePlaceholder}
|
|
397
|
-
query={paletteQuery}
|
|
398
|
-
title={commandPaletteTitle}
|
|
399
|
-
onClose={closePalette}
|
|
400
|
-
onQueryChange={setPaletteQuery}
|
|
401
|
-
onRunCommand={runPaletteCommand}
|
|
402
|
-
/>
|
|
403
|
-
) : null}
|
|
404
|
-
{enableQuickOpen ? (
|
|
405
|
-
<WorkbenchQuickOpen
|
|
406
|
-
closeLabel={quickOpenCloseLabel}
|
|
407
|
-
emptyLabel={quickOpenEmptyLabel}
|
|
408
|
-
open={quickOpenOpen}
|
|
409
|
-
placeholder={quickOpenPlaceholder}
|
|
410
|
-
providers={resolvedQuickOpenProviders}
|
|
411
|
-
query={quickOpenQuery}
|
|
412
|
-
title={quickOpenTitle}
|
|
413
|
-
onClose={closeQuickOpen}
|
|
414
|
-
onQueryChange={setQuickOpenQuery}
|
|
415
|
-
onSelectItem={runQuickOpenItem}
|
|
416
|
-
/>
|
|
417
|
-
) : null}
|
|
418
|
-
</>
|
|
366
|
+
typeof Element !== 'undefined' &&
|
|
367
|
+
target instanceof Element &&
|
|
368
|
+
target.closest('[data-workbench-shortcut-capture-recording="true"]') !== null
|
|
419
369
|
);
|
|
420
370
|
}
|
|
@@ -1,32 +1,21 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import {
|
|
2
|
+
evaluateWhenClause,
|
|
3
|
+
normalizeWorkbenchShortcutCandidates,
|
|
4
|
+
normalizeWorkbenchShortcutFromEvent,
|
|
5
|
+
resolveWorkbenchShortcutPlatform,
|
|
6
|
+
workbenchShortcutsOverlap,
|
|
7
|
+
type ContextKeyValue,
|
|
8
|
+
type KeybindingDefinition,
|
|
9
|
+
type KeybindingMatch,
|
|
10
|
+
type KeybindingRegistry,
|
|
11
|
+
type WorkbenchShortcutPlatform,
|
|
12
|
+
} from '@workbench-kit/platform';
|
|
12
13
|
|
|
13
14
|
export function normalizeKeybindingKeyFromEvent(
|
|
14
15
|
event: Pick<KeyboardEvent, 'altKey' | 'ctrlKey' | 'key' | 'metaKey' | 'shiftKey'>,
|
|
16
|
+
platform: WorkbenchShortcutPlatform = resolveWorkbenchShortcutPlatform(),
|
|
15
17
|
): string {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (event.ctrlKey || event.metaKey) {
|
|
19
|
-
parts.push('ctrl');
|
|
20
|
-
}
|
|
21
|
-
if (event.altKey) {
|
|
22
|
-
parts.push('alt');
|
|
23
|
-
}
|
|
24
|
-
if (event.shiftKey) {
|
|
25
|
-
parts.push('shift');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
parts.push(normalizeKeyToken(event.key));
|
|
29
|
-
return parts.join('+');
|
|
18
|
+
return normalizeWorkbenchShortcutFromEvent(event, platform) ?? '';
|
|
30
19
|
}
|
|
31
20
|
|
|
32
21
|
export function resolveExtensionKeybindingCommand(
|
|
@@ -34,21 +23,78 @@ export function resolveExtensionKeybindingCommand(
|
|
|
34
23
|
event: Pick<KeyboardEvent, 'altKey' | 'ctrlKey' | 'key' | 'metaKey' | 'shiftKey'>,
|
|
35
24
|
contextKeys: Readonly<Record<string, ContextKeyValue>> = {},
|
|
36
25
|
overrides: readonly KeybindingDefinition[] = [],
|
|
37
|
-
)
|
|
38
|
-
|
|
26
|
+
platform: WorkbenchShortcutPlatform = resolveWorkbenchShortcutPlatform(),
|
|
27
|
+
excludedCommandIds: ReadonlySet<string> = new Set(),
|
|
28
|
+
): KeybindingMatch | undefined {
|
|
29
|
+
const key = normalizeKeybindingKeyFromEvent(event, platform);
|
|
30
|
+
if (!key) return undefined;
|
|
39
31
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
32
|
+
const defaults = registry
|
|
33
|
+
.getKeybindings()
|
|
34
|
+
.filter(
|
|
35
|
+
(binding) =>
|
|
36
|
+
!excludedCommandIds.has(binding.command) &&
|
|
37
|
+
normalizeExtensionKeybindingCandidates(binding.key, platform, true).length > 0,
|
|
38
|
+
);
|
|
39
|
+
const ownedCommandIds = new Set(defaults.map((binding) => binding.command));
|
|
40
|
+
const ownedOverrides = overrides.filter((binding) => ownedCommandIds.has(binding.command));
|
|
41
|
+
const overriddenCommands = new Set(ownedOverrides.map((binding) => binding.command));
|
|
42
|
+
const userMatches = ownedOverrides.filter((binding) =>
|
|
43
|
+
bindingMatchesEvent(
|
|
44
|
+
binding,
|
|
44
45
|
key,
|
|
45
46
|
contextKeys,
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
platform,
|
|
48
|
+
binding.when !== undefined || (binding.args?.length ?? 0) > 0,
|
|
49
|
+
),
|
|
50
|
+
);
|
|
51
|
+
const defaultMatches = defaults.filter(
|
|
52
|
+
(binding) =>
|
|
53
|
+
!overriddenCommands.has(binding.command) &&
|
|
54
|
+
bindingMatchesEvent(binding, key, contextKeys, platform, true),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return [...userMatches, ...defaultMatches]
|
|
58
|
+
.map((binding) => ({
|
|
59
|
+
...binding,
|
|
60
|
+
specificity: binding.when ? binding.when.length : 0,
|
|
61
|
+
}))
|
|
62
|
+
.sort((left, right) => right.specificity - left.specificity)[0];
|
|
63
|
+
}
|
|
51
64
|
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
function bindingMatchesEvent(
|
|
66
|
+
binding: KeybindingDefinition,
|
|
67
|
+
eventKey: string,
|
|
68
|
+
contextKeys: Readonly<Record<string, ContextKeyValue>>,
|
|
69
|
+
platform: WorkbenchShortcutPlatform,
|
|
70
|
+
preserveLegacyMacPrimaryCompatibility: boolean,
|
|
71
|
+
): boolean {
|
|
72
|
+
return (
|
|
73
|
+
(workbenchShortcutsOverlap(binding.key, eventKey, platform) ||
|
|
74
|
+
normalizeExtensionKeybindingCandidates(
|
|
75
|
+
binding.key,
|
|
76
|
+
platform,
|
|
77
|
+
preserveLegacyMacPrimaryCompatibility,
|
|
78
|
+
).some((candidate) => workbenchShortcutsOverlap(candidate, eventKey, platform))) &&
|
|
79
|
+
evaluateWhenClause(binding.when, contextKeys)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function normalizeExtensionKeybindingCandidates(
|
|
84
|
+
shortcut: string,
|
|
85
|
+
platform: WorkbenchShortcutPlatform,
|
|
86
|
+
preserveLegacyMacPrimaryCompatibility = false,
|
|
87
|
+
): readonly string[] {
|
|
88
|
+
return normalizeWorkbenchShortcutCandidates(shortcut, platform).flatMap((candidate) => {
|
|
89
|
+
const tokens = candidate.split('+');
|
|
90
|
+
if (
|
|
91
|
+
!preserveLegacyMacPrimaryCompatibility ||
|
|
92
|
+
platform !== 'mac' ||
|
|
93
|
+
!tokens.includes('ctrl') ||
|
|
94
|
+
tokens.includes('meta')
|
|
95
|
+
) {
|
|
96
|
+
return [candidate];
|
|
97
|
+
}
|
|
98
|
+
return [candidate, tokens.map((token) => (token === 'ctrl' ? 'meta' : token)).join('+')];
|
|
99
|
+
});
|
|
54
100
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
resolveCommandValue,
|
|
3
|
+
type CommandDefinition,
|
|
4
|
+
type CommandRegistry,
|
|
5
|
+
} from '@workbench-kit/platform';
|
|
2
6
|
import type { WorkbenchShellCommandContext } from '@workbench-kit/react/workbench';
|
|
3
7
|
|
|
4
8
|
export interface WorkbenchShellCommandRegistration {
|
|
@@ -14,16 +18,34 @@ export function registerWorkbenchShellCommandHandlers(
|
|
|
14
18
|
const handler = () => {
|
|
15
19
|
command.run?.(getContext());
|
|
16
20
|
};
|
|
21
|
+
const isEnabled = command.isEnabled
|
|
22
|
+
? () => command.isEnabled?.(getContext()) ?? true
|
|
23
|
+
: undefined;
|
|
24
|
+
const run = () => {
|
|
25
|
+
command.run?.(getContext());
|
|
26
|
+
};
|
|
27
|
+
const shortcut = resolveCommandValue(command.shortcut, getContext());
|
|
17
28
|
const existing = registry.getCommand(command.id);
|
|
18
29
|
|
|
19
30
|
if (existing) {
|
|
20
31
|
const previousHandler = existing.handler;
|
|
32
|
+
const previousIsEnabled = existing.isEnabled;
|
|
33
|
+
const previousRun = existing.run;
|
|
34
|
+
const previousShortcut = existing.shortcut;
|
|
21
35
|
existing.handler = handler;
|
|
36
|
+
existing.isEnabled = isEnabled;
|
|
37
|
+
existing.run = run;
|
|
38
|
+
existing.shortcut = shortcut;
|
|
39
|
+
registry.notifyCommandChanged(command.id);
|
|
22
40
|
|
|
23
41
|
return {
|
|
24
42
|
dispose() {
|
|
25
|
-
if (existing.handler === handler) {
|
|
43
|
+
if (registry.getCommand(command.id) === existing && existing.handler === handler) {
|
|
26
44
|
existing.handler = previousHandler;
|
|
45
|
+
existing.isEnabled = previousIsEnabled;
|
|
46
|
+
existing.run = previousRun;
|
|
47
|
+
existing.shortcut = previousShortcut;
|
|
48
|
+
registry.notifyCommandChanged(command.id);
|
|
27
49
|
}
|
|
28
50
|
},
|
|
29
51
|
};
|
|
@@ -34,6 +56,9 @@ export function registerWorkbenchShellCommandHandlers(
|
|
|
34
56
|
handler,
|
|
35
57
|
icon: resolveStaticCommandIcon(command),
|
|
36
58
|
id: command.id,
|
|
59
|
+
isEnabled,
|
|
60
|
+
run,
|
|
61
|
+
shortcut,
|
|
37
62
|
title: resolveStaticCommandTitle(command),
|
|
38
63
|
});
|
|
39
64
|
});
|