How to bind one key to multiple commands in VSCode - visual-studio-code

I'm trying to make the key Ctrl+UpArrow execute both commands
cursorUp and
scrollLineUp.
I was hoping that this would work, but it doesn't:
{
"key": "ctrl+up",
"command": ["cursorUp", "scrollLineUp"], // This doesn't work
"when": "editorTextFocus"
}
How do I do that in VSCode?

This is currently not possible, but the corresponding feature request is tracked here. However you should take a look to the macros extension. It enables you to chain different commands to a single custom command. This custom command then can be bound to a hotkey.
In your case you could add this to your settings.json:
"macros": {
"myCustomCommand": [
"cursorUp",
"scrollLineUp"
]
}
And then add your custom hotkey to the keybindings.json:
{
"key": "ctrl+up",
"command": "macros.myCustomCommand"
}

There's a new way to achieve this without an extension:
Run "Tasks: Open User Tasks" command to create or open a user level tasks file.
Define commands as separate tasks, like so:
{
"version": "2.0.0",
"tasks": [
{
"label": "ctrlUp1",
"command": "${command:cursorUp}"
},
{
"label": "ctrlUp2",
"command": "${command:scrollLineUp}"
},
{
"label": "ctrlUpAll",
"dependsOrder": "sequence",
"dependsOn": [
"ctrlUp1",
"ctrlUp2"
],
"problemMatcher": []
}
]
}
In your keybindings.json:
{
"key": "ctrl+up",
"command": "workbench.action.tasks.runTask",
"args": "ctrlUpAll",
"when": "editorTextFocus"
}
("ctrlUpNNN" label format chosen for readability, task labels can be anything).

Related

How to pass arguments to a task in vscode that executes a snippet linked to a hotkey?

I have this working hotkey:
{
"key": "cmd+t",
"command": "editor.action.insertSnippet",
"args": {
"name": "TryCatch"
}
},
Which wraps the selected text into a tryCatch block, and adds the wanted logs and error reporting.
However, I want to link it with other sequence of either hotkeys or tasks.
I have this task in tasks.json, when when triggered in attempts to perform the above command, it prompts me for user input, because I can't figure out how to pass the name of the snippet as an argument, similar to what is done with hotKey binding configurations in example 1 above.
This is the task:
{
"label": "insertSnippet",
"command": "${command:editor.action.insertSnippet}",
"args": [
// "${name:TryCatch}",
],
},
I've been trying to get tasks to execute without having to wait for user input or pressing enter for example, but dreadfully failed. I couldn't find a wait to intercept the execution of a task and pass data or select an item from a menu.
Any help on setting up a single hotKey which then triggers two or more commands?
Please note that I need to commands/tasks in the editor, not in terminal or shell. All the solutions I came across are for shell. Also inputs or text work in shell or in the editor, but not in the dropdown as in the following images, which are triggered by tasks.
Thanks.
Edit, what worked in the end. Thanks a lot #Mark
{
"version": "2.0.0",
"tasks": [
{
"label": "insertTryCatchSnippet",
"command": [
"workbench.action.tasks.runTask",
"${input:tryCatchInput}"
]
},
{
"label": "save",
"command": "${command:workbench.action.files.save}",
},
{
"label": "TryCatch",
"dependsOrder": "sequence",
"dependsOn": [
"insertTryCatchSnippet",
"save",
],
},
],
"inputs": [
{
"id": "tryCatchInput",
"type": "command",
"command": "editor.action.insertSnippet",
"args": {
"name": "TryCatch"
}
}
]
}
And this hotkey shortcut:
{
"key": "cmd+t",
"command": "workbench.action.tasks.runTask",
"args": "TryCatch"
},
Flawlessly without using macros or extensions. Thanks again.
You can run vscode commands, like editor.action.insertSnippet. But if they take arguments than I believe you have to use the inputs of tasks.json to supply the args. In your tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "insertTryCatchSnippet",
"command": [
"${input:tryCatchInput}"
],
}
],
"inputs": [
{
"id": "tryCatchInput",
"type": "command",
"command": "editor.action.insertSnippet",
"args": {
"name": "tryCatch"
}
}
where your snippet name is defined in some snippets file.
You can then assign this task directly to a keybinding like this (in your keybindings.json):
{
"key": "alt+w",
"command": "workbench.action.tasks.runTask",
"args": "insertTryCatchSnippet",
"when": "editorFocus"
}
If your desired command didn't need any args than you could do something like this in a task:
{
"label": "SplitTerminal",
"command": "${command:workbench.action.terminal.split}",
"type": "shell",
"problemMatcher": []
}
You can use multiple vscode commands in a task too (although some commands may need to wait for the previous command to finish and you should make 2+ tasks that then run from a master task with the dependsOrder property sequence):
{
"label": "open new terminal and then saveAll",
// "type": "shell",
"command": [
"${command:workbench.action.terminal.new}",
"${command:workbench.action.files.saveAll}"
]
}

Keyboard shortcut that opens a terminal window in current directory and runs a command

I would like to create a keyboard shortcut that opens a terminal tab and then runs a command that includes the filename. I have tried using multi-command with Terminal Here in the following way:
"multiCommand.commands":[
{
"command": "multiCommand.formatLaTeX",
"interval": 750,
"sequence":[
"workbench.action.files.save",
"terminalHere.create",
{
"command": "workbench.action.terminal.sendSequence",
"args": {"text": "pdftex -ini -jobname=\"${fileBasenameNoExtension}\" \"&pdflatex\" mylatexformat.ltx ${fileBasename}\u000D"},
}
]
}
]
This saves the file, opens a terminal in a new window in the same directory, and then tries to run the command.
When I use "normal" characters that don't include filenames, i.e. no ${fileBasename}, it works perfectly.
How can I make it work when I use the file names? For example, if I'm working in foo.tex, I want it to run the command
pdftex -ini -jobname="foo" "&pdflatex" mylatexformat.ltx foo.tex
and then execute it.
Make this keybinding (in keybindings.json), if it works you can make it into a setting if you wish - obviously I can't test your exact shell command:
{
"key": "ctrl+shift+/",
"command": "extension.multiCommand.execute",
"args": {
"interval": 750,
"sequence": [
"workbench.action.files.save",
"workbench.action.terminal.new",
{
"command": "workbench.action.terminal.sendSequence",
"args": {"text": "cd '${fileDirname}' && echo Howdy \u000d"}
}
],
},
"when": "editorTextFocus"
},
Also, you should wrap your variables that might have spaces in them like this: '${fileDirname}', etc. Replace the echo... with your shell command and see if it works.
It may be necessary to split the two shell commands into two separate commands so the second command is run in the new directory:
{
"key": "ctrl+shift+/",
"command": "extension.multiCommand.execute",
"args": {
"interval": 750,
"sequence": [
"workbench.action.files.save",
"workbench.action.terminal.new",
{
"command": "workbench.action.terminal.sendSequence",
"args": {"text": "cd '${fileDirname}'\u000d"}
},
{
"command": "workbench.action.terminal.sendSequence",
"args": {
"text": "echo '${fileDirname}'\u000d" // this does work for me
}
},
],
},
"when": "editorTextFocus"
},

How do I disable inserting a new empty line when I press Enter when the cursor is in brackets?

Steps to reproduce:
simple code:
if () {}
cursor is between {}
i press Enter
result:
if () {
}
expected result:
if () {
}
I want a empty line not to be inserted.
It may be that it works by default(adds a empty line), and when Alt+Enter it doesn't add a empty line.
I did not find settings in vscode. I didn't find anything on google.
I tried this:
{
"key": "alt+enter",
"command": "type",
"args": {
"text": "\n"
},
"when": "editorTextFocus"
}
Because Alt+Enter does nothing by default.
However, the onEnterRules function used with the editor.autoIndent option detects the addition of the \n character and adds an extra empty line anyway. :(
I want to use editor.autoIndent. But I want to turn off (do not turn on) using the shortcut Alt+Enter.
Worst option: look for an extension that does exactly the same as editor.autoIndent, but has the ability to create a shortcut Alt+Enter to work the way I want.
You can use the extension multi-command and construct a command that does what you want.
Add this to your settings.json (global or workspace)
"multiCommand.commands": {
"multiCommand.lineBreakNoEmptyline": {
"sequence": [
"lineBreakInsert",
"deleteWordRight",
"cursorRight",
"cursorHome"
]
}
}
Add this to your keybindings.json:
{
"key": "alt+enter",
"command": "multiCommand.lineBreakNoEmptyline",
"when": "editorTextFocus"
}
Or using the keybinding only method
{
"key": "alt+enter",
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
"lineBreakInsert",
"deleteWordRight",
"cursorRight",
"cursorHome"
]
},
"when": "editorTextFocus"
}
I'll show the info from my comment here so that it is clearer. This keybinding:
{
"key": "alt+enter", // whatever keybinding you want
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
// "lineBreakInsert",
{
"command": "type",
"args": {
"text": "\n"
}
},
"editor.action.clipboardCutAction"
]
},
}
The type command acts differently than a lineBreakInsert command so it is a little easier to then delete that extra line as the cursor is already there. It is just a small improvement, 2 less commands.
Demo:

Visual Studio Code keybindings - Running two or more commands with one shortcut

I have the following keybinding in VS Code which toggles the position of the cursor between the active document and built-in terminal:
// Toggle between terminal and editor focus
{
"key": "oem_8",
"command": "workbench.action.terminal.focus"
},
{
"key": "oem_8",
"command": "workbench.action.focusActiveEditorGroup",
"when": "terminalFocus"
}
Before i click the shortcut key to move the cursor to the terminal, i first have to save the active file.
I would therefore like to run the file saving command, which after searching on google i believe is workbench.action.files.save
How would i do this? I have tried adding the above code snippet at the end of the "command" line but it has not worked.
You would need a macro extension to run multiple commands from one keybinding.
I now use multi-command and there are other macro extensions now.
You can use this keybinding (in your keybindings.json) with the multi-command extension - no need for anything in settings.json:
{
"key": "oem_8", // or whatever keybinding you wish
"command": "extension.multiCommand.execute",
"args": {
"sequence": [
"workbench.action.files.save",
"workbench.action.terminal.focus"
]
},
"when": "editorTextFocus" // if you want this, you probably do
}
If you have more complicated macros you can still build them in your settings.json if you wish.
There is a way to run a sequence of commands without any extensions. It is by using Tasks. I like this method, because it allows to define a command, that is in workspace scope, not in global scope. The idea was taken from this blog post.
Example of tasks.json:
{
"version": "2.0.0",
"tasks": [
{
"label": "cmd-1",
"command": "${command:workbench.action.files.save}"
},
{
"label": "cmd-2",
"command": "${command:workbench.action.terminal.focus}"
},
{
"label": "cmd-All",
"dependsOrder": "sequence",
"dependsOn": [
"cmd-1",
"cmd-2"
],
}
]
}
Then in keybindings.json you just bind your hotkey to the task:
{
"key": "oem_8",
"command": "workbench.action.tasks.runTask",
"args": "cmd-All"
}
Note, that when defining a task, you can pass arguments to the command with the help of input variables.
Another extension to run multiple commands: Commands
{
"key": "oem_8",
"command": "commands.run",
"args": [
"workbench.action.files.save",
"workbench.action.terminal.focus"
],
"when": "editorTextFocus"
}
I made this extension. It's great.

VSCode extension API for keybindings

Trying to dynamically create keybindings from within an extension.
I can't seem to find any API that supports this.
Anyone knows?
This link should show you how to do it. https://code.visualstudio.com/api/references/contribution-points#contributes.keybindings
Steps:
register a new command (in extenson.ts)
let disposable = vscode.commands.registerCommand('extension.helloWorld', () => {
console.log("command ran");
});
context.subscriptions.push(disposable);`
Then add it to the activation events (in package.json)
"activationEvents": [
"onCommand:extension.helloWorld",
"onCommand:extension.newComment"
],
Then declare your new command (in package.json)
"contributes": {
"commands": [{
"command": "extension.helloWorld",
"title": "Hello World"
}],
"keybindings": [{
"command": "extension.helloWorld",
"key": "ctrl+k ctrl+k",
"mac": "cmd+k cmd+k",
"when": "editorTextFocus"
}]
},
Now whenever someone double presses k while holding cmd, the helloWorld command will run and "command ran" will be print to the console.
You can use Vscode namespace API for your extension. There is a keybindings section in your package.json. So you can define key map inside that.
For example you should use like this:
{ "key": "tab", "command": "tab", "when": ... },
{ "key": "tab", "command": "editor.emmet.action.expandAbbreviation", "when": ... },
{ "key": "tab", "command": "jumpToNextSnippetPlaceholder", "when": ... },
{ "key": "tab", "command": "acceptSelectedSuggestion", "when": ... },
{ "key": "ctrl+shift+k", "command": "editor.action.deleteLines", "when": "editorTextFocus" },
Extra helpful link: Windows virtual key list:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731
For detailed information about API and practices, please check following link:
https://code.visualstudio.com/docs/getstarted/keybindings#_customizing-shortcuts
You can do that by contributing all of your keybindings and using a custom where clause. See https://code.visualstudio.com/api/references/when-clause-contexts#add-a-custom-when-clause-context