@workbench-kit/shell-react 0.0.2-prototype.0.2.18 → 0.0.2-prototype.0.2.19
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/package.json +9 -8
- package/src/extensions/builtin/accounts/src/index.ts +13 -0
- package/src/extensions/builtin/accounts/workbench.extension.json +45 -0
- package/src/extensions/builtin/chat/src/index.ts +40 -0
- package/src/extensions/builtin/chat/workbench.extension.json +66 -0
- package/src/extensions/builtin/commands/src/command-inspector-editor-host.ts +79 -0
- package/src/extensions/builtin/commands/src/index.ts +65 -0
- package/src/extensions/builtin/commands/workbench.extension.json +64 -0
- package/src/extensions/builtin/editor/src/index.ts +95 -0
- package/src/extensions/builtin/editor/src/missing-resource-editor-host.ts +58 -0
- package/src/extensions/builtin/editor/src/resource-uri.ts +16 -0
- package/src/extensions/builtin/editor/src/text-editor-host.ts +86 -0
- package/src/extensions/builtin/editor/workbench.extension.json +32 -0
- package/src/extensions/builtin/explorer/src/index.ts +466 -0
- package/src/extensions/builtin/explorer/workbench.extension.json +132 -0
- package/src/extensions/builtin/extensions/src/index.ts +28 -0
- package/src/extensions/builtin/extensions/workbench.extension.json +53 -0
- package/src/extensions/builtin/keybindings/src/index.ts +6 -0
- package/src/extensions/builtin/keybindings/workbench.extension.json +21 -0
- package/src/extensions/builtin/search/src/index.ts +22 -0
- package/src/extensions/builtin/search/workbench.extension.json +43 -0
- package/src/extensions/builtin/settings/src/index.ts +23 -0
- package/src/extensions/builtin/settings/workbench.extension.json +41 -0
- package/src/extensions/builtin/workspace/src/index.ts +12 -0
- package/src/extensions/builtin/workspace/workbench.extension.json +37 -0
- package/src/extensions/builtin-extensions.ts +591 -0
- package/src/extensions/management-model.ts +41 -35
- package/src/extensions/use-extension-management.ts +11 -4
- package/src/index.ts +2 -0
- package/src/shell/provider.tsx +6 -6
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "workbench-kit.builtin.editor",
|
|
4
|
+
"name": "builtin-editor",
|
|
5
|
+
"displayName": "Text Editor",
|
|
6
|
+
"version": "0.0.0",
|
|
7
|
+
"publisher": "workbench-kit",
|
|
8
|
+
"engines": {
|
|
9
|
+
"workbench": "^0.0.0",
|
|
10
|
+
"extensionApi": "^0.0.0"
|
|
11
|
+
},
|
|
12
|
+
"activationEvents": ["onStartup"],
|
|
13
|
+
"contributes": {
|
|
14
|
+
"documentViews": [
|
|
15
|
+
{
|
|
16
|
+
"id": "workbench-kit.builtin.editor.markdown-preview",
|
|
17
|
+
"kind": "preview",
|
|
18
|
+
"label": "Preview",
|
|
19
|
+
"priority": 5,
|
|
20
|
+
"filenamePatterns": ["*.md", "*.mdx"],
|
|
21
|
+
"mimeTypes": ["text/markdown"]
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"editors": [
|
|
25
|
+
{
|
|
26
|
+
"id": "workbench-kit.builtin.editor.text",
|
|
27
|
+
"label": "Text Editor",
|
|
28
|
+
"icon": "file"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
import {
|
|
2
|
+
WORKBENCH_EDITOR_SERVICE_CAPABILITY_ID,
|
|
3
|
+
type ExtensionContext,
|
|
4
|
+
type WorkbenchEditorServiceCapability,
|
|
5
|
+
} from '@workbench-kit/workbench-extension-sdk';
|
|
6
|
+
import {
|
|
7
|
+
WORKBENCH_WORKSPACE_CAPABILITY_ID,
|
|
8
|
+
createWorkspaceResourceTransaction,
|
|
9
|
+
fileNameOfPath,
|
|
10
|
+
formatWorkspaceResourceUri,
|
|
11
|
+
getAvailableWorkspaceEntryName,
|
|
12
|
+
getWorkspaceEntryMovePlan,
|
|
13
|
+
isSimpleWorkspaceName,
|
|
14
|
+
isWorkspaceEntryPathAvailable,
|
|
15
|
+
joinWorkspacePath,
|
|
16
|
+
normalizeWorkspacePath,
|
|
17
|
+
parentPathOf,
|
|
18
|
+
type VirtualWorkspaceState,
|
|
19
|
+
type VirtualWorkspaceInitialState,
|
|
20
|
+
type WorkspaceResourceMutation,
|
|
21
|
+
type WorkspaceResourceService,
|
|
22
|
+
type WorkspaceFile,
|
|
23
|
+
} from '@workbench-kit/workspace';
|
|
24
|
+
|
|
25
|
+
export const EXTENSION_ID = 'workbench-kit.builtin.explorer' as const;
|
|
26
|
+
|
|
27
|
+
export const EXPLORER_VIEW_ID = 'workbench-kit.builtin.explorer.tree' as const;
|
|
28
|
+
export const EXPLORER_VIEW_RENDER_KIND = 'workbench-kit.builtin.explorer.view' as const;
|
|
29
|
+
export const REFRESH_COMMAND_ID = 'workbench-kit.builtin.explorer.refresh' as const;
|
|
30
|
+
export const REVEAL_COMMAND_ID = 'workbench-kit.builtin.explorer.reveal' as const;
|
|
31
|
+
export const FOCUS_COMMAND_ID = 'workbench-kit.builtin.explorer.focus' as const;
|
|
32
|
+
export const MOVE_COMMAND_ID = 'workbench-kit.builtin.explorer.move' as const;
|
|
33
|
+
|
|
34
|
+
const WORKSPACE_NEW_FILE_COMMAND_ID = 'workspace.newFile' as const;
|
|
35
|
+
const WORKSPACE_NEW_FOLDER_COMMAND_ID = 'workspace.newFolder' as const;
|
|
36
|
+
const WORKSPACE_INIT_COMMAND_ID = 'workspace.init' as const;
|
|
37
|
+
const WORKSPACE_OPEN_COMMAND_ID = 'workspace.open' as const;
|
|
38
|
+
const WORKSPACE_COPY_PATH_COMMAND_ID = 'workspace.copyPath' as const;
|
|
39
|
+
const WORKSPACE_RENAME_COMMAND_ID = 'workspace.rename' as const;
|
|
40
|
+
const WORKSPACE_DELETE_COMMAND_ID = 'workspace.delete' as const;
|
|
41
|
+
|
|
42
|
+
interface ExplorerViewRenderData {
|
|
43
|
+
readonly kind: typeof EXPLORER_VIEW_RENDER_KIND;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface WorkspaceCommandResult {
|
|
47
|
+
readonly path?: string | undefined;
|
|
48
|
+
readonly paths?: readonly string[] | undefined;
|
|
49
|
+
readonly transactionId?: string | undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function activate(context: ExtensionContext): void {
|
|
53
|
+
context.commands.registerCommand(REFRESH_COMMAND_ID, () => {
|
|
54
|
+
const service = getWorkspaceService(context);
|
|
55
|
+
return {
|
|
56
|
+
refreshed: true,
|
|
57
|
+
version: service?.getSnapshot().version,
|
|
58
|
+
viewId: EXPLORER_VIEW_ID,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
context.commands.registerCommand(REVEAL_COMMAND_ID, (input) => ({
|
|
63
|
+
path: readFirstPath(input),
|
|
64
|
+
viewId: EXPLORER_VIEW_ID,
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
context.commands.registerCommand(FOCUS_COMMAND_ID, () => ({
|
|
68
|
+
focused: true,
|
|
69
|
+
viewId: EXPLORER_VIEW_ID,
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
context.commands.registerCommand(WORKSPACE_NEW_FILE_COMMAND_ID, (input) =>
|
|
73
|
+
createWorkspaceFile(context, input),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
context.commands.registerCommand(WORKSPACE_NEW_FOLDER_COMMAND_ID, (input) =>
|
|
77
|
+
createWorkspaceFolder(context, input),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
context.commands.registerCommand(WORKSPACE_INIT_COMMAND_ID, (input) =>
|
|
81
|
+
initializeWorkspace(context, input),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
context.commands.registerCommand(WORKSPACE_OPEN_COMMAND_ID, (input) =>
|
|
85
|
+
openWorkspaceTargets(context, input),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
context.commands.registerCommand(WORKSPACE_COPY_PATH_COMMAND_ID, (input) =>
|
|
89
|
+
copyWorkspacePaths(input),
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
context.commands.registerCommand(WORKSPACE_RENAME_COMMAND_ID, (input) =>
|
|
93
|
+
renameWorkspaceTarget(context, input),
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
context.commands.registerCommand(WORKSPACE_DELETE_COMMAND_ID, (input) =>
|
|
97
|
+
deleteWorkspaceTargets(context, input),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
context.commands.registerCommand(MOVE_COMMAND_ID, (input) =>
|
|
101
|
+
moveWorkspaceTargets(context, input),
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
context.views.registerViewProvider({
|
|
105
|
+
viewId: EXPLORER_VIEW_ID,
|
|
106
|
+
resolveViewHost: () => ({
|
|
107
|
+
dispose() {},
|
|
108
|
+
render: (): ExplorerViewRenderData => ({ kind: EXPLORER_VIEW_RENDER_KIND }),
|
|
109
|
+
title: 'Explorer',
|
|
110
|
+
}),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function createWorkspaceFile(
|
|
115
|
+
context: ExtensionContext,
|
|
116
|
+
input: unknown,
|
|
117
|
+
): WorkspaceCommandResult | undefined {
|
|
118
|
+
const service = getWorkspaceService(context);
|
|
119
|
+
if (!service) return undefined;
|
|
120
|
+
|
|
121
|
+
const state = service.getState();
|
|
122
|
+
const parentPath = normalizeWorkspacePath(readString(input, 'parentPath') ?? '');
|
|
123
|
+
const explicitPath = normalizeWorkspacePath(readString(input, 'path') ?? '');
|
|
124
|
+
const path =
|
|
125
|
+
explicitPath ||
|
|
126
|
+
resolveNewEntryPath({
|
|
127
|
+
fallbackName: 'untitled.md',
|
|
128
|
+
input,
|
|
129
|
+
parentPath,
|
|
130
|
+
state,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (
|
|
134
|
+
!path ||
|
|
135
|
+
!isWorkspaceEntryPathAvailable({ files: state.files, folders: state.folders, path })
|
|
136
|
+
) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return applyMutations(service, 'Create file', [
|
|
141
|
+
{
|
|
142
|
+
file: {
|
|
143
|
+
content: '',
|
|
144
|
+
path,
|
|
145
|
+
source: 'user',
|
|
146
|
+
},
|
|
147
|
+
path,
|
|
148
|
+
type: 'create-file',
|
|
149
|
+
},
|
|
150
|
+
]);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function createWorkspaceFolder(
|
|
154
|
+
context: ExtensionContext,
|
|
155
|
+
input: unknown,
|
|
156
|
+
): WorkspaceCommandResult | undefined {
|
|
157
|
+
const service = getWorkspaceService(context);
|
|
158
|
+
if (!service) return undefined;
|
|
159
|
+
|
|
160
|
+
const state = service.getState();
|
|
161
|
+
const parentPath = normalizeWorkspacePath(readString(input, 'parentPath') ?? '');
|
|
162
|
+
const explicitPath = normalizeWorkspacePath(readString(input, 'path') ?? '');
|
|
163
|
+
const path =
|
|
164
|
+
explicitPath ||
|
|
165
|
+
resolveNewEntryPath({
|
|
166
|
+
fallbackName: 'new-folder',
|
|
167
|
+
input,
|
|
168
|
+
parentPath,
|
|
169
|
+
state,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
if (
|
|
173
|
+
!path ||
|
|
174
|
+
!isWorkspaceEntryPathAvailable({ files: state.files, folders: state.folders, path })
|
|
175
|
+
) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return applyMutations(service, 'Create folder', [{ path, type: 'create-folder' }]);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function initializeWorkspace(
|
|
183
|
+
context: ExtensionContext,
|
|
184
|
+
input: unknown,
|
|
185
|
+
): WorkspaceCommandResult | undefined {
|
|
186
|
+
const service = getWorkspaceService(context);
|
|
187
|
+
if (!service) return undefined;
|
|
188
|
+
|
|
189
|
+
const initialState = readWorkspaceInitialState(input);
|
|
190
|
+
return applyMutations(
|
|
191
|
+
service,
|
|
192
|
+
'Initialize workspace',
|
|
193
|
+
[{ type: 'initialize-workspace', state: initialState }],
|
|
194
|
+
{
|
|
195
|
+
paths: [
|
|
196
|
+
...readStringArray(input, 'folders'),
|
|
197
|
+
...readWorkspaceFiles(input).map((file) => file.path),
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function openWorkspaceTargets(
|
|
204
|
+
context: ExtensionContext,
|
|
205
|
+
input: unknown,
|
|
206
|
+
): WorkspaceCommandResult | undefined {
|
|
207
|
+
const service = getWorkspaceService(context);
|
|
208
|
+
const editorService = context.getCapability<WorkbenchEditorServiceCapability>(
|
|
209
|
+
WORKBENCH_EDITOR_SERVICE_CAPABILITY_ID,
|
|
210
|
+
);
|
|
211
|
+
if (!service || !editorService) return undefined;
|
|
212
|
+
|
|
213
|
+
const fileByPath = new Map(service.getState().files.map((file) => [file.path, file]));
|
|
214
|
+
const paths = readPaths(input).filter((path) => fileByPath.has(path));
|
|
215
|
+
for (const path of paths) {
|
|
216
|
+
const file = fileByPath.get(path);
|
|
217
|
+
editorService.openEditor({
|
|
218
|
+
pinned: true,
|
|
219
|
+
resourceUri: formatWorkspaceResourceUri({ kind: 'file', path }),
|
|
220
|
+
title: file ? fileNameOfPath(file.path) : fileNameOfPath(path),
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return paths.length > 0 ? { paths } : undefined;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function copyWorkspacePaths(input: unknown): WorkspaceCommandResult | undefined {
|
|
228
|
+
const paths = readPaths(input);
|
|
229
|
+
if (paths.length === 0) return undefined;
|
|
230
|
+
|
|
231
|
+
const clipboard = globalThis.navigator?.clipboard;
|
|
232
|
+
if (clipboard) {
|
|
233
|
+
void clipboard.writeText(paths.join('\n')).catch(() => undefined);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return { paths };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function renameWorkspaceTarget(
|
|
240
|
+
context: ExtensionContext,
|
|
241
|
+
input: unknown,
|
|
242
|
+
): WorkspaceCommandResult | undefined {
|
|
243
|
+
const service = getWorkspaceService(context);
|
|
244
|
+
if (!service) return undefined;
|
|
245
|
+
|
|
246
|
+
const state = service.getState();
|
|
247
|
+
const path = readFirstPath(input);
|
|
248
|
+
const name = readString(input, 'name')?.trim();
|
|
249
|
+
if (!path || !name || !isSimpleWorkspaceName(name)) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const destinationPath = joinWorkspacePath(parentPathOf(path), name);
|
|
254
|
+
if (
|
|
255
|
+
!destinationPath ||
|
|
256
|
+
!isWorkspaceEntryPathAvailable({
|
|
257
|
+
excludedPaths: [path],
|
|
258
|
+
files: state.files,
|
|
259
|
+
folders: state.folders,
|
|
260
|
+
path: destinationPath,
|
|
261
|
+
})
|
|
262
|
+
) {
|
|
263
|
+
return undefined;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const kind =
|
|
267
|
+
readString(input, 'kind') === 'folder' ? 'folder' : resolveWorkspacePathKind(state, path);
|
|
268
|
+
if (!kind) return undefined;
|
|
269
|
+
|
|
270
|
+
return applyMutations(
|
|
271
|
+
service,
|
|
272
|
+
kind === 'folder' ? 'Rename folder' : 'Rename file',
|
|
273
|
+
[
|
|
274
|
+
kind === 'folder'
|
|
275
|
+
? { name, path, type: 'rename-folder' }
|
|
276
|
+
: { name, path, type: 'rename-file' },
|
|
277
|
+
],
|
|
278
|
+
{ path: destinationPath, paths: [destinationPath] },
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function deleteWorkspaceTargets(
|
|
283
|
+
context: ExtensionContext,
|
|
284
|
+
input: unknown,
|
|
285
|
+
): WorkspaceCommandResult | undefined {
|
|
286
|
+
const service = getWorkspaceService(context);
|
|
287
|
+
if (!service) return undefined;
|
|
288
|
+
|
|
289
|
+
const state = service.getState();
|
|
290
|
+
const mutations = readPaths(input)
|
|
291
|
+
.map((path): WorkspaceResourceMutation | undefined => {
|
|
292
|
+
const kind =
|
|
293
|
+
readString(input, 'kind') === 'folder' ? 'folder' : resolveWorkspacePathKind(state, path);
|
|
294
|
+
if (kind === 'folder') {
|
|
295
|
+
return { path, type: 'delete-folder' };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (kind === 'file') {
|
|
299
|
+
return { path, type: 'delete-file' };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return undefined;
|
|
303
|
+
})
|
|
304
|
+
.filter((mutation): mutation is WorkspaceResourceMutation => Boolean(mutation));
|
|
305
|
+
|
|
306
|
+
if (mutations.length === 0) return undefined;
|
|
307
|
+
|
|
308
|
+
return applyMutations(service, 'Delete workspace entries', mutations, { paths: [] });
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function moveWorkspaceTargets(
|
|
312
|
+
context: ExtensionContext,
|
|
313
|
+
input: unknown,
|
|
314
|
+
): WorkspaceCommandResult | undefined {
|
|
315
|
+
const service = getWorkspaceService(context);
|
|
316
|
+
if (!service) return undefined;
|
|
317
|
+
|
|
318
|
+
const state = service.getState();
|
|
319
|
+
const targetFolderPath = normalizeWorkspacePath(readString(input, 'targetFolderPath') ?? '');
|
|
320
|
+
const plan = getWorkspaceEntryMovePlan({
|
|
321
|
+
files: state.files,
|
|
322
|
+
folders: state.folders,
|
|
323
|
+
sourcePaths: readStringArray(input, 'sourcePaths'),
|
|
324
|
+
targetFolderPath,
|
|
325
|
+
});
|
|
326
|
+
const mutations = plan.moves.map<WorkspaceResourceMutation>((move) =>
|
|
327
|
+
move.kind === 'folder'
|
|
328
|
+
? {
|
|
329
|
+
sourcePath: move.sourcePath,
|
|
330
|
+
targetFolderPath: plan.targetFolderPath,
|
|
331
|
+
type: 'move-folder',
|
|
332
|
+
}
|
|
333
|
+
: {
|
|
334
|
+
sourcePath: move.sourcePath,
|
|
335
|
+
targetFolderPath: plan.targetFolderPath,
|
|
336
|
+
type: 'move-file',
|
|
337
|
+
},
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
if (mutations.length === 0) return undefined;
|
|
341
|
+
|
|
342
|
+
return applyMutations(service, 'Move workspace entries', mutations, {
|
|
343
|
+
paths: plan.moves.map((move) => move.destinationPath),
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function applyMutations(
|
|
348
|
+
service: WorkspaceResourceService,
|
|
349
|
+
label: string,
|
|
350
|
+
mutations: readonly WorkspaceResourceMutation[],
|
|
351
|
+
result: Omit<WorkspaceCommandResult, 'transactionId'> = {},
|
|
352
|
+
): WorkspaceCommandResult {
|
|
353
|
+
const transaction = createWorkspaceResourceTransaction({ label, mutations });
|
|
354
|
+
service.applyTransaction(transaction);
|
|
355
|
+
|
|
356
|
+
const mutationPaths = mutations.flatMap((mutation) => {
|
|
357
|
+
if ('path' in mutation) return [mutation.path];
|
|
358
|
+
if (mutation.type === 'move-file') return [mutation.sourcePath];
|
|
359
|
+
if (mutation.type === 'move-folder') return [mutation.sourcePath];
|
|
360
|
+
return [];
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
return {
|
|
364
|
+
path: result.path ?? result.paths?.[0] ?? mutationPaths[0],
|
|
365
|
+
paths: result.paths ?? mutationPaths,
|
|
366
|
+
transactionId: transaction.id,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function resolveNewEntryPath({
|
|
371
|
+
fallbackName,
|
|
372
|
+
input,
|
|
373
|
+
parentPath,
|
|
374
|
+
state,
|
|
375
|
+
}: {
|
|
376
|
+
fallbackName: string;
|
|
377
|
+
input: unknown;
|
|
378
|
+
parentPath: string;
|
|
379
|
+
state: VirtualWorkspaceState;
|
|
380
|
+
}): string {
|
|
381
|
+
const preferredName = readString(input, 'name')?.trim() || fallbackName;
|
|
382
|
+
if (!isSimpleWorkspaceName(preferredName)) return '';
|
|
383
|
+
|
|
384
|
+
const name = getAvailableWorkspaceEntryName({
|
|
385
|
+
files: state.files,
|
|
386
|
+
folders: state.folders,
|
|
387
|
+
parentPath,
|
|
388
|
+
preferredName,
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
return joinWorkspacePath(parentPath, name);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function getWorkspaceService(context: ExtensionContext): WorkspaceResourceService | undefined {
|
|
395
|
+
return context.getCapability<WorkspaceResourceService>(WORKBENCH_WORKSPACE_CAPABILITY_ID);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function resolveWorkspacePathKind(
|
|
399
|
+
state: VirtualWorkspaceState,
|
|
400
|
+
path: string,
|
|
401
|
+
): 'file' | 'folder' | undefined {
|
|
402
|
+
if (state.files.some((file) => file.path === path)) return 'file';
|
|
403
|
+
if (state.folders.includes(path)) return 'folder';
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function readFirstPath(input: unknown): string | undefined {
|
|
408
|
+
return readPaths(input)[0];
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function readPaths(input: unknown): string[] {
|
|
412
|
+
const paths = readStringArray(input, 'paths');
|
|
413
|
+
const path = readString(input, 'path');
|
|
414
|
+
const allPaths = path ? [path, ...paths] : paths;
|
|
415
|
+
|
|
416
|
+
return [...new Set(allPaths.map(normalizeWorkspacePath).filter(Boolean))];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function readStringArray(input: unknown, key: string): string[] {
|
|
420
|
+
const value = isRecord(input) ? input[key] : undefined;
|
|
421
|
+
if (!Array.isArray(value)) return [];
|
|
422
|
+
|
|
423
|
+
return value.filter((entry): entry is string => typeof entry === 'string');
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function readWorkspaceInitialState(input: unknown): VirtualWorkspaceInitialState {
|
|
427
|
+
return {
|
|
428
|
+
expandedPaths: readStringArray(input, 'expandedPaths'),
|
|
429
|
+
files: readWorkspaceFiles(input),
|
|
430
|
+
folders: readStringArray(input, 'folders'),
|
|
431
|
+
openPaths: readStringArray(input, 'openPaths'),
|
|
432
|
+
searchQuery: readString(input, 'searchQuery') ?? '',
|
|
433
|
+
selectedPath: readString(input, 'selectedPath'),
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function readWorkspaceFiles(input: unknown): WorkspaceFile[] {
|
|
438
|
+
const value = isRecord(input) ? input.files : undefined;
|
|
439
|
+
if (!Array.isArray(value)) return [];
|
|
440
|
+
|
|
441
|
+
return value.flatMap((entry) => {
|
|
442
|
+
if (!isRecord(entry)) return [];
|
|
443
|
+
|
|
444
|
+
const path = typeof entry.path === 'string' ? entry.path : '';
|
|
445
|
+
if (!path) return [];
|
|
446
|
+
|
|
447
|
+
return [
|
|
448
|
+
{
|
|
449
|
+
content: typeof entry.content === 'string' ? entry.content : '',
|
|
450
|
+
mimeType: typeof entry.mimeType === 'string' ? entry.mimeType : undefined,
|
|
451
|
+
path,
|
|
452
|
+
source: entry.source === 'assistant' || entry.source === 'user' ? entry.source : undefined,
|
|
453
|
+
updatedAt: typeof entry.updatedAt === 'string' ? entry.updatedAt : undefined,
|
|
454
|
+
},
|
|
455
|
+
];
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
function readString(input: unknown, key: string): string | undefined {
|
|
460
|
+
const value = isRecord(input) ? input[key] : undefined;
|
|
461
|
+
return typeof value === 'string' ? value : undefined;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
465
|
+
return typeof value === 'object' && value !== null;
|
|
466
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"id": "workbench-kit.builtin.explorer",
|
|
4
|
+
"name": "builtin-explorer",
|
|
5
|
+
"displayName": "Explorer",
|
|
6
|
+
"version": "0.0.0",
|
|
7
|
+
"publisher": "workbench-kit",
|
|
8
|
+
"engines": {
|
|
9
|
+
"workbench": "^0.0.0",
|
|
10
|
+
"extensionApi": "^0.0.0"
|
|
11
|
+
},
|
|
12
|
+
"activationEvents": [
|
|
13
|
+
"onView:workbench-kit.builtin.explorer.tree",
|
|
14
|
+
"onCommand:workbench-kit.builtin.explorer.refresh",
|
|
15
|
+
"onCommand:workbench-kit.builtin.explorer.reveal",
|
|
16
|
+
"onCommand:workbench-kit.builtin.explorer.focus",
|
|
17
|
+
"onCommand:workbench-kit.builtin.explorer.move",
|
|
18
|
+
"onCommand:workspace.newFile",
|
|
19
|
+
"onCommand:workspace.newFolder",
|
|
20
|
+
"onCommand:workspace.init",
|
|
21
|
+
"onCommand:workspace.open",
|
|
22
|
+
"onCommand:workspace.copyPath",
|
|
23
|
+
"onCommand:workspace.rename",
|
|
24
|
+
"onCommand:workspace.delete"
|
|
25
|
+
],
|
|
26
|
+
"capabilities": {
|
|
27
|
+
"requires": ["workbench.workspace"]
|
|
28
|
+
},
|
|
29
|
+
"permissions": ["workspace.read", "workspace.write"],
|
|
30
|
+
"contributes": {
|
|
31
|
+
"commands": [
|
|
32
|
+
{
|
|
33
|
+
"command": "workbench-kit.builtin.explorer.refresh",
|
|
34
|
+
"title": "Refresh Explorer",
|
|
35
|
+
"category": "Explorer"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"command": "workbench-kit.builtin.explorer.reveal",
|
|
39
|
+
"title": "Reveal in Explorer",
|
|
40
|
+
"category": "Explorer"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"command": "workbench-kit.builtin.explorer.focus",
|
|
44
|
+
"title": "Focus Explorer",
|
|
45
|
+
"category": "Explorer"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"command": "workbench-kit.builtin.explorer.move",
|
|
49
|
+
"title": "Move Workspace Entry",
|
|
50
|
+
"category": "Explorer"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"command": "workspace.newFile",
|
|
54
|
+
"title": "New File",
|
|
55
|
+
"category": "Workspace",
|
|
56
|
+
"icon": "new-file"
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
"command": "workspace.newFolder",
|
|
60
|
+
"title": "New Folder",
|
|
61
|
+
"category": "Workspace",
|
|
62
|
+
"icon": "new-folder"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"command": "workspace.init",
|
|
66
|
+
"title": "Initialize Workspace",
|
|
67
|
+
"category": "Workspace"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"command": "workspace.open",
|
|
71
|
+
"title": "Open",
|
|
72
|
+
"category": "Workspace",
|
|
73
|
+
"icon": "go-to-file"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"command": "workspace.copyPath",
|
|
77
|
+
"title": "Copy Path",
|
|
78
|
+
"category": "Workspace",
|
|
79
|
+
"icon": "copy"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"command": "workspace.rename",
|
|
83
|
+
"title": "Rename",
|
|
84
|
+
"category": "Workspace",
|
|
85
|
+
"icon": "edit"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"command": "workspace.delete",
|
|
89
|
+
"title": "Delete",
|
|
90
|
+
"category": "Workspace",
|
|
91
|
+
"icon": "trash"
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"menus": {
|
|
95
|
+
"view/title": [
|
|
96
|
+
{
|
|
97
|
+
"command": "workbench-kit.builtin.explorer.refresh",
|
|
98
|
+
"group": "navigation",
|
|
99
|
+
"order": 1,
|
|
100
|
+
"when": "view == workbench-kit.builtin.explorer.tree"
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
},
|
|
104
|
+
"viewContainers": {
|
|
105
|
+
"activitybar": [
|
|
106
|
+
{
|
|
107
|
+
"id": "explorer",
|
|
108
|
+
"title": "Explorer",
|
|
109
|
+
"icon": "files",
|
|
110
|
+
"order": 10
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"activities": [
|
|
115
|
+
{
|
|
116
|
+
"id": "workbench-kit.builtin.explorer.activity",
|
|
117
|
+
"viewContainerId": "explorer",
|
|
118
|
+
"icon": "files",
|
|
119
|
+
"title": "Explorer",
|
|
120
|
+
"order": 10
|
|
121
|
+
}
|
|
122
|
+
],
|
|
123
|
+
"views": {
|
|
124
|
+
"explorer": [
|
|
125
|
+
{
|
|
126
|
+
"id": "workbench-kit.builtin.explorer.tree",
|
|
127
|
+
"name": "Explorer"
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ExtensionContext } from '@workbench-kit/workbench-extension-sdk';
|
|
2
|
+
|
|
3
|
+
export const EXTENSION_ID = 'workbench-kit.builtin.extensions' as const;
|
|
4
|
+
export const EXTENSIONS_VIEW_ID = 'workbench-kit.builtin.extensions.panel' as const;
|
|
5
|
+
export const EXTENSIONS_VIEW_RENDER_KIND = 'workbench-kit.builtin.extensions.view' as const;
|
|
6
|
+
export const FOCUS_EXTENSIONS_COMMAND_ID = 'workbench-kit.builtin.extensions.focus' as const;
|
|
7
|
+
|
|
8
|
+
export interface BuiltinExtensionsViewRenderData {
|
|
9
|
+
readonly kind: typeof EXTENSIONS_VIEW_RENDER_KIND;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function activate(context: ExtensionContext): void {
|
|
13
|
+
context.commands.registerCommand(FOCUS_EXTENSIONS_COMMAND_ID, () => ({
|
|
14
|
+
focused: true,
|
|
15
|
+
viewId: EXTENSIONS_VIEW_ID,
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
context.views.registerViewProvider({
|
|
19
|
+
viewId: EXTENSIONS_VIEW_ID,
|
|
20
|
+
resolveViewHost: () => ({
|
|
21
|
+
dispose() {},
|
|
22
|
+
render: (): BuiltinExtensionsViewRenderData => ({
|
|
23
|
+
kind: EXTENSIONS_VIEW_RENDER_KIND,
|
|
24
|
+
}),
|
|
25
|
+
title: 'Extensions',
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
}
|