VS Code keyboard-fu: custom keyboard shortcuts that will boost your productivity

19 min read
VS Code keyboard-fu: custom keyboard shortcuts that will boost your productivity cover image

Keyboard Shortcuts (keybindings) can help you achieve tasks faster, and with less effort. Visual Studio Code (VS Code) comes with default keybindings for many of its built-in commands. You just need to learn some of these and put them to use (see keybindings references for Linux (US), Windows (US), macOS (US)). Great, right?

Well, most extensions do not have default keybindings! Since some of your most commonly used functionality probably lives in some extension or another, you would need to add your own keybindings to reap the rewards there! And there may be builtin commands that you want a shortcut for, but it has none; or maybe there is one that is not to your liking! You will need to get your hands dirty at some stage!

And what shortcuts should you use?

This is not intended to be a guide on keybindings in VS Code, there is a good guide for that already, however I will cover a few key points (pardon the pun) on adding and modifying keybindings that will ensure we are on the page.

Then, I will dive into some keybindings that I use everyday. Here is my current keybindings.json, which I reference throughout. You can copy it exactly if you wish, but keep in mind that some of the keybindings apply to extensions that I have installed. I think keybindings are something that are particular to individuals. So, you probably do not want to copy it all verbatim. However, it may spark some ideas of how to adapt your own configuration.

How do I use shortcuts?

Any task you do regularly with the mouse, or through the execution of a command in the Command Palette, is a good candidate for for a keyboard shortcut. The sweet spot for me is:

  • to use keyboard shortcuts for my most commonly performed tasks,
  • to modify existing keybindings to fall into line with other programs I use,
  • and occasionally to modify keybindings to use combinations that are shorter and more memorable for me.

I add shortcuts to my repertoire over time when I see an opportunity, or encounter some friciton when doing something. As you are changing your habits, it is probably best to do this slowly rather than as a big bang initiative! Think crash dieting here! For this reason, I think its best to think of shortcuts as an input into creating healthier habits. I had some wrist pain and it has certainly contributed to the alleviation of that over time.

Also, a really nice thing to do is to use a keybinding consistently within VS Code for similar tasks. For example, I like to use Ctrl + Tab for switching between tabs in a group, in the section Keybindings for Panels you can see that I added a keybinding for switching between panels to match up with switching between Editors.

How to add and modify keybindings

To view and edit keybindings, you can open the Keyboard Shortcuts editor through the command “Preferences: Open Keyboard Shortcuts”. It lists all available commands with and without keybindings. You can modify, remove, and reset the keybindings for commands by right-clicking on a keybinding and using the available actions from the context menu.

screenshot of keyboard shortcut editor

I don’t know why exactly, but I was confused by this initially. 😵‍💫 I was looking at the UI thinking “how do I add a new keybinding”! I expected an add button somewhere, and there is not one! The missing mental link here is that this list shows all commands already, so you are adding a keybinding to one of these commands. That wasn’t intuitive to me.

So, to add a new keybinding: you search for the command you are interested in, right-click on the list item in the filtered list, and select “Add Keybinding…“ option from the menu. Then, you can type in the key combination you want to assign.

If you want to change or remove a keybinding, select the options from the same context menu.

If you want to manually add a keybinding, you can run the “Preferences: Open Keyboard Shortcuts (JSON)” command to open the JSON file that stores your keybindings. It is an array of objects that stores the keybindings in the following format:

  {
      "key": "ctrl+shift+v",
      "command": "markdown.showPreviewToSide",
      "when": "editorTextFocus && editorLangId == markdown"
  }

The properties correspond to the same fields as in the Keyboard Shortcut editor.

If you want to disable a keybinding, you place a hypen at the start of the name of the command. So in cases where you want to change a keybinding for a command, actually you are disabling the current keybinding, and adding a new one. For example, here I am replacing the default behaviour for Ctrl + N:

  {
    "key": "ctrl+n",
    "command": "-workbench.action.files.newUntitledFile"
  },
  {
    "key": "ctrl+n",
    "command": "filebunny.createFile"
  }

If you want to assign a keybinding to a command that takes an argument, you must do it manually because you need to populate an args object that is not exposed in the Keyboard Shortcuts editor (there is an issue for this on the VS Code repo on GitHub). It is not that common to do this (I guess), but an example of this is if you want to assign a keybinding to a snippet. Here I am assigning a keybinding to the “Insert table” markdown snippet:

  {
    "key": "ctrl+t",
    "command": "editor.action.insertSnippet",
    "when": "editorTextFocus && editorLangId == markdown",
    "args": {
      "langId": "markdown",
      "name": "Insert table"
    }
  }

What is the when clause?

The when clause is used to evaluate if the keybinding is active in the current context. The expression is evaluated as a boolean expression - it can contain conditional operators and you have a selection of built-in context variables.

The when clause is optional. If you omit it, the keybinding is global. For example, when you open the Command Palette through the "Show All Commands" command, this works everywhere with Ctrl + Shift + P and has no when clause.

However, there are many occasions where you only want a keybinding to be active in a specific context. For example, for commands related to a manipulating the cursor, these commands can only be executed as intended when an editor has focus. The editorTextFocus context variable is used to specify this.

cursor commands in keyboard shorcut editor to demonstrate the when clause

You should try to have a when clause when you make your own keybindings. You want to ensure that if you assign the same keybinding to more than one command, that they will apply to separate contexts. Otherwise, you may get some funky behaviour.

How to avoid and fix conflicts

If the same keyboard shortcut is mapped to several commands, it can led to confusing behavior. So when you add a new keybinding, it is a good idea to identify any potential conflicts.

In the Keyboard Shortcuts editor you can search for a keybinding by putting the keybinding in quotes.

searching for control and f2 keybinding in the shotcut keyboard editor

If a particular keybinding is used already, look to add an unique when clause, or choose a different keybinding.

There is a “Developer: Toggle Keyboard Shortcuts Troubleshooting” command to troubleshoot conflicts if you can’t pinpoint the issue. This will activate logging of dispatched keyboard shortcuts and will open an Output panel view with the corresponding log file.

Keybindings for panels

The panel is the section anchored to the bottom of the UI that contains the panel views: Output, Debug Console, Terminal, and Problems (by default). I want a shortcut to navigate to the next panel view. In the screenshot below, I want to navigate from the Terminal to Problems.

screenshot of the panel UI component

I use the same keybinding for navigating to the next editor:

   {
		"key": "ctrl+tab",
		"command": "workbench.action.nextPanelView",
		"when": "panelFocus"
    }

This keybinding will navigate to the next panel and will cycle back to the beginning when you are on the last panel view.

Keybindings for Markdown

If you have keyboard shortcuts that cover the span of the Markdown syntax, then you can have a document editing experience that is similar to a dedicated writing application. I think this is desirable for everyone. Surely at some stage, you will need to edit a markdown file!

Most people install an extension to give them toggle style editing in markdown. The most popular extension is Markdown All in One. This extension only provides shortcuts for a few commands, namely “Markdown All In One: Toggle Bold” and “Markdown All In One: Toggle Italic”. So, you have to add the rest yourself.

I do not use Markdown All in One because it is bloated for my needs. This led me to write my own extension for editing markdown called Marky Edit. It loads in 3ms, whereas Markdown All in One loads in 120ms. A considerable difference I would say! So, the following shortcuts are for Marky Edit, but you can subsitute the command names if you use another extension.

I also use Typora for writing in markdown, I based some of these shortcuts on what Typora uses. Otherwise, I tried to pick something that I found memorable. It can be arbitrary picking a combination of keys sometimes!

Toggle inline elements (image, link..etc)

Marky Edit provides default shortcuts for:

  • "Marky Edit: Toggle Strong Emphasis (Bold)": Ctrl + B;
  • "Marky Edit: Toggle Emphasis (Italic)" : Ctrl + I

You must add your own for:

  • "Marky Edit: Toggle Link "
  • "Marky Edit: Toggle Image "
  • "Marky Edit: Toggle Inline Code "
  • "Marky Edit: Toggle Delete (Strikethrough) "
  {
    "key": "ctrl+k",
    "command": "marky-edit.toggleLink",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+shift+i",
    "command": "marky-edit.toggleImage",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+shift+c",
    "command": "marky-edit.toggleInlineCode",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+shift+s",
    "command": "marky-edit.toggleDelete",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  }

Toggle block elements

Animation of running the toggle orderded list command from the marky edit extension

The following elements:

  • “Marky Edit: Toggle Ordered List (Numbered List)”
  • “Marky Edit: Toggle Unordered List (Bulleted List)”
  • “Marky Edit: Toggle Quote”
  • “Marky Edit: Toggle Code Block”
  • “Marky Edit: Toggle Thematic Break (Horizontal Rule)”
 {
    "key": "ctrl+shift+]",
    "command": "marky-edit.toggleUnorderedList",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+shift+[",
    "command": "marky-edit.toggleOrderedList",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+shift+q",
    "command": "marky-edit.toggleQuote",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+shift+k",
    "command": "marky-edit.toggleCodeBlock",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+shift+h",
    "command": "marky-edit.toggleHorizontalRule",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  }

Toggle headings

I must admit that I don’t use these, but I should try to get into the habit!

animation of toggle heading 1 command from marky edit extension

  {
    "key": "ctrl+1",
    "command": "marky-edit.toggleHeading1",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+2",
    "command": "marky-edit.toggleHeading2",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+3",
    "command": "marky-edit.toggleHeading3",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+4",
    "command": "marky-edit.toggleHeading4",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+5",
    "command": "marky-edit.toggleHeading5",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  },
  {
    "key": "ctrl+6",
    "command": "marky-edit.toggleHeading6",
    "when": "editorTextFocus && editorLangId == 'markdown'"
  }

Extended syntax

These shortcuts use snippets from the extension Markdown Snippets to:

  • "insert a table" insert table snippet being executed
  • "insert a task list".
  {
    "key": "ctrl+t",
    "command": "editor.action.insertSnippet",
    "when": "editorTextFocus && editorLangId == markdown",
    "args": {
      "langId": "markdown",
      "name": "Insert table"
    }
  },
  {
    "key": "ctrl+shift+x",
    "command": "editor.action.insertSnippet",
    "when": "editorTextFocus && editorLangId == markdown",
    "args": {
      "langId": "markdown",
      "name": "Insert task list"
    }
  }

There is an existing keybinding for Ctrl + T for the command “Go to Symbol in Workspace…“, if you want to use this in markdown files, then you may want to choose another keybinding!

Avoid a clash with the “View: Toggle Side Bar Visibility” command

The default keybinding for the command “View: Toggle Side Bar Visibility” is Ctrl + B, this overlaps with the keybinding for “Marky Edit: Toggle Strong Emphasis (Bold)”, which means that you have no keybinding to toggle the side bar when a markdown file is open. I decided to switch this to Ctrl + D instead.

  {
		"key": "ctrl+b",
		"command": "-workbench.action.toggleSidebarVisibility"
	},
	{
		"key": "ctrl+d",
		"command": "workbench.action.toggleSidebarVisibility"
	},
	{
		"key": "ctrl+d",
		"command": "-editor.action.addSelectionToNextFindMatch",
		"when": "editorFocus"
	}

Keybindings for file management

I wrote an extension called File Bunny to provide more commands for file actions, so you can largely skip file dialogs and the file explorer sidebar. I discuss this in another article titled, Easy file management in VS Code. There are a couple of other extensions that I mention in the article that perform similar actions also. This was a game-changer for me.

For example, now when I want to open a folder, I use the command “File Bunny: Open a Folder” instead via Ctrl + O. This command enables finding a folder by building paths using incremental completion in the command palette as below.

animation of execution of File Bunny: Open a Folder command to open a particular folder

I replace the default behavior for file management with the commands from File Bunny for:

  • Opening a folder
  • Opening a file
  • Creating a new file
  {
    "key": "ctrl+o",
    "command": "-workbench.action.files.openFile"
  },
  {
    "key": "ctrl+o",
    "command": "filebunny.openFolder"
  },
 {
    "key": "ctrl+p",
    "command": "-workbench.action.quickOpen"
  },
  {
    "key": "ctrl+p",
    "command": "filebunny.openFile"
  },
  {
    "key": "ctrl+n",
    "command": "-workbench.action.files.newUntitledFile"
  },
  {
    "key": "ctrl+n",
    "command": "filebunny.createFile"
  }

Keybindings for the terminal

Simplify opening a new terminal pane

Use Ctrl + ` instead of Ctrl + Shift + `.

  {
    "key": "ctrl+`",
    "command": "workbench.action.terminal.new"
  },
  {
    "key": "ctrl+shift+oem_3",
    "command": "-workbench.action.terminal.new"
  }

Close any terminal instance

This is a bit tricky since you can now open a terminal as an editor view also. I had to change the when clause for the binding for the command workbench.action.terminal.killEditor to enable Ctrl + W to close an terminal as a panel view, or a terminal as an editor view.

{
    "key": "ctrl+w",
    "command": "workbench.action.terminal.kill",
    "when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
  },
  {
    "key": "ctrl+w",
    "command": "workbench.action.terminal.killEditor",
    "when": "terminalEditorFocus && terminalHasBeenCreated && resourceScheme == 'vscode-terminal' || terminalEditorFocus && terminalProcessSupported && resourceScheme == 'vscode-terminal'"
  },
  {
    "key": "ctrl+w",
    "command": "-workbench.action.terminal.killEditor",
    "when": "terminalEditorFocus && terminalFocus && terminalHasBeenCreated && resourceScheme == 'vscode-terminal' || terminalEditorFocus && terminalFocus && terminalProcessSupported && resourceScheme == 'vscode-terminal'"
  }

Simplify paste

Use Ctrl + V instead of Ctrl + Shift + V:

  {
    "key": "ctrl+shift+v",
    "command": "-workbench.action.terminal.paste",
    "when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
  },
  {
    "key": "ctrl+v",
    "command": "workbench.action.terminal.paste",
    "when": "terminalFocus && terminalHasBeenCreated || terminalFocus && terminalProcessSupported"
  },

Simplify scrolling

I prefer to use the same keys that I use in the editor view:

  • Use PageUp to scroll up instead of Ctrl + Shift + Pageup
  • Use PageDown to scroll down instead of Ctrl + Shift + Pagedown.
  {
    "key": "ctrl+alt+pageup",
    "command": "-workbench.action.terminal.scrollUp",
    "when": "terminalFocus"
  },
  {
    "key": "pageup",
    "command": "workbench.action.terminal.scrollUp",
    "when": "terminalFocus"
  },
  {
    "key": "ctrl+alt+pagedown",
    "command": "-workbench.action.terminal.scrollDown",
    "when": "terminalFocus"
  },
  {
    "key": "pagedown",
    "command": "workbench.action.terminal.scrollDown",
    "when": "terminalFocus"
  },

Final word

It is worthwhile to learn some keyboard shortcuts and put them into use. I recommend targeting things that you do frequently in the beginning to see how it goes. Adding and editing keyboard shortcuts is quite straightforward, it is a quick task, so it is a cheap investment of your time.

When you consider that extensions do not have shortcuts assigned by default, and that there is so much functionality in VS Code provided by extensions, it is worthwhile to learn the basics about keybindings and add some of your own. I view keyboard shortcuts as micro investments that pay off over time. It is just down to your own habits how you tackle that.