Theia workspace extension providing workspace functionality and services for Eclipse Theia IDE framework
—
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.
All workspace-related command constants with their definitions.
namespace WorkspaceCommands {
// File/Workspace Opening Commands
const OPEN: Command & { dialogLabel: string };
const OPEN_FILE: Command & { dialogLabel: string };
const OPEN_FOLDER: Command & { dialogLabel: string };
const OPEN_WORKSPACE: Command & { dialogLabel: string };
const OPEN_RECENT_WORKSPACE: Command;
const CLOSE: Command;
// File Operations Commands
const NEW_FILE: Command;
const NEW_FOLDER: Command;
const FILE_RENAME: Command;
const FILE_DELETE: Command;
const FILE_DUPLICATE: Command;
const FILE_COMPARE: Command;
const COPY_RELATIVE_FILE_PATH: Command;
// Workspace Management Commands
const ADD_FOLDER: Command;
const REMOVE_FOLDER: Command;
const SAVE_WORKSPACE_AS: Command;
const OPEN_WORKSPACE_FILE: Command;
}Usage Example:
import { WorkspaceCommands } from "@theia/workspace/lib/browser";
import { CommandRegistry } from "@theia/core/lib/common";
// Execute workspace commands programmatically
registry.executeCommand(WorkspaceCommands.NEW_FILE.id);
registry.executeCommand(WorkspaceCommands.OPEN_WORKSPACE.id, workspaceUri);
registry.executeCommand(WorkspaceCommands.SAVE_WORKSPACE_AS.id);Main contribution class that registers all workspace commands and handles their execution.
class WorkspaceCommandContribution implements CommandContribution {
/**
* Event fired when a new file is created
*/
readonly onDidCreateNewFile: Event<DidCreateNewResourceEvent>;
/**
* Event fired when a new folder is created
*/
readonly onDidCreateNewFolder: Event<DidCreateNewResourceEvent>;
/**
* Register all workspace commands with the command registry
*/
registerCommands(registry: CommandRegistry): void;
/**
* Validate file name for creation operations
* @param name - Proposed file name
* @param parent - Parent directory
* @param allowNested - Whether to allow nested path creation
*/
protected validateFileName(name: string, parent: FileStat, allowNested?: boolean): Promise<string>;
}Usage Example:
import { injectable, inject } from "@theia/core/shared/inversify";
import { WorkspaceCommandContribution, DidCreateNewResourceEvent } from "@theia/workspace/lib/browser";
import { Disposable } from "@theia/core";
@injectable()
export class MyWorkspaceListener {
@inject(WorkspaceCommandContribution)
protected readonly workspaceCommands: WorkspaceCommandContribution;
protected readonly disposables = new DisposableCollection();
@postConstruct()
initialize(): void {
// Listen to file creation events
this.disposables.push(
this.workspaceCommands.onDidCreateNewFile(event => {
console.log(`New file created: ${event.uri}`);
console.log(`In directory: ${event.parent}`);
})
);
// Listen to folder creation events
this.disposables.push(
this.workspaceCommands.onDidCreateNewFolder(event => {
console.log(`New folder created: ${event.uri}`);
this.indexNewFolder(event.uri);
})
);
}
private indexNewFolder(uri: URI): void {
// Custom logic for handling new folders
}
}Specialized handlers for file operations with built-in validation and user interaction.
class WorkspaceDeleteHandler implements UriCommandHandler<URI[]> {
/**
* Check if delete operation is visible for given URIs
*/
isVisible(uris: URI[]): boolean;
/**
* Check if delete operation is enabled for given URIs
*/
isEnabled(uris: URI[]): boolean;
/**
* Execute delete operation for given URIs
*/
execute(uris: URI[]): Promise<void>;
}
class WorkspaceDuplicateHandler implements UriCommandHandler<URI[]> {
/**
* Check if duplicate operation is visible for given URIs
*/
isVisible(uris: URI[]): boolean;
/**
* Check if duplicate operation is enabled for given URIs
*/
isEnabled(uris: URI[]): boolean;
/**
* Execute duplicate operation for given URIs
*/
execute(uris: URI[]): Promise<void>;
}
class WorkspaceCompareHandler implements UriCommandHandler<URI[]> {
/**
* Check if compare operation is visible for given URIs
*/
isVisible(uris: URI[]): boolean;
/**
* Check if compare operation is enabled for given URIs
*/
isEnabled(uris: URI[]): boolean;
/**
* Execute compare operation for given URIs
*/
execute(uris: URI[]): Promise<void>;
}Usage Example:
import { injectable, inject } from "@theia/core/shared/inversify";
import { WorkspaceDeleteHandler, WorkspaceDuplicateHandler } from "@theia/workspace/lib/browser";
import URI from "@theia/core/lib/common/uri";
@injectable()
export class MyFileOperations {
@inject(WorkspaceDeleteHandler)
protected readonly deleteHandler: WorkspaceDeleteHandler;
@inject(WorkspaceDuplicateHandler)
protected readonly duplicateHandler: WorkspaceDuplicateHandler;
async deleteFiles(fileUris: URI[]): Promise<void> {
if (this.deleteHandler.isEnabled(fileUris)) {
await this.deleteHandler.execute(fileUris);
}
}
async duplicateFiles(fileUris: URI[]): Promise<void> {
if (this.duplicateHandler.isEnabled(fileUris)) {
await this.duplicateHandler.execute(fileUris);
}
}
}Menu contributions for file and edit menus with workspace-specific entries.
class FileMenuContribution implements MenuContribution {
/**
* Register file menu entries for workspace operations
*/
registerMenus(registry: MenuModelRegistry): void;
}
class EditMenuContribution implements MenuContribution {
/**
* Register edit menu entries for workspace operations
*/
registerMenus(registry: MenuModelRegistry): void;
}Usage Example:
import { injectable } from "@theia/core/shared/inversify";
import { MenuContribution, MenuModelRegistry } from "@theia/core/lib/common";
import { WorkspaceCommands } from "@theia/workspace/lib/browser";
@injectable()
export class CustomWorkspaceMenuContribution implements MenuContribution {
registerMenus(registry: MenuModelRegistry): void {
// Add custom menu items to workspace menu
registry.registerMenuAction(CommonMenus.FILE_NEW, {
commandId: WorkspaceCommands.NEW_FILE.id,
label: 'New File...',
order: '10'
});
registry.registerMenuAction(['my-custom-menu'], {
commandId: WorkspaceCommands.SAVE_WORKSPACE_AS.id,
label: 'Save Workspace As...'
});
}
}URI-aware command handlers for workspace-specific operations.
class WorkspaceRootUriAwareCommandHandler extends UriAwareCommandHandler<URI> {
/**
* Check if command is enabled for current context
*/
isEnabled(...args: any[]): boolean;
/**
* Check if command is visible for current context
*/
isVisible(...args: any[]): boolean;
/**
* Get URI from command arguments
*/
protected getUri(...args: any[]): URI | undefined;
}Usage Example:
import { injectable, inject } from "@theia/core/shared/inversify";
import { WorkspaceRootUriAwareCommandHandler, WorkspaceService } from "@theia/workspace/lib/browser";
import { SelectionService } from "@theia/core/lib/common";
@injectable()
export class MyCustomCommandHandler extends WorkspaceRootUriAwareCommandHandler {
constructor(
@inject(WorkspaceService) workspaceService: WorkspaceService,
@inject(SelectionService) selectionService: SelectionService
) {
super(workspaceService, selectionService, {
execute: (uri: URI) => this.executeCustomCommand(uri),
isEnabled: (uri: URI) => this.isCustomCommandEnabled(uri),
isVisible: (uri: URI) => this.isCustomCommandVisible(uri)
});
}
private executeCustomCommand(uri: URI): void {
console.log(`Executing custom command on workspace root: ${uri}`);
}
private isCustomCommandEnabled(uri: URI): boolean {
return this.workspaceService.areWorkspaceRoots([uri]);
}
private isCustomCommandVisible(uri: URI): boolean {
return true;
}
}Utility functions for workspace operations and validation.
class WorkspaceUtils {
/**
* Determine if root directory exists for a given array of URIs
* @param uris - Array of URIs to check
*/
containsRootDirectory(uris: URI[]): boolean;
}Usage Example:
import { injectable, inject } from "@theia/core/shared/inversify";
import { WorkspaceUtils } from "@theia/workspace/lib/browser";
import URI from "@theia/core/lib/common/uri";
@injectable()
export class MyWorkspaceValidator {
@inject(WorkspaceUtils)
protected readonly workspaceUtils: WorkspaceUtils;
validateSelection(uris: URI[]): boolean {
// Check if selection contains workspace root directories
if (this.workspaceUtils.containsRootDirectory(uris)) {
console.log("Selection contains workspace root directories");
return false; // May want to prevent certain operations on roots
}
return true;
}
}Specialized dialog for workspace file/folder creation with path validation.
class WorkspaceInputDialog extends SingleTextInputDialog {
constructor(
props: WorkspaceInputDialogProps,
labelProvider: LabelProvider
);
/**
* Append parent path information to dialog
*/
protected appendParentPath(): void;
}
class WorkspaceInputDialogProps extends SingleTextInputDialogProps {
/**
* The parent URI for the selection present in the explorer.
* Used to display the path in which the file/folder is created at.
*/
parentUri: URI;
}interface DidCreateNewResourceEvent {
/** The URI of the created resource */
uri: URI;
/** The URI of the parent directory */
parent: URI;
}
enum WorkspaceStates {
/** The state is `empty` when no workspace is opened */
empty = 'empty',
/** The state is `workspace` when a workspace is opened */
workspace = 'workspace',
/** The state is `folder` when a folder is opened (1 folder) */
folder = 'folder'
}
type WorkspaceState = keyof typeof WorkspaceStates;
type WorkbenchState = keyof typeof WorkspaceStates;
interface Command {
id: string;
category?: string;
label?: string;
iconClass?: string;
tooltip?: string;
}
interface UriCommandHandler<T> {
execute(uri: T, ...args: any[]): any;
isVisible?(uri: T, ...args: any[]): boolean;
isEnabled?(uri: T, ...args: any[]): boolean;
}Install with Tessl CLI
npx tessl i tessl/npm-theia--workspace