0
# Workspace Commands
1
2
The workspace commands module provides all command definitions, handlers, and menu contributions for workspace operations. It includes file management, workspace opening/closing, and folder operations with comprehensive event handling and extensibility points.
3
4
## Capabilities
5
6
### Command Definitions
7
8
All workspace-related command constants with their definitions.
9
10
```typescript { .api }
11
namespace WorkspaceCommands {
12
// File/Workspace Opening Commands
13
const OPEN: Command & { dialogLabel: string };
14
const OPEN_FILE: Command & { dialogLabel: string };
15
const OPEN_FOLDER: Command & { dialogLabel: string };
16
const OPEN_WORKSPACE: Command & { dialogLabel: string };
17
const OPEN_RECENT_WORKSPACE: Command;
18
const CLOSE: Command;
19
20
// File Operations Commands
21
const NEW_FILE: Command;
22
const NEW_FOLDER: Command;
23
const FILE_RENAME: Command;
24
const FILE_DELETE: Command;
25
const FILE_DUPLICATE: Command;
26
const FILE_COMPARE: Command;
27
const COPY_RELATIVE_FILE_PATH: Command;
28
29
// Workspace Management Commands
30
const ADD_FOLDER: Command;
31
const REMOVE_FOLDER: Command;
32
const SAVE_WORKSPACE_AS: Command;
33
const OPEN_WORKSPACE_FILE: Command;
34
}
35
```
36
37
**Usage Example:**
38
39
```typescript
40
import { WorkspaceCommands } from "@theia/workspace/lib/browser";
41
import { CommandRegistry } from "@theia/core/lib/common";
42
43
// Execute workspace commands programmatically
44
registry.executeCommand(WorkspaceCommands.NEW_FILE.id);
45
registry.executeCommand(WorkspaceCommands.OPEN_WORKSPACE.id, workspaceUri);
46
registry.executeCommand(WorkspaceCommands.SAVE_WORKSPACE_AS.id);
47
```
48
49
### Command Contribution
50
51
Main contribution class that registers all workspace commands and handles their execution.
52
53
```typescript { .api }
54
class WorkspaceCommandContribution implements CommandContribution {
55
/**
56
* Event fired when a new file is created
57
*/
58
readonly onDidCreateNewFile: Event<DidCreateNewResourceEvent>;
59
60
/**
61
* Event fired when a new folder is created
62
*/
63
readonly onDidCreateNewFolder: Event<DidCreateNewResourceEvent>;
64
65
/**
66
* Register all workspace commands with the command registry
67
*/
68
registerCommands(registry: CommandRegistry): void;
69
70
/**
71
* Validate file name for creation operations
72
* @param name - Proposed file name
73
* @param parent - Parent directory
74
* @param allowNested - Whether to allow nested path creation
75
*/
76
protected validateFileName(name: string, parent: FileStat, allowNested?: boolean): Promise<string>;
77
}
78
```
79
80
**Usage Example:**
81
82
```typescript
83
import { injectable, inject } from "@theia/core/shared/inversify";
84
import { WorkspaceCommandContribution, DidCreateNewResourceEvent } from "@theia/workspace/lib/browser";
85
import { Disposable } from "@theia/core";
86
87
@injectable()
88
export class MyWorkspaceListener {
89
90
@inject(WorkspaceCommandContribution)
91
protected readonly workspaceCommands: WorkspaceCommandContribution;
92
93
protected readonly disposables = new DisposableCollection();
94
95
@postConstruct()
96
initialize(): void {
97
// Listen to file creation events
98
this.disposables.push(
99
this.workspaceCommands.onDidCreateNewFile(event => {
100
console.log(`New file created: ${event.uri}`);
101
console.log(`In directory: ${event.parent}`);
102
})
103
);
104
105
// Listen to folder creation events
106
this.disposables.push(
107
this.workspaceCommands.onDidCreateNewFolder(event => {
108
console.log(`New folder created: ${event.uri}`);
109
this.indexNewFolder(event.uri);
110
})
111
);
112
}
113
114
private indexNewFolder(uri: URI): void {
115
// Custom logic for handling new folders
116
}
117
}
118
```
119
120
### File Operation Handlers
121
122
Specialized handlers for file operations with built-in validation and user interaction.
123
124
```typescript { .api }
125
class WorkspaceDeleteHandler implements UriCommandHandler<URI[]> {
126
/**
127
* Check if delete operation is visible for given URIs
128
*/
129
isVisible(uris: URI[]): boolean;
130
131
/**
132
* Check if delete operation is enabled for given URIs
133
*/
134
isEnabled(uris: URI[]): boolean;
135
136
/**
137
* Execute delete operation for given URIs
138
*/
139
execute(uris: URI[]): Promise<void>;
140
}
141
142
class WorkspaceDuplicateHandler implements UriCommandHandler<URI[]> {
143
/**
144
* Check if duplicate operation is visible for given URIs
145
*/
146
isVisible(uris: URI[]): boolean;
147
148
/**
149
* Check if duplicate operation is enabled for given URIs
150
*/
151
isEnabled(uris: URI[]): boolean;
152
153
/**
154
* Execute duplicate operation for given URIs
155
*/
156
execute(uris: URI[]): Promise<void>;
157
}
158
159
class WorkspaceCompareHandler implements UriCommandHandler<URI[]> {
160
/**
161
* Check if compare operation is visible for given URIs
162
*/
163
isVisible(uris: URI[]): boolean;
164
165
/**
166
* Check if compare operation is enabled for given URIs
167
*/
168
isEnabled(uris: URI[]): boolean;
169
170
/**
171
* Execute compare operation for given URIs
172
*/
173
execute(uris: URI[]): Promise<void>;
174
}
175
```
176
177
**Usage Example:**
178
179
```typescript
180
import { injectable, inject } from "@theia/core/shared/inversify";
181
import { WorkspaceDeleteHandler, WorkspaceDuplicateHandler } from "@theia/workspace/lib/browser";
182
import URI from "@theia/core/lib/common/uri";
183
184
@injectable()
185
export class MyFileOperations {
186
187
@inject(WorkspaceDeleteHandler)
188
protected readonly deleteHandler: WorkspaceDeleteHandler;
189
190
@inject(WorkspaceDuplicateHandler)
191
protected readonly duplicateHandler: WorkspaceDuplicateHandler;
192
193
async deleteFiles(fileUris: URI[]): Promise<void> {
194
if (this.deleteHandler.isEnabled(fileUris)) {
195
await this.deleteHandler.execute(fileUris);
196
}
197
}
198
199
async duplicateFiles(fileUris: URI[]): Promise<void> {
200
if (this.duplicateHandler.isEnabled(fileUris)) {
201
await this.duplicateHandler.execute(fileUris);
202
}
203
}
204
}
205
```
206
207
### Menu Contributions
208
209
Menu contributions for file and edit menus with workspace-specific entries.
210
211
```typescript { .api }
212
class FileMenuContribution implements MenuContribution {
213
/**
214
* Register file menu entries for workspace operations
215
*/
216
registerMenus(registry: MenuModelRegistry): void;
217
}
218
219
class EditMenuContribution implements MenuContribution {
220
/**
221
* Register edit menu entries for workspace operations
222
*/
223
registerMenus(registry: MenuModelRegistry): void;
224
}
225
```
226
227
**Usage Example:**
228
229
```typescript
230
import { injectable } from "@theia/core/shared/inversify";
231
import { MenuContribution, MenuModelRegistry } from "@theia/core/lib/common";
232
import { WorkspaceCommands } from "@theia/workspace/lib/browser";
233
234
@injectable()
235
export class CustomWorkspaceMenuContribution implements MenuContribution {
236
237
registerMenus(registry: MenuModelRegistry): void {
238
// Add custom menu items to workspace menu
239
registry.registerMenuAction(CommonMenus.FILE_NEW, {
240
commandId: WorkspaceCommands.NEW_FILE.id,
241
label: 'New File...',
242
order: '10'
243
});
244
245
registry.registerMenuAction(['my-custom-menu'], {
246
commandId: WorkspaceCommands.SAVE_WORKSPACE_AS.id,
247
label: 'Save Workspace As...'
248
});
249
}
250
}
251
```
252
253
### Specialized Command Handlers
254
255
URI-aware command handlers for workspace-specific operations.
256
257
```typescript { .api }
258
class WorkspaceRootUriAwareCommandHandler extends UriAwareCommandHandler<URI> {
259
/**
260
* Check if command is enabled for current context
261
*/
262
isEnabled(...args: any[]): boolean;
263
264
/**
265
* Check if command is visible for current context
266
*/
267
isVisible(...args: any[]): boolean;
268
269
/**
270
* Get URI from command arguments
271
*/
272
protected getUri(...args: any[]): URI | undefined;
273
}
274
```
275
276
**Usage Example:**
277
278
```typescript
279
import { injectable, inject } from "@theia/core/shared/inversify";
280
import { WorkspaceRootUriAwareCommandHandler, WorkspaceService } from "@theia/workspace/lib/browser";
281
import { SelectionService } from "@theia/core/lib/common";
282
283
@injectable()
284
export class MyCustomCommandHandler extends WorkspaceRootUriAwareCommandHandler {
285
286
constructor(
287
@inject(WorkspaceService) workspaceService: WorkspaceService,
288
@inject(SelectionService) selectionService: SelectionService
289
) {
290
super(workspaceService, selectionService, {
291
execute: (uri: URI) => this.executeCustomCommand(uri),
292
isEnabled: (uri: URI) => this.isCustomCommandEnabled(uri),
293
isVisible: (uri: URI) => this.isCustomCommandVisible(uri)
294
});
295
}
296
297
private executeCustomCommand(uri: URI): void {
298
console.log(`Executing custom command on workspace root: ${uri}`);
299
}
300
301
private isCustomCommandEnabled(uri: URI): boolean {
302
return this.workspaceService.areWorkspaceRoots([uri]);
303
}
304
305
private isCustomCommandVisible(uri: URI): boolean {
306
return true;
307
}
308
}
309
```
310
311
### Workspace Utilities
312
313
Utility functions for workspace operations and validation.
314
315
```typescript { .api }
316
class WorkspaceUtils {
317
/**
318
* Determine if root directory exists for a given array of URIs
319
* @param uris - Array of URIs to check
320
*/
321
containsRootDirectory(uris: URI[]): boolean;
322
}
323
```
324
325
**Usage Example:**
326
327
```typescript
328
import { injectable, inject } from "@theia/core/shared/inversify";
329
import { WorkspaceUtils } from "@theia/workspace/lib/browser";
330
import URI from "@theia/core/lib/common/uri";
331
332
@injectable()
333
export class MyWorkspaceValidator {
334
335
@inject(WorkspaceUtils)
336
protected readonly workspaceUtils: WorkspaceUtils;
337
338
validateSelection(uris: URI[]): boolean {
339
// Check if selection contains workspace root directories
340
if (this.workspaceUtils.containsRootDirectory(uris)) {
341
console.log("Selection contains workspace root directories");
342
return false; // May want to prevent certain operations on roots
343
}
344
return true;
345
}
346
}
347
```
348
349
### Input Dialog
350
351
Specialized dialog for workspace file/folder creation with path validation.
352
353
```typescript { .api }
354
class WorkspaceInputDialog extends SingleTextInputDialog {
355
constructor(
356
props: WorkspaceInputDialogProps,
357
labelProvider: LabelProvider
358
);
359
360
/**
361
* Append parent path information to dialog
362
*/
363
protected appendParentPath(): void;
364
}
365
366
class WorkspaceInputDialogProps extends SingleTextInputDialogProps {
367
/**
368
* The parent URI for the selection present in the explorer.
369
* Used to display the path in which the file/folder is created at.
370
*/
371
parentUri: URI;
372
}
373
```
374
375
## Types
376
377
```typescript { .api }
378
interface DidCreateNewResourceEvent {
379
/** The URI of the created resource */
380
uri: URI;
381
/** The URI of the parent directory */
382
parent: URI;
383
}
384
385
enum WorkspaceStates {
386
/** The state is `empty` when no workspace is opened */
387
empty = 'empty',
388
/** The state is `workspace` when a workspace is opened */
389
workspace = 'workspace',
390
/** The state is `folder` when a folder is opened (1 folder) */
391
folder = 'folder'
392
}
393
394
type WorkspaceState = keyof typeof WorkspaceStates;
395
type WorkbenchState = keyof typeof WorkspaceStates;
396
397
interface Command {
398
id: string;
399
category?: string;
400
label?: string;
401
iconClass?: string;
402
tooltip?: string;
403
}
404
405
interface UriCommandHandler<T> {
406
execute(uri: T, ...args: any[]): any;
407
isVisible?(uri: T, ...args: any[]): boolean;
408
isEnabled?(uri: T, ...args: any[]): boolean;
409
}
410
```