Command Architecture
About 4 min
Command Architecture
This chapter provides an in-depth look at the architecture design of the WebCAD command system, helping you understand how commands work.
Command Class Structure
main() Method Convention
Every command class must implement a main() method as the command entry point. This is the core convention of the WebCAD command system:
export class MyCommand {
async main(): Promise<void> {
// Command logic
}
}Characteristics of the main() method:
- Async method: Returns
Promise<void>, supportsawaitfor waiting on user input - No parameters: Command parameters are obtained through user interaction, not method parameters
- No return value: Command execution results are reflected through side effects (creating entities, modifying properties, etc.)
Complete Command Class Example
import { Point2D } from 'vjcad';
import { Engine } from 'vjcad';
import { LineEnt } from 'vjcad';
import {
getPoint,
PointInputOptions,
InputStatusEnum,
ssSetFirst,
writeMessage
} from 'vjcad';
export class SimpleLineCommand {
// State variables
private startPoint: Point2D = new Point2D();
private endPoint: Point2D = new Point2D();
constructor() {
// Initialize state
this.startPoint = new Point2D();
this.endPoint = new Point2D();
}
async main(): Promise<void> {
// Clear selection set
ssSetFirst([]);
// Start undo mark
Engine.undoManager.start_undoMark();
try {
// Get start point
const p1Options = new PointInputOptions("Specify first point:");
const p1Result = await getPoint(p1Options);
if (p1Result.status !== InputStatusEnum.OK) {
return; // User cancelled
}
this.startPoint = p1Result.value;
// Get end point
const p2Options = new PointInputOptions("Specify second point:");
p2Options.useBasePoint = true;
p2Options.basePoint = this.startPoint;
const p2Result = await getPoint(p2Options);
if (p2Result.status !== InputStatusEnum.OK) {
return; // User cancelled
}
this.endPoint = p2Result.value;
// Create line
const line = new LineEnt(this.startPoint, this.endPoint);
line.setDefaults();
Engine.pcanvas.addEntity(line);
Engine.undoManager.added_undoMark([line]);
writeMessage("<br/>Line created.");
} finally {
// Ensure undo mark is ended
Engine.undoManager.end_undoMark();
}
}
}Command Registration
CommandDefinition Class
CommandDefinition defines the metadata of a command:
import { CommandDefinition, CommandOptions } from 'vjcad';
const definition = new CommandDefinition(
'MYLINE', // Command name (uppercase)
'Draw simple line', // Description
SimpleLineCommand, // Command class
new CommandOptions() // Options
);| Parameter | Type | Description |
|---|---|---|
name | string | Command name, must be uppercase, users enter this name in the command line to execute the command |
description | string | Command description, displayed in command prompts and help |
commandClass | Class | Command class, must have a main() method |
options | CommandOptions | Command options |
CommandOptions in Detail
CommandOptions controls the behavioral characteristics of a command:
const options = new CommandOptions();
options.useAutoComplete = true; // Enable command line auto-complete
options.overrideSvgFileName = ''; // Custom icon file name| Property | Type | Default | Description |
|---|---|---|---|
useAutoComplete | boolean | true | Whether to show auto-complete when typing in the command line |
overrideSvgFileName | string | '' | Custom SVG file name for the command icon |
Registering Commands with CommandRegistry
Use CommandRegistry to register commands to the system:
import { CommandRegistry, CommandDefinition, CommandOptions } from 'vjcad';
// Create command definition
const options = new CommandOptions();
const cmdDef = new CommandDefinition(
'MYLINE',
'Draw simple line',
SimpleLineCommand,
options
);
// Register command
CommandRegistry.regist(cmdDef);Query Registered Commands
// Get command definition
const cmd = CommandRegistry.item('MYLINE');
if (cmd) {
console.log('Command name:', cmd.name);
console.log('Description:', cmd.description);
}
// Get all commands
const allCommands = CommandRegistry.items;Command Lifecycle
Lifecycle Phases
- Command Lookup: User enters the command name, the system finds the corresponding
CommandDefinitionfromCommandRegistry - Instance Creation: The system creates a new instance of the command class
- Execution Entry: The
main()method is called - User Interaction: The command interacts with the user through input functions
- State Modification: The command creates/modifies entities and records undo information
- Command End: The
main()method returns and the command is complete
Registering Commands in Plugins
In the plugin system, using PluginContext to register commands is more convenient:
import type { Plugin, PluginContext } from 'vjcad';
// Command class
class MyPluginCommand {
async main(): Promise<void> {
console.log('Plugin command executed');
// Command logic...
}
}
// Plugin definition
const plugin: Plugin = {
manifest: {
id: 'my-plugin',
name: 'My Plugin',
version: '1.0.0',
author: 'Developer',
description: 'Example plugin'
},
onLoad(context: PluginContext): void {
console.log('Plugin loaded');
},
onActivate(context: PluginContext): void {
// Register command (simplified API)
context.registerCommand(
'MYPLUGIN', // Command name
'My plugin command', // Description
MyPluginCommand // Command class
);
// Optional: Add to Ribbon menu
context.addRibbonGroup('plugins', {
id: 'my-plugin-group',
label: 'My Plugin',
primaryButtons: [
{
icon: 'myplugin',
cmd: 'MYPLUGIN',
prompt: 'Execute plugin command'
}
]
});
},
onDeactivate(context: PluginContext): void {
// Unregister command (optional, automatically cleaned up when plugin is deactivated)
context.unregisterCommand('MYPLUGIN');
},
onUnload(context: PluginContext): void {
console.log('Plugin unloaded');
}
};
export default plugin;Differences Between Plugin Commands and Direct Registration
| Feature | Direct Registration | Plugin Registration |
|---|---|---|
| API | CommandRegistry.regist() | context.registerCommand() |
| Lifecycle Management | Manual | Automatic (follows plugin activation/deactivation) |
| UI Integration | Requires additional code | Provides convenient API |
| Use Case | Core commands | Extension features |
Practical Plugin Example: Find and Replace
Below is a simplified structure of the find-replace-plugin:
import type { Plugin, PluginContext } from 'vjcad';
import { Engine } from 'vjcad';
// Panel instance management
let panelInstance: FindReplacePanel | null = null;
// Find and Replace command
class FindReplaceCommand {
async main(): Promise<void> {
Engine.writeMessage('<br/>Opening Find and Replace panel');
if (panelInstance) {
panelInstance.show();
return;
}
panelInstance = createFindReplacePanel();
panelInstance.show();
}
}
// Plugin definition
const plugin: Plugin = {
manifest: {
id: 'find-replace',
name: 'Find and Replace Text',
version: '1.0.0',
author: 'WebCAD Team',
description: 'Provides text find and replace functionality'
},
onActivate(context: PluginContext): void {
// Register icon
context.registerIcon('FINDREPLACE', ICON_SVG);
// Register command
context.registerCommand('FINDREPLACE', 'Find and Replace Panel', FindReplaceCommand);
// Add Ribbon button
context.addRibbonGroup('plugins', {
id: 'find-replace',
label: 'Find Replace',
primaryButtons: [
{ icon: 'findreplace', cmd: 'FINDREPLACE', prompt: 'Text find and replace', type: 'large' }
]
});
},
onDeactivate(context: PluginContext): void {
// Clean up panel
if (panelInstance) {
panelInstance.destroy();
panelInstance = null;
}
}
};
export default plugin;Command Execution Methods
Command Line Execution
Users enter the command name in the command line:
LINE
CIRCLE
MOVEScript Execution
Execute commands through code:
// Method 1: Using Editor
await Engine.editor.executerWithOp('LINE');
// Method 2: Direct instantiation
const cmd = new LineCommand();
await cmd.main();Execution with Parameters
Some commands support script parameters:
// Execute string command sequence
await Engine.editor.executerWithOp('EXECSTR', 'LINE 0,0 100,100 ');Next Steps
- Point Picking Guide - Learn how to get user-clicked coordinates
- Entity Selection Guide - Learn how to let users select entities
- Command Design Patterns - Learn design patterns for different types of commands