@workbench-kit/shell-react 0.0.2-prototype.0.2.32 → 0.0.2-prototype.0.2.34
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 +32 -0
- package/package.json +9 -9
- package/src/commands/use-command-descriptors.ts +7 -3
- package/src/commands/use-extension-registry-command-descriptors.ts +23 -6
- package/src/devtools/use-workbench-devtools-snapshot.ts +39 -14
- package/src/devtools/workbench-devtools-snapshot.ts +32 -13
- package/src/editor/area.tsx +3 -2
- package/src/editor/state-storage.ts +31 -0
- package/src/editor/tab-context-menu.ts +8 -8
- package/src/editor/use-editor.ts +6 -6
- package/src/explorer/context-menu.ts +8 -4
- package/src/explorer/view.tsx +4 -3
- package/src/extensions/canonical-extension-descriptions.ts +58 -0
- package/src/extensions/context-menu.ts +9 -6
- package/src/extensions/extension-enablement-context.ts +15 -0
- package/src/extensions/extension-enablement-controller.ts +453 -0
- package/src/extensions/management-model.ts +111 -47
- package/src/extensions/theme-selection-protection.ts +98 -0
- package/src/extensions/uninstall-eligibility.ts +103 -0
- package/src/extensions/use-extension-management.ts +151 -67
- package/src/extensions/view.tsx +4 -0
- package/src/field-remap/chrome-labels.ts +87 -2
- package/src/field-remap/convert-palette.tsx +164 -18
- package/src/field-remap/demo.tsx +48 -3
- package/src/field-remap/detail-panel.tsx +6 -5
- package/src/field-remap/flow.tsx +341 -155
- package/src/field-remap/history.ts +99 -0
- package/src/field-remap/index.ts +9 -1
- package/src/field-remap/panel.tsx +388 -97
- package/src/field-remap/preview-controller.ts +122 -0
- package/src/field-remap/preview.tsx +171 -0
- package/src/field-remap/view.css +154 -2
- package/src/index.ts +16 -1
- package/src/management/keybinding-overrides-storage.ts +28 -0
- package/src/management/preference-settings-storage.ts +28 -0
- package/src/management/settings.tsx +2 -0
- package/src/management/use-command-management.ts +31 -26
- package/src/management/use-keybinding-management.ts +25 -12
- package/src/shell/focused-extension-services.ts +138 -0
- package/src/shell/host-shell.tsx +13 -10
- package/src/shell/persistence-diagnostic-context.ts +11 -0
- package/src/shell/provider.tsx +373 -69
- package/src/shell/settings.tsx +25 -16
- package/src/shell/shell.tsx +119 -78
- package/src/shell/view-host.tsx +23 -22
- package/src/storage/local-json-storage.ts +43 -29
- package/src/storage/persistence-diagnostics.ts +72 -0
- package/src/workbench/appearance-storage.ts +28 -0
- package/src/workbench/command-host.tsx +19 -22
- package/src/workbench/command-palette.ts +14 -13
- package/src/workbench/layout-storage.ts +52 -5
- package/src/workbench/use-persisted-appearance.ts +38 -12
package/README.md
CHANGED
|
@@ -51,6 +51,23 @@ registry can use `registry-command-descriptors` without importing Provider
|
|
|
51
51
|
context into that leaf bundle. The root barrel remains the discovery surface,
|
|
52
52
|
not the default runtime import graph.
|
|
53
53
|
|
|
54
|
+
### Focused extension context migration
|
|
55
|
+
|
|
56
|
+
`WorkbenchContextValue` no longer exposes the aggregate `ExtensionRegistry`.
|
|
57
|
+
Consumers that read Provider context use the focused `commands`, `menus`,
|
|
58
|
+
`extensionActivation`, `extensionActivationState`, `extensionCatalog`, and
|
|
59
|
+
`settingsCapabilityPublisher` fields instead. The focused contract types remain
|
|
60
|
+
available from the package root for external TypeScript consumers.
|
|
61
|
+
|
|
62
|
+
Hosts that explicitly own an `ExtensionRegistry` can continue passing that
|
|
63
|
+
instance to `useExtensionRegistryCommandDescriptors(registry, ...)`; this
|
|
64
|
+
host-composition hook is separate from Provider context and remains supported.
|
|
65
|
+
|
|
66
|
+
`WorkbenchShell` command hosts receive a focused `openSettings(categoryId?)`
|
|
67
|
+
control in their `onRunCommand` context. Use that host-composition seam for
|
|
68
|
+
commands that open a specific settings category without reading an aggregate
|
|
69
|
+
registry or capability map.
|
|
70
|
+
|
|
54
71
|
Use `host-shell` when the product owns sidebar, editor, panel, and overlay content.
|
|
55
72
|
It keeps Kit layout, Activity Bar ordering, resize persistence, and status routing
|
|
56
73
|
without loading the full Settings/Profile/Help assembly. Use `shell` for the
|
|
@@ -94,6 +111,21 @@ import '@workbench-kit/shell-react/field-remap/view.css';
|
|
|
94
111
|
for Flow-only embeds and custom bundler setups. The full barrel
|
|
95
112
|
`import { FieldRemapPanel } from '@workbench-kit/shell-react'` stays supported.
|
|
96
113
|
|
|
114
|
+
### Semantic history ownership
|
|
115
|
+
|
|
116
|
+
`FieldRemapPanel` keeps a private composite `{ edges, operators }` undo/redo stack only
|
|
117
|
+
when both durable channels are uncontrolled. If either channel is controlled, pass one
|
|
118
|
+
`historyOwner` for the complete composite state; the Panel never creates a partial stack.
|
|
119
|
+
`historyActionsRef` exposes host-chrome actions and
|
|
120
|
+
`onHistoryAvailabilityChange` reports whether those actions are available. Keyboard
|
|
121
|
+
routing remains host-owned.
|
|
122
|
+
|
|
123
|
+
Only semantic edits coming from the Flow mapper create entries. Hidden mappings are
|
|
124
|
+
reconstructed before an entry is recorded, so undo does not discard filtered state.
|
|
125
|
+
Shape apply or external source/target replacement prunes invalid mappings and resets
|
|
126
|
+
past/future without adding a history entry. Draft placement, selection, viewport, and
|
|
127
|
+
detail-panel state stay outside this history.
|
|
128
|
+
|
|
97
129
|
### Flow host chrome hooks
|
|
98
130
|
|
|
99
131
|
`FieldRemapFlowMapper` (and `FieldRemapPanel` pass-through) accept optional chrome
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workbench-kit/shell-react",
|
|
3
|
-
"version": "0.0.2-prototype.0.2.
|
|
3
|
+
"version": "0.0.2-prototype.0.2.34",
|
|
4
4
|
"private": false,
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css"
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"@radix-ui/react-slot": "^1.3.0",
|
|
32
32
|
"@xyflow/react": "^12.11.2",
|
|
33
33
|
"jsonata": "^2.2.0",
|
|
34
|
-
"@workbench-kit/platform": "0.0.2-prototype.0.2.
|
|
35
|
-
"@workbench-kit/field-remap": "0.0.2-prototype.0.2.
|
|
36
|
-
"@workbench-kit/
|
|
37
|
-
"@workbench-kit/
|
|
38
|
-
"@workbench-kit/workbench-
|
|
39
|
-
"@workbench-kit/
|
|
40
|
-
"@workbench-kit/
|
|
41
|
-
"@workbench-kit/workspace": "0.0.2-prototype.0.2.
|
|
34
|
+
"@workbench-kit/platform": "0.0.2-prototype.0.2.34",
|
|
35
|
+
"@workbench-kit/field-remap": "0.0.2-prototype.0.2.34",
|
|
36
|
+
"@workbench-kit/workbench-core": "0.0.2-prototype.0.2.34",
|
|
37
|
+
"@workbench-kit/react": "0.0.2-prototype.0.2.34",
|
|
38
|
+
"@workbench-kit/workbench-config": "0.0.2-prototype.0.2.34",
|
|
39
|
+
"@workbench-kit/tokens": "0.0.2-prototype.0.2.34",
|
|
40
|
+
"@workbench-kit/workbench-extension-sdk": "0.0.2-prototype.0.2.34",
|
|
41
|
+
"@workbench-kit/workspace": "0.0.2-prototype.0.2.34"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"react": "^19.0.0",
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { WorkbenchCommandDescriptor } from '@workbench-kit/react/workbench';
|
|
2
2
|
|
|
3
3
|
import { useWorkbench } from '../shell/provider.js';
|
|
4
|
-
import {
|
|
4
|
+
import { useCommandRegistryCommandDescriptors } from './use-extension-registry-command-descriptors.js';
|
|
5
5
|
|
|
6
6
|
const EMPTY_COMMAND_DESCRIPTORS: readonly WorkbenchCommandDescriptor[] = [];
|
|
7
7
|
|
|
8
8
|
export function useWorkbenchCommandDescriptors(
|
|
9
9
|
additionalCommands: readonly WorkbenchCommandDescriptor[] = EMPTY_COMMAND_DESCRIPTORS,
|
|
10
10
|
) {
|
|
11
|
-
const {
|
|
12
|
-
return
|
|
11
|
+
const { commands, extensionCatalog } = useWorkbench();
|
|
12
|
+
return useCommandRegistryCommandDescriptors(
|
|
13
|
+
commands,
|
|
14
|
+
extensionCatalog.getFeatureSpecs(),
|
|
15
|
+
additionalCommands,
|
|
16
|
+
);
|
|
13
17
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { WorkbenchCommandDescriptor } from '@workbench-kit/react/workbench';
|
|
2
|
-
import type {
|
|
2
|
+
import type { CommandRegistry } from '@workbench-kit/platform';
|
|
3
|
+
import type { ExtensionFeatureSpec, ExtensionRegistry } from '@workbench-kit/workbench-core';
|
|
3
4
|
import { useEffect, useMemo, useReducer } from 'react';
|
|
4
5
|
|
|
5
6
|
import {
|
|
@@ -18,29 +19,45 @@ const EMPTY_COMMAND_DESCRIPTORS: readonly WorkbenchCommandDescriptor[] = [];
|
|
|
18
19
|
export function useExtensionRegistryCommandDescriptors(
|
|
19
20
|
extensionRegistry: ExtensionRegistry,
|
|
20
21
|
additionalCommands: readonly WorkbenchCommandDescriptor[] = EMPTY_COMMAND_DESCRIPTORS,
|
|
22
|
+
): readonly WorkbenchCommandDescriptor[] {
|
|
23
|
+
return useCommandRegistryCommandDescriptors(
|
|
24
|
+
extensionRegistry.commands,
|
|
25
|
+
extensionRegistry.getFeatureSpecs(),
|
|
26
|
+
additionalCommands,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function useCommandRegistryCommandDescriptors(
|
|
31
|
+
commands: CommandRegistry,
|
|
32
|
+
featureSpecs: readonly ExtensionFeatureSpec[],
|
|
33
|
+
additionalCommands: readonly WorkbenchCommandDescriptor[] = EMPTY_COMMAND_DESCRIPTORS,
|
|
21
34
|
): readonly WorkbenchCommandDescriptor[] {
|
|
22
35
|
const [refreshToken, refreshCommands] = useReducer((count: number) => count + 1, 0);
|
|
23
36
|
|
|
24
37
|
useEffect(() => {
|
|
25
|
-
const disposable =
|
|
38
|
+
const disposable = commands.onDidChangeCommands(() => {
|
|
26
39
|
refreshCommands();
|
|
27
40
|
});
|
|
41
|
+
// A host may register commands in a layout effect after this hook rendered
|
|
42
|
+
// but before its passive subscription was installed. Re-read once after
|
|
43
|
+
// subscribing so that transition cannot leave the memoized snapshot stale.
|
|
44
|
+
refreshCommands();
|
|
28
45
|
|
|
29
46
|
return () => {
|
|
30
47
|
disposable.dispose();
|
|
31
48
|
};
|
|
32
|
-
}, [
|
|
49
|
+
}, [commands]);
|
|
33
50
|
|
|
34
51
|
return useMemo(() => {
|
|
35
|
-
const commandFeaturesById = collectExtensionCommandFeaturesById(
|
|
52
|
+
const commandFeaturesById = collectExtensionCommandFeaturesById(featureSpecs);
|
|
36
53
|
|
|
37
54
|
return mergeWorkbenchCommandDescriptors(
|
|
38
|
-
|
|
55
|
+
commands
|
|
39
56
|
.getCommands()
|
|
40
57
|
.map((command) =>
|
|
41
58
|
extensionCommandToDescriptor(command, commandFeaturesById.get(command.id)),
|
|
42
59
|
),
|
|
43
60
|
[...additionalCommands],
|
|
44
61
|
);
|
|
45
|
-
}, [additionalCommands,
|
|
62
|
+
}, [additionalCommands, commands, featureSpecs, refreshToken]);
|
|
46
63
|
}
|
|
@@ -8,14 +8,31 @@ import { useWorkbench } from '../shell/provider.js';
|
|
|
8
8
|
import type { WorkbenchWorkspaceHostPort as WorkspaceHostPort } from '@workbench-kit/workspace';
|
|
9
9
|
|
|
10
10
|
export function useWorkbenchDevtoolsSnapshot(): WorkbenchDevtoolsSnapshot {
|
|
11
|
-
const {
|
|
11
|
+
const {
|
|
12
|
+
activities,
|
|
13
|
+
commands,
|
|
14
|
+
editorService,
|
|
15
|
+
extensionActivationState,
|
|
16
|
+
extensionCatalog,
|
|
17
|
+
keybindings,
|
|
18
|
+
layoutService,
|
|
19
|
+
menus,
|
|
20
|
+
views,
|
|
21
|
+
workspaceHostPort,
|
|
22
|
+
} = useWorkbench();
|
|
12
23
|
|
|
13
24
|
const store = useMemo(() => {
|
|
14
25
|
const collectSnapshot = () =>
|
|
15
26
|
collectWorkbenchDevtoolsSnapshot({
|
|
27
|
+
activities,
|
|
28
|
+
commands,
|
|
16
29
|
editorService,
|
|
17
|
-
|
|
30
|
+
extensionActivationState,
|
|
31
|
+
extensionCatalog,
|
|
32
|
+
keybindings,
|
|
18
33
|
layoutService,
|
|
34
|
+
menus,
|
|
35
|
+
views,
|
|
19
36
|
workspaceHostPort,
|
|
20
37
|
});
|
|
21
38
|
let snapshot = collectSnapshot();
|
|
@@ -35,31 +52,28 @@ export function useWorkbenchDevtoolsSnapshot(): WorkbenchDevtoolsSnapshot {
|
|
|
35
52
|
editorService.onDidChangeEditors(() => {
|
|
36
53
|
notifyChange(onStoreChange);
|
|
37
54
|
}),
|
|
38
|
-
|
|
55
|
+
commands.onDidChangeCommands(() => {
|
|
39
56
|
notifyChange(onStoreChange);
|
|
40
57
|
}),
|
|
41
|
-
|
|
58
|
+
menus.onDidRegisterMenuItem(() => {
|
|
42
59
|
notifyChange(onStoreChange);
|
|
43
60
|
}),
|
|
44
|
-
|
|
61
|
+
keybindings.onDidRegisterKeybinding(() => {
|
|
45
62
|
notifyChange(onStoreChange);
|
|
46
63
|
}),
|
|
47
|
-
|
|
64
|
+
views.onDidRegisterView(() => {
|
|
48
65
|
notifyChange(onStoreChange);
|
|
49
66
|
}),
|
|
50
|
-
|
|
67
|
+
views.onDidRegisterViewContainer(() => {
|
|
51
68
|
notifyChange(onStoreChange);
|
|
52
69
|
}),
|
|
53
|
-
|
|
70
|
+
views.onDidRegisterViewProvider(() => {
|
|
54
71
|
notifyChange(onStoreChange);
|
|
55
72
|
}),
|
|
56
|
-
|
|
73
|
+
activities.onDidRegisterActivity(() => {
|
|
57
74
|
notifyChange(onStoreChange);
|
|
58
75
|
}),
|
|
59
|
-
|
|
60
|
-
notifyChange(onStoreChange);
|
|
61
|
-
}),
|
|
62
|
-
extensionRegistry.onDidDeactivateExtension(() => {
|
|
76
|
+
extensionActivationState.onDidChangeActiveExtensions(() => {
|
|
63
77
|
notifyChange(onStoreChange);
|
|
64
78
|
}),
|
|
65
79
|
];
|
|
@@ -78,7 +92,18 @@ export function useWorkbenchDevtoolsSnapshot(): WorkbenchDevtoolsSnapshot {
|
|
|
78
92
|
};
|
|
79
93
|
},
|
|
80
94
|
};
|
|
81
|
-
}, [
|
|
95
|
+
}, [
|
|
96
|
+
activities,
|
|
97
|
+
commands,
|
|
98
|
+
editorService,
|
|
99
|
+
extensionActivationState,
|
|
100
|
+
extensionCatalog,
|
|
101
|
+
keybindings,
|
|
102
|
+
layoutService,
|
|
103
|
+
menus,
|
|
104
|
+
views,
|
|
105
|
+
workspaceHostPort,
|
|
106
|
+
]);
|
|
82
107
|
|
|
83
108
|
return useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
84
109
|
}
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
EditorService,
|
|
3
3
|
EditorState,
|
|
4
|
+
ActivityRegistry,
|
|
4
5
|
ExtensionDependencyDiagnostic,
|
|
5
|
-
ExtensionRegistry,
|
|
6
6
|
LayoutService,
|
|
7
|
+
MenuRegistry,
|
|
8
|
+
ViewRegistry,
|
|
7
9
|
WorkbenchLayoutState,
|
|
8
10
|
} from '@workbench-kit/workbench-core';
|
|
11
|
+
import type { CommandRegistry, KeybindingRegistry } from '@workbench-kit/platform';
|
|
9
12
|
import type {
|
|
10
13
|
WorkbenchWorkspaceHostPort as WorkspaceHostPort,
|
|
11
14
|
WorkspaceResourceTransaction,
|
|
12
15
|
} from '@workbench-kit/workspace';
|
|
13
16
|
|
|
14
|
-
import type {
|
|
17
|
+
import type {
|
|
18
|
+
WorkbenchExtensionActivationStateReader,
|
|
19
|
+
WorkbenchExtensionCatalogReader,
|
|
20
|
+
WorkbenchWorkspaceHostPort,
|
|
21
|
+
} from '../shell/provider.js';
|
|
15
22
|
|
|
16
23
|
export interface WorkbenchDevtoolsSnapshot {
|
|
17
24
|
readonly activeExtensions: readonly { readonly extensionId: string }[];
|
|
@@ -58,18 +65,30 @@ export interface WorkbenchDevtoolsSnapshot {
|
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
export interface CollectWorkbenchDevtoolsSnapshotInput {
|
|
68
|
+
readonly activities: ActivityRegistry;
|
|
61
69
|
readonly capturedAt?: string | undefined;
|
|
70
|
+
readonly commands: CommandRegistry;
|
|
62
71
|
readonly editorService: EditorService;
|
|
63
|
-
readonly
|
|
72
|
+
readonly extensionActivationState: WorkbenchExtensionActivationStateReader;
|
|
73
|
+
readonly extensionCatalog: WorkbenchExtensionCatalogReader;
|
|
74
|
+
readonly keybindings: KeybindingRegistry;
|
|
64
75
|
readonly layoutService: LayoutService;
|
|
76
|
+
readonly menus: MenuRegistry;
|
|
77
|
+
readonly views: ViewRegistry;
|
|
65
78
|
readonly workspaceHostPort?: WorkbenchWorkspaceHostPort | undefined;
|
|
66
79
|
}
|
|
67
80
|
|
|
68
81
|
export function collectWorkbenchDevtoolsSnapshot({
|
|
82
|
+
activities,
|
|
69
83
|
capturedAt = new Date().toISOString(),
|
|
84
|
+
commands,
|
|
70
85
|
editorService,
|
|
71
|
-
|
|
86
|
+
extensionActivationState,
|
|
87
|
+
extensionCatalog,
|
|
88
|
+
keybindings,
|
|
72
89
|
layoutService,
|
|
90
|
+
menus,
|
|
91
|
+
views,
|
|
73
92
|
workspaceHostPort,
|
|
74
93
|
}: CollectWorkbenchDevtoolsSnapshotInput): WorkbenchDevtoolsSnapshot {
|
|
75
94
|
const layout = layoutService.getState();
|
|
@@ -77,17 +96,17 @@ export function collectWorkbenchDevtoolsSnapshot({
|
|
|
77
96
|
const activeTabCount = editor.groups.reduce((count, group) => count + group.tabs.length, 0);
|
|
78
97
|
|
|
79
98
|
return {
|
|
80
|
-
activeExtensions:
|
|
99
|
+
activeExtensions: extensionActivationState.getActiveExtensions().map(({ extensionId }) => ({
|
|
81
100
|
extensionId,
|
|
82
101
|
})),
|
|
83
|
-
activities:
|
|
102
|
+
activities: activities.getActivities().map((activity) => ({
|
|
84
103
|
icon: activity.icon,
|
|
85
104
|
id: activity.id,
|
|
86
105
|
title: activity.title,
|
|
87
106
|
})),
|
|
88
|
-
capabilities:
|
|
107
|
+
capabilities: extensionCatalog.listCapabilityProviderIds(),
|
|
89
108
|
capturedAt,
|
|
90
|
-
commands:
|
|
109
|
+
commands: commands.getCommands().map((command) => ({
|
|
91
110
|
category: command.category,
|
|
92
111
|
id: command.id,
|
|
93
112
|
title: command.title,
|
|
@@ -102,15 +121,15 @@ export function collectWorkbenchDevtoolsSnapshot({
|
|
|
102
121
|
'layout.sideBar.visible': layout.sideBar.visible,
|
|
103
122
|
'workspace.hasHostPort': workspaceHostPort !== undefined,
|
|
104
123
|
},
|
|
105
|
-
dependencyDiagnostics:
|
|
124
|
+
dependencyDiagnostics: extensionCatalog.getDependencyDiagnostics(),
|
|
106
125
|
editor,
|
|
107
|
-
keybindings:
|
|
126
|
+
keybindings: keybindings.getKeybindings().map((binding) => ({
|
|
108
127
|
command: binding.command,
|
|
109
128
|
key: binding.key,
|
|
110
129
|
when: binding.when,
|
|
111
130
|
})),
|
|
112
131
|
layout,
|
|
113
|
-
menus:
|
|
132
|
+
menus: menus.getMenuItems().map((menu) => ({
|
|
114
133
|
command: menu.command,
|
|
115
134
|
group: menu.group,
|
|
116
135
|
menu: menu.menu,
|
|
@@ -118,13 +137,13 @@ export function collectWorkbenchDevtoolsSnapshot({
|
|
|
118
137
|
when: menu.when,
|
|
119
138
|
})),
|
|
120
139
|
transactions: readWorkspaceTransactionJournal(workspaceHostPort),
|
|
121
|
-
viewContainers:
|
|
140
|
+
viewContainers: views.getViewContainers().map((container) => ({
|
|
122
141
|
icon: container.icon,
|
|
123
142
|
id: container.id,
|
|
124
143
|
location: container.location,
|
|
125
144
|
title: container.title,
|
|
126
145
|
})),
|
|
127
|
-
views:
|
|
146
|
+
views: views.getViews().map((view) => ({
|
|
128
147
|
containerId: view.containerId,
|
|
129
148
|
id: view.id,
|
|
130
149
|
name: view.name,
|
package/src/editor/area.tsx
CHANGED
|
@@ -265,7 +265,7 @@ function EditorGroupPane({
|
|
|
265
265
|
viewProviders: readonly EditorDocumentViewProvider[];
|
|
266
266
|
}) {
|
|
267
267
|
const editorService = useEditorService();
|
|
268
|
-
const { executeCommand,
|
|
268
|
+
const { commands, executeCommand, menus } = useWorkbench();
|
|
269
269
|
const tabs = group.tabs;
|
|
270
270
|
const activeTabId = group.activeTabId ?? tabs[0]?.id ?? '';
|
|
271
271
|
const activeTab = tabs.find((tab) => tab.id === activeTabId) ?? tabs[0];
|
|
@@ -659,10 +659,11 @@ function EditorGroupPane({
|
|
|
659
659
|
<ContextMenu
|
|
660
660
|
ariaLabel="Editor tab menu"
|
|
661
661
|
items={createEditorTabContextMenuItems({
|
|
662
|
+
commands,
|
|
662
663
|
editorService,
|
|
663
664
|
executeExtensionCommand: (commandId) => executeCommand(commandId),
|
|
664
|
-
extensionRegistry,
|
|
665
665
|
groupId: group.id,
|
|
666
|
+
menus,
|
|
666
667
|
tab: contextTab,
|
|
667
668
|
tabs,
|
|
668
669
|
})}
|
|
@@ -4,6 +4,9 @@ import {
|
|
|
4
4
|
type EditorLayoutNode,
|
|
5
5
|
type EditorState,
|
|
6
6
|
type EditorTabState,
|
|
7
|
+
type WorkbenchPersistenceDiagnosticOptions,
|
|
8
|
+
type WorkbenchPersistenceReadResult,
|
|
9
|
+
type WorkbenchPersistenceWriteResult,
|
|
7
10
|
type WorkbenchStorageReader,
|
|
8
11
|
type WorkbenchStorageWriter,
|
|
9
12
|
} from '@workbench-kit/workbench-core';
|
|
@@ -11,8 +14,10 @@ import {
|
|
|
11
14
|
import { isRecord } from '../is-record.js';
|
|
12
15
|
import {
|
|
13
16
|
readLocalJsonStorage,
|
|
17
|
+
readLocalJsonStorageResult,
|
|
14
18
|
resolveLocalWorkbenchStorage,
|
|
15
19
|
writeLocalJsonStorage,
|
|
20
|
+
writeLocalJsonStorageResult,
|
|
16
21
|
} from '../storage/local-json-storage.js';
|
|
17
22
|
|
|
18
23
|
export const DEFAULT_WORKBENCH_EDITOR_STATE_STORAGE_KEY = 'workbench-kit/.workbench/editors';
|
|
@@ -49,6 +54,20 @@ export function readPersistedEditorState(
|
|
|
49
54
|
return readLocalJsonStorage(storageKey, parseEditorStateStorageValue, () => undefined, storage);
|
|
50
55
|
}
|
|
51
56
|
|
|
57
|
+
export function readPersistedEditorStateResult(
|
|
58
|
+
storageKey = DEFAULT_WORKBENCH_EDITOR_STATE_STORAGE_KEY,
|
|
59
|
+
storage?: WorkbenchStorageReader,
|
|
60
|
+
options: WorkbenchPersistenceDiagnosticOptions = {},
|
|
61
|
+
): WorkbenchPersistenceReadResult<EditorState | undefined> {
|
|
62
|
+
return readLocalJsonStorageResult(
|
|
63
|
+
storageKey,
|
|
64
|
+
parseEditorStateStorageValue,
|
|
65
|
+
() => undefined,
|
|
66
|
+
storage,
|
|
67
|
+
options,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
52
71
|
export function writePersistedEditorState(
|
|
53
72
|
state: EditorState,
|
|
54
73
|
storageKey = DEFAULT_WORKBENCH_EDITOR_STATE_STORAGE_KEY,
|
|
@@ -59,6 +78,18 @@ export function writePersistedEditorState(
|
|
|
59
78
|
});
|
|
60
79
|
}
|
|
61
80
|
|
|
81
|
+
export function writePersistedEditorStateResult(
|
|
82
|
+
state: EditorState,
|
|
83
|
+
storageKey = DEFAULT_WORKBENCH_EDITOR_STATE_STORAGE_KEY,
|
|
84
|
+
storage?: WorkbenchStorageWriter,
|
|
85
|
+
options: WorkbenchPersistenceDiagnosticOptions = {},
|
|
86
|
+
): WorkbenchPersistenceWriteResult {
|
|
87
|
+
return writeLocalJsonStorageResult(storageKey, state, storage, {
|
|
88
|
+
...options,
|
|
89
|
+
toStorageValue: editorStateToStorageValue,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
62
93
|
function parseEditorStateStorageValue(value: unknown): EditorState | undefined {
|
|
63
94
|
if (!isRecord(value)) {
|
|
64
95
|
return undefined;
|
|
@@ -12,11 +12,8 @@ import {
|
|
|
12
12
|
createWorkbenchEditorTabMenuEntries,
|
|
13
13
|
type WorkbenchEditorCommandContext,
|
|
14
14
|
} from '@workbench-kit/react/workbench/commands';
|
|
15
|
-
import type {
|
|
16
|
-
|
|
17
|
-
EditorTabState,
|
|
18
|
-
ExtensionRegistry,
|
|
19
|
-
} from '@workbench-kit/workbench-core';
|
|
15
|
+
import type { EditorService, EditorTabState, MenuRegistry } from '@workbench-kit/workbench-core';
|
|
16
|
+
import type { CommandRegistry } from '@workbench-kit/platform';
|
|
20
17
|
|
|
21
18
|
import { copyResourcePath, pathForResource } from './resource.js';
|
|
22
19
|
import {
|
|
@@ -34,17 +31,19 @@ const EDITOR_TAB_CONTEXT_MENU = 'editor/tab/context';
|
|
|
34
31
|
const EDITOR_TAB_EXTENSION_MENU_SEPARATOR_ID = 'editor-tab-extension-separator';
|
|
35
32
|
|
|
36
33
|
export function createEditorTabContextMenuItems({
|
|
34
|
+
commands,
|
|
37
35
|
editorService,
|
|
38
36
|
executeExtensionCommand,
|
|
39
|
-
extensionRegistry,
|
|
40
37
|
groupId,
|
|
38
|
+
menus,
|
|
41
39
|
tab,
|
|
42
40
|
tabs,
|
|
43
41
|
}: {
|
|
42
|
+
commands?: CommandRegistry | undefined;
|
|
44
43
|
editorService: EditorService;
|
|
45
44
|
executeExtensionCommand?: ((commandId: string) => unknown) | undefined;
|
|
46
|
-
extensionRegistry?: ExtensionRegistry | undefined;
|
|
47
45
|
groupId: string;
|
|
46
|
+
menus?: MenuRegistry | undefined;
|
|
48
47
|
tab: EditorTabState;
|
|
49
48
|
tabs: readonly EditorTabState[];
|
|
50
49
|
}): ContextMenuItem[] {
|
|
@@ -108,10 +107,11 @@ export function createEditorTabContextMenuItems({
|
|
|
108
107
|
return appendExtensionContextMenuItems(
|
|
109
108
|
baseItems,
|
|
110
109
|
createExtensionContextMenuItems({
|
|
110
|
+
commands,
|
|
111
111
|
contextKeys,
|
|
112
112
|
executeCommand: executeExtensionCommand,
|
|
113
|
-
extensionRegistry,
|
|
114
113
|
menu: EDITOR_TAB_CONTEXT_MENU,
|
|
114
|
+
menus,
|
|
115
115
|
}),
|
|
116
116
|
EDITOR_TAB_EXTENSION_MENU_SEPARATOR_ID,
|
|
117
117
|
);
|
package/src/editor/use-editor.ts
CHANGED
|
@@ -38,7 +38,7 @@ export function useActiveEditorTab(): EditorTabState | undefined {
|
|
|
38
38
|
|
|
39
39
|
export function useEditorHost(tabId?: string): EditorHost | undefined {
|
|
40
40
|
const editorService = useEditorService();
|
|
41
|
-
const {
|
|
41
|
+
const { extensionActivation, waitForExtensionStartup } = useWorkbench();
|
|
42
42
|
const editorState = useEditorState();
|
|
43
43
|
const forceRender = useForceRender();
|
|
44
44
|
const activeGroup = editorState.groups.find((group) => group.id === editorState.activeGroupId);
|
|
@@ -68,11 +68,11 @@ export function useEditorHost(tabId?: string): EditorHost | undefined {
|
|
|
68
68
|
useEffect(() => {
|
|
69
69
|
// Late onView / onCommand activations register editor host factories after the
|
|
70
70
|
// first paint that restores persisted tabs. Retry host creation when they land.
|
|
71
|
-
const disposable =
|
|
71
|
+
const disposable = extensionActivation.onDidActivateExtension(forceRender);
|
|
72
72
|
return () => {
|
|
73
73
|
disposable.dispose();
|
|
74
74
|
};
|
|
75
|
-
}, [
|
|
75
|
+
}, [extensionActivation, forceRender]);
|
|
76
76
|
|
|
77
77
|
if (!resolvedTabId) {
|
|
78
78
|
return undefined;
|
|
@@ -87,7 +87,7 @@ export function useEditorHost(tabId?: string): EditorHost | undefined {
|
|
|
87
87
|
export function useEditorDocumentViewProviders(
|
|
88
88
|
localProviders?: readonly EditorDocumentViewProvider[] | undefined,
|
|
89
89
|
): readonly EditorDocumentViewProvider[] {
|
|
90
|
-
const { editorDocumentViewProviders,
|
|
90
|
+
const { editorDocumentViewProviders, extensionActivation, waitForExtensionStartup } =
|
|
91
91
|
useWorkbench();
|
|
92
92
|
const forceRender = useForceRender();
|
|
93
93
|
|
|
@@ -115,11 +115,11 @@ export function useEditorDocumentViewProviders(
|
|
|
115
115
|
}, [forceRender, waitForExtensionStartup]);
|
|
116
116
|
|
|
117
117
|
useEffect(() => {
|
|
118
|
-
const disposable =
|
|
118
|
+
const disposable = extensionActivation.onDidActivateExtension(forceRender);
|
|
119
119
|
return () => {
|
|
120
120
|
disposable.dispose();
|
|
121
121
|
};
|
|
122
|
-
}, [
|
|
122
|
+
}, [extensionActivation, forceRender]);
|
|
123
123
|
|
|
124
124
|
const registryProviders = editorDocumentViewProviders.getProviders();
|
|
125
125
|
|
|
@@ -8,12 +8,13 @@ import {
|
|
|
8
8
|
type WorkbenchWorkspaceCommandContext,
|
|
9
9
|
} from '@workbench-kit/react/workbench/commands';
|
|
10
10
|
import {
|
|
11
|
+
type CommandRegistry,
|
|
11
12
|
createCommandRegistry,
|
|
12
13
|
executeCommand as executeRegisteredCommand,
|
|
13
14
|
resolveCommandMenuItems,
|
|
14
15
|
} from '@workbench-kit/platform';
|
|
15
16
|
import { parentPathOf, type WorkspaceTreeNode } from '@workbench-kit/workspace';
|
|
16
|
-
import type {
|
|
17
|
+
import type { MenuRegistry } from '@workbench-kit/workbench-core';
|
|
17
18
|
import {
|
|
18
19
|
appendExtensionContextMenuItems,
|
|
19
20
|
createExtensionContextMenuItems,
|
|
@@ -29,26 +30,28 @@ const EXPLORER_EXTENSION_MENU_SEPARATOR_ID = 'explorer-extension-separator';
|
|
|
29
30
|
|
|
30
31
|
export function createExplorerItemContextMenuItems({
|
|
31
32
|
actionPaths,
|
|
33
|
+
commands,
|
|
32
34
|
copyPaths,
|
|
33
35
|
createFile,
|
|
34
36
|
createFolder,
|
|
35
37
|
deleteTargets,
|
|
36
38
|
executeExtensionCommand,
|
|
37
|
-
extensionRegistry,
|
|
38
39
|
files,
|
|
40
|
+
menus,
|
|
39
41
|
node,
|
|
40
42
|
openFiles,
|
|
41
43
|
revealFolder,
|
|
42
44
|
renameTarget,
|
|
43
45
|
}: {
|
|
44
46
|
actionPaths: readonly string[];
|
|
47
|
+
commands?: CommandRegistry | undefined;
|
|
45
48
|
copyPaths: (paths: string[]) => void;
|
|
46
49
|
createFile: (parentPath: string) => void;
|
|
47
50
|
createFolder: (parentPath: string) => void;
|
|
48
51
|
deleteTargets: (paths: string[]) => void;
|
|
49
52
|
executeExtensionCommand?: ((commandId: string) => unknown) | undefined;
|
|
50
|
-
extensionRegistry?: ExtensionRegistry | undefined;
|
|
51
53
|
files: readonly { path: string }[];
|
|
54
|
+
menus?: MenuRegistry | undefined;
|
|
52
55
|
node: WorkspaceTreeNode;
|
|
53
56
|
openFiles: (paths: string[]) => void;
|
|
54
57
|
revealFolder: (path: string) => void;
|
|
@@ -104,10 +107,11 @@ export function createExplorerItemContextMenuItems({
|
|
|
104
107
|
return appendExtensionContextMenuItems(
|
|
105
108
|
baseItems,
|
|
106
109
|
createExtensionContextMenuItems({
|
|
110
|
+
commands,
|
|
107
111
|
contextKeys,
|
|
108
112
|
executeCommand: executeExtensionCommand,
|
|
109
|
-
extensionRegistry,
|
|
110
113
|
menu: EXPLORER_CONTEXT_MENU,
|
|
114
|
+
menus,
|
|
111
115
|
}),
|
|
112
116
|
EXPLORER_EXTENSION_MENU_SEPARATOR_ID,
|
|
113
117
|
);
|
package/src/explorer/view.tsx
CHANGED
|
@@ -52,7 +52,7 @@ interface ExplorerContextMenuState {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
export function BuiltinExplorerView() {
|
|
55
|
-
const { executeCommand,
|
|
55
|
+
const { commands, executeCommand, menus, workspaceHostPort } = useWorkbench();
|
|
56
56
|
const activeTab = useActiveEditorTab();
|
|
57
57
|
const workspaceService = isWorkspaceResourceService(workspaceHostPort?.service)
|
|
58
58
|
? workspaceHostPort.service
|
|
@@ -146,6 +146,7 @@ export function BuiltinExplorerView() {
|
|
|
146
146
|
ariaLabel: `${node.name} menu`,
|
|
147
147
|
items: createExplorerItemContextMenuItems({
|
|
148
148
|
actionPaths: meta.actionPaths,
|
|
149
|
+
commands,
|
|
149
150
|
copyPaths: (paths) => {
|
|
150
151
|
void executeWorkspaceCommand(WORKBENCH_WORKSPACE_COPY_PATH_COMMAND_ID, { paths });
|
|
151
152
|
},
|
|
@@ -158,8 +159,8 @@ export function BuiltinExplorerView() {
|
|
|
158
159
|
});
|
|
159
160
|
},
|
|
160
161
|
executeExtensionCommand: (commandId) => executeCommand(commandId),
|
|
161
|
-
extensionRegistry,
|
|
162
162
|
files: workspaceState?.files ?? [],
|
|
163
|
+
menus,
|
|
163
164
|
node,
|
|
164
165
|
openFiles: (paths) => {
|
|
165
166
|
void executeWorkspaceCommand(WORKBENCH_WORKSPACE_OPEN_COMMAND_ID, {
|
|
@@ -174,7 +175,7 @@ export function BuiltinExplorerView() {
|
|
|
174
175
|
y: event.clientY,
|
|
175
176
|
});
|
|
176
177
|
},
|
|
177
|
-
[executeWorkspaceCommand, explorer, workspaceState?.files],
|
|
178
|
+
[commands, executeWorkspaceCommand, explorer, menus, workspaceState?.files],
|
|
178
179
|
);
|
|
179
180
|
|
|
180
181
|
if (!workspaceService || !workspaceState) {
|