or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-framework.mdcommands.mddependency-injection.mdevents-messaging.mdindex.mdkeybindings.mdmenus.mdpreferences-configuration.mdresources-files.mdwidgets-ui.md

commands.mddocs/

0

# Command System

1

2

Theia's command system provides centralized command registry with handler prioritization, context awareness, and event-driven lifecycle management for building extensible applications.

3

4

## Capabilities

5

6

### Command Definition

7

8

Define commands that can be executed throughout the application.

9

10

```typescript { .api }

11

/**

12

* Command definition interface

13

*/

14

interface Command {

15

/** Unique command identifier */

16

id: string;

17

/** Human-readable label for UI display */

18

label?: string;

19

/** CSS class for command icon */

20

iconClass?: string;

21

/** Short title used for display in menus */

22

shortTitle?: string;

23

/** Category for grouping commands */

24

category?: string;

25

/** Original label before localization */

26

originalLabel?: string;

27

/** Original category before localization */

28

originalCategory?: string;

29

}

30

31

/**

32

* Command utility functions

33

*/

34

namespace Command {

35

/**

36

* Determine whether object is a Command

37

* @param arg - Object to test

38

* @returns True if object is a Command

39

*/

40

function is(arg: unknown): arg is Command;

41

42

/**

43

* Utility function to easily translate commands

44

* @param command - Command to localize

45

* @param nlsLabelKey - NLS key for label (defaults to command.id)

46

* @param nlsCategoryKey - NLS key for category

47

* @returns Localized command

48

*/

49

function toLocalizedCommand(command: Command, nlsLabelKey?: string, nlsCategoryKey?: string): Command;

50

51

/**

52

* Convert command to default localized version

53

* @param command - Command to localize

54

* @returns Default localized command

55

*/

56

function toDefaultLocalizedCommand(command: Command): Command;

57

58

/**

59

* Comparator function for sorting commands

60

* @param a - First command

61

* @param b - Second command

62

* @returns Comparison result

63

*/

64

function compareCommands(a: Command, b: Command): number;

65

66

/**

67

* Determine if two commands are equal

68

* @param a - First command for comparison

69

* @param b - Second command for comparison

70

* @returns True if commands are equal

71

*/

72

function equals(a: Command, b: Command): boolean;

73

}

74

```

75

76

**Usage Example:**

77

78

```typescript

79

import { Command } from "@theia/core";

80

81

export const SAVE_COMMAND: Command = {

82

id: 'core.save',

83

label: 'Save',

84

iconClass: 'fa fa-save',

85

category: 'File'

86

};

87

88

export const CUSTOM_COMMAND: Command = {

89

id: 'my-extension.custom-action',

90

label: 'Custom Action',

91

category: 'Custom'

92

};

93

```

94

95

### Command Handler

96

97

Implement command execution logic with optional enablement and visibility conditions.

98

99

```typescript { .api }

100

/**

101

* Command handler interface

102

*/

103

interface CommandHandler {

104

/**

105

* Execute the command with optional arguments

106

* @param args - Command arguments

107

* @returns Command result or promise

108

*/

109

execute(...args: any[]): any;

110

111

/**

112

* Determine if command is enabled in current context

113

* @param args - Command arguments

114

* @returns True if command should be enabled

115

*/

116

isEnabled?(...args: any[]): boolean;

117

118

/**

119

* Determine if command is visible in current context

120

* @param args - Command arguments

121

* @returns True if command should be visible

122

*/

123

isVisible?(...args: any[]): boolean;

124

125

/**

126

* Determine if command should toggle state

127

* @param args - Command arguments

128

* @returns True if command is in toggled state

129

*/

130

isToggled?(...args: any[]): boolean;

131

}

132

```

133

134

**Usage Examples:**

135

136

```typescript

137

import { CommandHandler } from "@theia/core";

138

139

// Simple command handler

140

const saveHandler: CommandHandler = {

141

execute: () => {

142

console.log("Save executed");

143

return "saved";

144

}

145

};

146

147

// Context-aware command handler

148

const conditionalHandler: CommandHandler = {

149

execute: (uri: string) => {

150

console.log(`Processing: ${uri}`);

151

},

152

153

isEnabled: (uri: string) => {

154

return uri && uri.endsWith('.txt');

155

},

156

157

isVisible: (uri: string) => {

158

return uri !== undefined;

159

}

160

};

161

```

162

163

### Command Registry

164

165

Central registry for registering commands and handlers with execution capabilities.

166

167

```typescript { .api }

168

/**

169

* Command registry interface

170

*/

171

interface CommandRegistry {

172

/**

173

* Register a command with optional handler

174

* @param command - Command definition

175

* @param handler - Optional command handler

176

* @returns Disposable to unregister the command

177

*/

178

registerCommand(command: Command, handler?: CommandHandler): Disposable;

179

180

/**

181

* Unregister command from the registry

182

* @param command - Command to unregister

183

*/

184

unregisterCommand(command: Command): void;

185

186

/**

187

* Unregister command from the registry

188

* @param id - Command ID to unregister

189

*/

190

unregisterCommand(id: string): void;

191

192

/**

193

* Register a handler for a command ID

194

* @param commandId - Command ID

195

* @param handler - Command handler

196

* @returns Disposable to unregister the handler

197

*/

198

registerHandler(commandId: string, handler: CommandHandler): Disposable;

199

200

/**

201

* Execute a command by ID with arguments

202

* @param id - Command ID

203

* @param args - Command arguments

204

* @returns Promise resolving to command result

205

*/

206

executeCommand<T>(id: string, ...args: any[]): Promise<T | undefined>;

207

208

/**

209

* Get all registered commands with their handlers

210

* @returns Iterator of commands with handlers

211

*/

212

getAllCommands(): IterableIterator<Readonly<Command & { handlers: CommandHandler[] }>>;

213

214

/**

215

* Get all handlers for a command

216

* @param commandId - Command ID

217

* @returns Array of handlers for the command

218

*/

219

getAllHandlers(commandId: string): CommandHandler[];

220

221

/**

222

* Get command by ID

223

* @param id - Command ID

224

* @returns Command definition or undefined

225

*/

226

getCommand(id: string): Command | undefined;

227

228

/**

229

* Get all registered command objects

230

* @returns Array of all registered commands

231

*/

232

readonly commands: Command[];

233

234

/**

235

* Get all registered command IDs

236

* @returns Array of all command IDs

237

*/

238

readonly commandIds: string[];

239

240

/**

241

* Get visible handler for command

242

* @param commandId - Command ID

243

* @param args - Command arguments

244

* @returns Visible handler or undefined

245

*/

246

getVisibleHandler(commandId: string, ...args: any[]): CommandHandler | undefined;

247

248

/**

249

* Get active handler for command

250

* @param commandId - Command ID

251

* @param args - Command arguments

252

* @returns Active handler or undefined

253

*/

254

getActiveHandler(commandId: string, ...args: any[]): CommandHandler | undefined;

255

256

/**

257

* Get toggled handler for command

258

* @param commandId - Command ID

259

* @param args - Command arguments

260

* @returns Toggled handler or undefined

261

*/

262

getToggledHandler(commandId: string, ...args: any[]): CommandHandler | undefined;

263

264

/**

265

* Check if command is enabled

266

* @param id - Command ID

267

* @param args - Command arguments

268

* @returns True if command is enabled

269

*/

270

isEnabled(id: string, ...args: any[]): boolean;

271

272

/**

273

* Check if command is visible

274

* @param id - Command ID

275

* @param args - Command arguments

276

* @returns True if command is visible

277

*/

278

isVisible(id: string, ...args: any[]): boolean;

279

280

/**

281

* Check if command is toggled

282

* @param id - Command ID

283

* @param args - Command arguments

284

* @returns True if command is toggled

285

*/

286

isToggled(id: string, ...args: any[]): boolean;

287

288

/**

289

* Get the list of recently used commands

290

*/

291

recent: Command[];

292

293

/**

294

* Add a command to recently used list

295

* @param recent - Recent command or array of commands

296

*/

297

addRecentCommand(recent: Command | Command[]): void;

298

299

/**

300

* Clear the list of recently used commands

301

*/

302

clearCommandHistory(): void;

303

304

/**

305

* Event fired when commands change

306

*/

307

readonly onCommandsChanged: Event<void>;

308

309

/**

310

* Event fired before command execution

311

*/

312

readonly onWillExecuteCommand: Event<WillExecuteCommandEvent>;

313

314

/**

315

* Event fired after command execution

316

*/

317

readonly onDidExecuteCommand: Event<CommandEvent>;

318

}

319

320

/**

321

* Command event types

322

*/

323

interface CommandEvent {

324

commandId: string;

325

args: any[];

326

}

327

328

interface WillExecuteCommandEvent {

329

commandId: string;

330

args: any[];

331

waitUntil(thenable: Promise<any>): void;

332

}

333

334

/**

335

* Service token for CommandRegistry

336

*/

337

const CommandRegistry: symbol;

338

```

339

340

**Usage Example:**

341

342

```typescript

343

import { inject, injectable } from "@theia/core";

344

import { CommandRegistry, Command, CommandHandler } from "@theia/core";

345

346

@injectable()

347

export class MyCommandManager {

348

constructor(

349

@inject(CommandRegistry) private readonly commands: CommandRegistry

350

) {}

351

352

registerCommands(): void {

353

// Register command with handler

354

this.commands.registerCommand(SAVE_COMMAND, {

355

execute: () => this.save()

356

});

357

358

// Register command without handler (handler added later)

359

this.commands.registerCommand(CUSTOM_COMMAND);

360

}

361

362

async executeCustomCommand(): Promise<void> {

363

const result = await this.commands.executeCommand('my-extension.custom-action');

364

console.log('Command result:', result);

365

}

366

367

private save(): void {

368

console.log("Saving...");

369

}

370

}

371

```

372

373

### Command Service

374

375

High-level service interface for command execution.

376

377

```typescript { .api }

378

/**

379

* Command service interface

380

*/

381

interface CommandService {

382

/**

383

* Execute a command by ID

384

* @param id - Command ID

385

* @param args - Command arguments

386

* @returns Promise resolving to command result

387

*/

388

executeCommand<T>(id: string, ...args: any[]): Promise<T | undefined>;

389

}

390

391

/**

392

* Service token for CommandService

393

*/

394

const CommandService: symbol;

395

```

396

397

### Command Contribution

398

399

Extension point for contributing commands to the application.

400

401

```typescript { .api }

402

/**

403

* Command contribution interface for extensions

404

*/

405

interface CommandContribution {

406

/**

407

* Register commands with the command registry

408

* @param commands - Command registry instance

409

*/

410

registerCommands(commands: CommandRegistry): void;

411

}

412

413

/**

414

* Service token for CommandContribution

415

*/

416

const CommandContribution: symbol;

417

```

418

419

**Usage Example:**

420

421

```typescript

422

import { injectable } from "@theia/core";

423

import { CommandContribution, CommandRegistry } from "@theia/core";

424

425

@injectable()

426

export class MyCommandContribution implements CommandContribution {

427

428

registerCommands(registry: CommandRegistry): void {

429

registry.registerCommand({

430

id: 'my-extension.hello',

431

label: 'Say Hello',

432

category: 'Demo'

433

}, {

434

execute: () => {

435

console.log('Hello from my extension!');

436

return 'Hello executed';

437

},

438

isEnabled: () => true,

439

isVisible: () => true

440

});

441

442

registry.registerCommand({

443

id: 'my-extension.toggle',

444

label: 'Toggle Feature',

445

category: 'Demo'

446

}, {

447

execute: () => {

448

this.toggleFeature();

449

},

450

isToggled: () => this.isFeatureEnabled()

451

});

452

}

453

454

private toggleFeature(): void {

455

// Toggle implementation

456

}

457

458

private isFeatureEnabled(): boolean {

459

// Return current state

460

return false;

461

}

462

}

463

```

464

465

### Command Events

466

467

Events related to command execution lifecycle.

468

469

```typescript { .api }

470

/**

471

* Command event fired when command is executed

472

*/

473

interface CommandEvent {

474

/** Command ID that was executed */

475

commandId: string;

476

/** Arguments passed to command */

477

args: any[];

478

}

479

480

/**

481

* Event fired before command execution

482

*/

483

interface WillExecuteCommandEvent {

484

/** Command ID about to be executed */

485

commandId: string;

486

/** Arguments to be passed to command */

487

args: any[];

488

}

489

```

490

491

## Advanced Usage Patterns

492

493

### Handler Prioritization

494

495

Register multiple handlers for the same command with priority:

496

497

```typescript

498

// Higher priority handler (registered later wins)

499

registry.registerCommand(SAVE_COMMAND, primarySaveHandler);

500

registry.registerCommand(SAVE_COMMAND, fallbackSaveHandler);

501

```

502

503

### Conditional Commands

504

505

Create commands that adapt to context:

506

507

```typescript

508

const CONTEXT_COMMAND: Command = {

509

id: 'context.action',

510

label: 'Context Action'

511

};

512

513

const contextHandler: CommandHandler = {

514

execute: (context: any) => {

515

if (context.type === 'file') {

516

return this.handleFile(context);

517

} else if (context.type === 'folder') {

518

return this.handleFolder(context);

519

}

520

},

521

522

isEnabled: (context: any) => {

523

return context && (context.type === 'file' || context.type === 'folder');

524

},

525

526

isVisible: (context: any) => {

527

return context !== undefined;

528

}

529

};

530

```

531

532

### Command Chaining

533

534

Execute multiple commands in sequence:

535

536

```typescript

537

async executeCommandChain(): Promise<void> {

538

await this.commands.executeCommand('prepare.action');

539

const result = await this.commands.executeCommand('main.action', result);

540

await this.commands.executeCommand('cleanup.action', result);

541

}

542

```

543

544

## Types

545

546

```typescript { .api }

547

/**

548

* Command utilities namespace

549

*/

550

namespace Command {

551

/**

552

* Type predicate to check if object is a Command

553

* @param arg - Object to check

554

* @returns True if object is a Command

555

*/

556

function is(arg: any): arg is Command;

557

558

/**

559

* Compare two commands for equality

560

* @param a - First command

561

* @param b - Second command

562

* @returns True if commands are equal

563

*/

564

function equals(a: Command, b: Command): boolean;

565

}

566

567

/**

568

* Disposable interface for cleaning up registrations

569

*/

570

interface Disposable {

571

dispose(): void;

572

}

573

```