Skill v1.0.0
Trusted Publisher100/100version: "1.0.0" 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
// package.json → contributes.commands{"command": "cmake.myCommand","title": "%cmake-tools.command.cmake.myCommand.title%","category": "CMake"}
Rules
- Command ID format:
cmake.<commandName>(camelCase). - Title: NLS key in the format
%cmake-tools.command.cmake.<commandName>.title%. - Category:
"CMake"— this prefixes the title in the Command Palette asCMake: <title>. - `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:
// package.json → contributes.menus.commandPalette{"command": "cmake.myCommand","when": "cmake:enableFullFeatureSet"}
Sidebar tree-view inline button:
// 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
"cmake-tools.command.cmake.myCommand.title": "My Command Title"
For titles containing the product name, use the object form with a translator comment:
"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 underi18n/.
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.
// src/extension.tsconst funs: (keyof ExtensionManager)[] = [// ... existing entries ...'myCommand', // ← add here];
That's it — no manual registerCommand call needed. The loop that follows handles registration automatically:
for (const key of funs) {context.subscriptions.push(register(key));}
Only use manualvscode.commands.registerCommand()for commands that needcustom argument handling (e.g., tree-view context-menu commands that receivea node argument). Most commands go through thefunsarray.
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)
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
myCommandAll() {telemetry.logEvent('myCommand', { all: 'true' });return this.runCMakeCommandForAll(cmakeProject => cmakeProject.myCommand());}
Pattern C — Direct implementation (no CMakeProject delegation)
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 correctwhenclauses - [ ]
package.nls.json— English title string added - [ ]
src/extension.ts— method name added tofunsarray - [ ]
src/extension.ts— handler method implemented onExtensionManager - [ ] Handler uses
telemetry.logEvent()for telemetry - [ ] Handler delegates to
CMakeProjectviarunCMakeCommand(if project-scoped) - [ ]
CHANGELOG.md— entry added - [ ]
yarn compilesucceeds - [ ] No files under
i18n/were modified
See also: [`.github/copilot-instructions.md`](../copilot-instructions.md) for project-wide conventions.