--- name: add-command description: > Use when adding a new cmake.* command to CMake Tools. Touches package.json (contributes.commands), package.nls.json, src/extension.ts (funs array), and CHANGELOG.md. Triggers: "add command", "register command", "new command palette entry". --- # Adding a New Command Recipe for adding a new `cmake.*` command to CMake Tools. ## Files you must touch | File | What to add | |------|-------------| | `package.json` | Command declaration in `contributes.commands` + optional menu entries | | `package.nls.json` | English title string | | `src/extension.ts` | Method name in `funs` array + handler method on `ExtensionManager` | | `CHANGELOG.md` | Entry under the current version | --- ## Step 1 — Declare the command in `package.json` ### 1a — `contributes.commands` ```jsonc // package.json → contributes.commands { "command": "cmake.myCommand", "title": "%cmake-tools.command.cmake.myCommand.title%", "category": "CMake" } ``` ### Rules - **Command ID format:** `cmake.` (camelCase). - **Title:** NLS key in the format `%cmake-tools.command.cmake..title%`. - **Category:** `"CMake"` — this prefixes the title in the Command Palette as `CMake: `. - **`when`** (optional): controls when the command appears in the Command Palette. - **`icon`** (optional): Codicon reference like `"$(settings-gear)"` for tree-view inline buttons. ### 1b — `contributes.menus` (if needed) Add visibility rules for where the command appears. **Command Palette visibility:** ```jsonc // package.json → contributes.menus.commandPalette { "command": "cmake.myCommand", "when": "cmake:enableFullFeatureSet" } ``` **Sidebar tree-view inline button:** ```jsonc // package.json → contributes.menus["view/item/context"] { "command": "cmake.projectStatus.myCommand", "when": "view == cmake.projectStatus && cmake:enableFullFeatureSet && viewItem == 'myItem'", "group": "inline" } ``` Common `when` clause patterns: | Pattern | Meaning | |---------|---------| | `cmake:enableFullFeatureSet` | Extension is fully activated | | `useCMakePresets` | Presets mode is active | | `!useCMakePresets` | Kits/variants mode is active | | `view == cmake.projectStatus && viewItem == 'kit'` | Specific tree-view item | | `viewItem =~ /configPreset/` | Regex match on tree-view item | --- ## Step 2 — Add the English string to `package.nls.json` ```json "cmake-tools.command.cmake.myCommand.title": "My Command Title" ``` For titles containing the product name, use the object form with a translator comment: ```json "cmake-tools.command.cmake.myCommand.title": { "message": "Do Something with CMake Tools", "comment": ["The text 'CMake Tools' should not be localized."] } ``` > **Do not** modify any file under `i18n/`. --- ## Step 3 — Register the command in `src/extension.ts` Add the method name to the `funs` array (search for `const funs:` near the end of the file). The `register()` helper auto-generates the command ID `cmake.<name>`, wraps it with debug logging, and hands the promise to `rollbar.takePromise()` for error tracking. ```typescript // src/extension.ts const funs: (keyof ExtensionManager)[] = [ // ... existing entries ... 'myCommand', // ← add here ]; ``` That's it — no manual `registerCommand` call needed. The loop that follows handles registration automatically: ```typescript for (const key of funs) { context.subscriptions.push(register(key)); } ``` > Only use manual `vscode.commands.registerCommand()` for commands that need > custom argument handling (e.g., tree-view context-menu commands that receive > a node argument). Most commands go through the `funs` array. --- ## Step 4 — Implement the handler on `ExtensionManager` Add a method to the `ExtensionManager` class in `src/extension.ts`. The method name must match the string added to the `funs` array. ### Pattern A — Delegate to CMakeProject (most common) ```typescript myCommand(folder?: vscode.WorkspaceFolder) { telemetry.logEvent('myCommand'); return this.runCMakeCommand( cmakeProject => cmakeProject.myCommand(), folder, undefined, // precheck (optional) true // cleanOutputChannel ); } ``` Then implement the actual logic on `CMakeProject` in `src/cmakeProject.ts`. ### Pattern B — Run for all projects ```typescript myCommandAll() { telemetry.logEvent('myCommand', { all: 'true' }); return this.runCMakeCommandForAll( cmakeProject => cmakeProject.myCommand() ); } ``` ### Pattern C — Direct implementation (no CMakeProject delegation) ```typescript async myCommand() { telemetry.logEvent('myCommand'); const result = await vscode.window.showQuickPick(items); if (!result) { return; } // ... handle result ... } ``` ### Key helpers | Helper | Use when | |--------|----------| | `this.runCMakeCommand(cmd, folder)` | Single-project command | | `this.runCMakeCommandForAll(cmd)` | Runs on every open CMake project | | `this.runCMakeCommandForProject(cmd, project)` | Specific project instance | --- ## Step 5 — Add a CHANGELOG entry Add an entry under the current version in `CHANGELOG.md`, in the `Features:` section. --- ## Verification checklist - [ ] `package.json` — command declared with NLS title and `"CMake"` category - [ ] `package.json` — menu entries added (if applicable) with correct `when` clauses - [ ] `package.nls.json` — English title string added - [ ] `src/extension.ts` — method name added to `funs` array - [ ] `src/extension.ts` — handler method implemented on `ExtensionManager` - [ ] Handler uses `telemetry.logEvent()` for telemetry - [ ] Handler delegates to `CMakeProject` via `runCMakeCommand` (if project-scoped) - [ ] `CHANGELOG.md` — entry added - [ ] `yarn compile` succeeds - [ ] No files under `i18n/` were modified --- *See also: [`.github/copilot-instructions.md`](../copilot-instructions.md) for project-wide conventions.*