Run several VS Code commands from one keyboard shortcut (and what to do when that isn’t enough)
A feature request from December 2015 asks for this: bind a key to several commands, run in order. In the request’s example, Ctrl+S would format the file, trim trailing whitespace, then save. It has 699 👍 and is still open. The short version: part of it shipped in 2023, and it's worth knowing how it works before reaching for an extension.
The built-in way: runCommands
A VS Code team engineer wrote in that thread that VS Code added a built-in runCommands command that runs multiple commands sequentially. They were clear that it isn't full macro support, and that the request stays open. The keybindings documentation shows the syntax. Open Preferences: Open Keyboard Shortcuts (JSON) and add:
{
"key": "ctrl+alt+c",
"command": "runCommands",
"args": {
"commands": [
"editor.action.copyLinesDownAction",
"cursorUp",
"editor.action.addCommentLine",
"cursorDown"
]
}
}That’s the docs’ own example: copy the line down, comment the original, move to the copy. To pass arguments to a command, use an object with command and args instead of a string:
{ "command": "workbench.action.files.newUntitledFile", "args": { "languageId": "typescript" } }For the request’s own example, it would look like this. I haven’t checked whether each command ID below behaves well when chained, so test it first:
{
"key": "ctrl+shift+s",
"command": "runCommands",
"args": {
"commands": [
"editor.action.formatDocument",
"editor.action.trimTrailingWhitespace",
"workbench.action.files.save"
]
},
"when": "editorTextFocus"
}Limits people report in the thread
These come from comments on that issue, not from my testing:
- Undo takes more than one step. One commenter chained
joinLinesanddeleteRightand found they had to undo twice. - An error can stop the rest. Another commenter said a chain containing a
workbench.action.open…Settingscommand threw an error and prevented the later commands from running.
And by design, runCommands only runs VS Code commands, and you write each one's ID by hand.
When you want more than VS Code commands
What I kept wanting was a sequence that mixes VS Code commands with other things: run the tests in a terminal, stop if they fail, then commit. I built that into Slashi, a free VS Code extension. A command is a list of steps, and you can share it with your team by committing .vscode/slashi.json:
{
"commands": [
{
"name": "ship",
"args": "commit message",
"steps": [
{ "command": "workbench.action.files.saveAll" },
{ "terminal": "npm test" },
{ "terminal": "git add -A && git commit -m ${q:args} && git push" }
]
}
]
}Then bind it like any other command:
{ "key": "cmd+alt+s", "command": "slashi.run", "args": "/ship" }Press the key and Slashi asks for the commit message, since the command uses ${args}. Step types include a VS Code command, a terminal command, a setting change, an input or pick prompt, an AI step and a notification.
Get Alex’s stories in your inbox
Join Medium for free to get updates from this writer.
Two behaviors matter here:
- A failing terminal step stops the run. If
npm testexits with a non-zero code, the commit never happens. (The last step doesn't wait, since nothing comes after it.) - Shared commands ask first. A command that comes from a team file shows its steps and asks before it runs anything that can reach a shell, and
${args}is shell-quoted by${q:args}.
What this doesn’t do
- It doesn’t record. The request that asks for macro recording (#4490, 1,228 👍) is a different thing. In Slashi you write the steps by hand or with the
/new-commandwizard. - It’s an extension. If
runCommandscovers what you need, you don't need it.
Takeaway
If you only need to chain editor commands, runCommands in keybindings.json is built in and enough. When the sequence needs a terminal command that can stop it, or something you share through the repo, that's what Slashi's steps are for.
I’m the author of Slashi. It’s free and MIT-licensed: Marketplace · Open VSX · GitHub.





