Commands API
The Commands API allows you to register custom commands, execute existing commands, and manage keyboard shortcuts in Trae IDE.
Overview
The Commands API enables you to:
- Register custom commands
- Execute built-in and custom commands
- Handle command parameters
- Create keyboard shortcuts
- Manage command lifecycle
Basic Usage
Registering Commands
typescript
import { TraeAPI } from '@trae/api';
// Register a simple command
const disposable = TraeAPI.commands.registerCommand('myExtension.helloWorld', () => {
TraeAPI.window.showInformationMessage('Hello World!');
});
// Register command with parameters
TraeAPI.commands.registerCommand('myExtension.greet', (name: string) => {
TraeAPI.window.showInformationMessage(`Hello, ${name}!`);
});
// Register async command
TraeAPI.commands.registerCommand('myExtension.asyncOperation', async () => {
try {
const result = await performAsyncOperation();
TraeAPI.window.showInformationMessage(`Result: ${result}`);
} catch (error) {
TraeAPI.window.showErrorMessage(`Error: ${error.message}`);
}
});Executing Commands
typescript
// Execute a command
await TraeAPI.commands.executeCommand('workbench.action.files.save');
// Execute command with parameters
await TraeAPI.commands.executeCommand('myExtension.greet', 'Alice');
// Execute command and get result
const result = await TraeAPI.commands.executeCommand<string>('myExtension.getData');
console.log('Command result:', result);Getting Available Commands
typescript
// Get all available commands
const commands = await TraeAPI.commands.getCommands();
console.log('Available commands:', commands);
// Filter commands
const myCommands = commands.filter(cmd => cmd.startsWith('myExtension.'));Command Registration
Command with Context
typescript
class MyExtension {
private context: TraeAPI.ExtensionContext;
constructor(context: TraeAPI.ExtensionContext) {
this.context = context;
this.registerCommands();
}
private registerCommands() {
// Register command with class method
const disposable = TraeAPI.commands.registerCommand(
'myExtension.processFile',
this.processFile.bind(this)
);
this.context.subscriptions.push(disposable);
}
private async processFile(uri?: TraeAPI.Uri) {
const fileUri = uri || TraeAPI.window.activeTextEditor?.document.uri;
if (!fileUri) {
TraeAPI.window.showErrorMessage('No file selected');
return;
}
// Process the file
const document = await TraeAPI.workspace.openTextDocument(fileUri);
console.log(`Processing file: ${document.fileName}`);
}
}Command with Validation
typescript
TraeAPI.commands.registerCommand('myExtension.validateAndRun', async (...args) => {
// Validate arguments
if (args.length === 0) {
TraeAPI.window.showErrorMessage('Command requires at least one argument');
return;
}
const [firstArg] = args;
if (typeof firstArg !== 'string') {
TraeAPI.window.showErrorMessage('First argument must be a string');
return;
}
// Execute command logic
console.log('Executing with argument:', firstArg);
});Built-in Commands
File Operations
typescript
// Save current file
await TraeAPI.commands.executeCommand('workbench.action.files.save');
// Save all files
await TraeAPI.commands.executeCommand('workbench.action.files.saveAll');
// Open file
await TraeAPI.commands.executeCommand('workbench.action.files.openFile');
// New file
await TraeAPI.commands.executeCommand('workbench.action.files.newUntitledFile');Editor Operations
typescript
// Format document
await TraeAPI.commands.executeCommand('editor.action.formatDocument');
// Go to definition
await TraeAPI.commands.executeCommand('editor.action.revealDefinition');
// Find and replace
await TraeAPI.commands.executeCommand('editor.action.startFindReplaceAction');
// Comment/uncomment lines
await TraeAPI.commands.executeCommand('editor.action.commentLine');Workspace Operations
typescript
// Open folder
await TraeAPI.commands.executeCommand('workbench.action.files.openFolder');
// Close workspace
await TraeAPI.commands.executeCommand('workbench.action.closeFolder');
// Reload window
await TraeAPI.commands.executeCommand('workbench.action.reloadWindow');Keyboard Shortcuts
Defining Shortcuts in package.json
json
{
"contributes": {
"commands": [
{
"command": "myExtension.quickAction",
"title": "Quick Action",
"category": "My Extension"
}
],
"keybindings": [
{
"command": "myExtension.quickAction",
"key": "ctrl+shift+q",
"mac": "cmd+shift+q",
"when": "editorTextFocus"
}
]
}
}Conditional Keybindings
json
{
"keybindings": [
{
"command": "myExtension.debugAction",
"key": "f5",
"when": "debuggersAvailable && !inDebugMode"
},
{
"command": "myExtension.testAction",
"key": "ctrl+t",
"when": "resourceExtname == .test.js"
}
]
}Command Palette Integration
Adding Commands to Palette
json
{
"contributes": {
"commands": [
{
"command": "myExtension.analyze",
"title": "Analyze Code",
"category": "Code Analysis",
"icon": "$(search)"
}
]
}
}Context Menu Integration
json
{
"contributes": {
"menus": {
"editor/context": [
{
"command": "myExtension.refactor",
"when": "editorHasSelection",
"group": "1_modification"
}
],
"explorer/context": [
{
"command": "myExtension.processFile",
"when": "resourceExtname == .js"
}
]
}
}
}Advanced Usage
Command Chaining
typescript
TraeAPI.commands.registerCommand('myExtension.complexOperation', async () => {
// Chain multiple commands
await TraeAPI.commands.executeCommand('editor.action.selectAll');
await TraeAPI.commands.executeCommand('editor.action.formatSelection');
await TraeAPI.commands.executeCommand('workbench.action.files.save');
TraeAPI.window.showInformationMessage('Complex operation completed');
});Command with Progress
typescript
TraeAPI.commands.registerCommand('myExtension.longRunningTask', async () => {
await TraeAPI.window.withProgress({
location: TraeAPI.ProgressLocation.Notification,
title: 'Processing...',
cancellable: true
}, async (progress, token) => {
for (let i = 0; i < 100; i++) {
if (token.isCancellationRequested) {
break;
}
progress.report({ increment: 1, message: `Step ${i + 1}/100` });
await new Promise(resolve => setTimeout(resolve, 50));
}
});
});Command with User Input
typescript
TraeAPI.commands.registerCommand('myExtension.createFile', async () => {
const fileName = await TraeAPI.window.showInputBox({
prompt: 'Enter file name',
placeHolder: 'example.txt'
});
if (!fileName) {
return;
}
const fileType = await TraeAPI.window.showQuickPick(
['JavaScript', 'TypeScript', 'JSON', 'Markdown'],
{ placeHolder: 'Select file type' }
);
if (fileType) {
// Create file based on user input
await createFileWithType(fileName, fileType);
}
});API Reference
registerCommand()
typescript
registerCommand(
command: string,
callback: (...args: any[]) => any,
thisArg?: any
): Disposable;executeCommand()
typescript
executeCommand<T = unknown>(
command: string,
...rest: any[]
): Thenable<T | undefined>;getCommands()
typescript
getCommands(filterInternal?: boolean): Thenable<string[]>;Best Practices
- Use descriptive command names with extension prefix
- Handle errors gracefully in command handlers
- Provide user feedback for long-running operations
- Validate command parameters before execution
- Dispose of command registrations properly
- Use appropriate keyboard shortcuts that don't conflict
- Add commands to appropriate menus for discoverability
Error Handling
typescript
TraeAPI.commands.registerCommand('myExtension.safeCommand', async () => {
try {
const result = await riskyOperation();
TraeAPI.window.showInformationMessage(`Success: ${result}`);
} catch (error) {
console.error('Command failed:', error);
TraeAPI.window.showErrorMessage(`Failed: ${error.message}`);
}
});Testing Commands
typescript
// In test file
import * as assert from 'assert';
import { TraeAPI } from '@trae/api';
suite('Command Tests', () => {
test('should execute custom command', async () => {
const result = await TraeAPI.commands.executeCommand('myExtension.testCommand');
assert.strictEqual(result, 'expected result');
});
});Related APIs
- UI API - For creating command interfaces
- Editor API - For editor-specific commands
- Workspace API - For workspace commands