28 February 2021

Use Emacs key bindings in VS Code

Emacs key bindings in VSCode

I’ve been working in Visual Studio Code a lot these days. I used to write code entirely in Emacs, except when working with Java and the need for a heavier IDE would present itself. However, once I started writing a lot of TypeScript all the checking, completion, refactoring, etc. were too alluring to ignore.

I really like how a lot of the Emacs key bindings just work on Mac OSX. It makes editing text in any old random text box (such as TextEdit or a web browser) that much quicker, e.g.,

  • ctrl + e - move to end of line
  • ctrl + a - move to beginning of line
  • ctrl + p - move to previous line
  • ctrl + n - move to next line
  • ctrl + k - kill the rest of the current line
  • ctrl + y - paste what was last “killed”

This is a great head start to using those key bindings in another IDE, but it’s not enough. Naturally, there are extensions to solve this problem.

I looked for something that would be simple and would give me all the core commands I wanted while not getting in the way of the other useful things VSCode has to offer. I landed on Awesome Emacs Keymap (emacs-mcx).

After installing it, almost everything seemed right, but—like any Emacs user who is used to customizing things—I was running into a couple design decisions by the extension that I wanted to change. My main issue was with the find widget closing when I didn’t it want to. I achieved these changes with the following steps:

  1. In VS Code go to Code > Preferences > Keyboard Shortcuts [⌘K ⌘S]

  2. Switch to JSON view (flip doc icon)

  3. Take a look at the keybindings.json file from the emacs-mcx repo to see the rules it applies. As seen below, any commands that include “meta” in this file should be “alt” in your keyboard shortcuts JSON file.

  4. Enter your overrides! In my examples below, I’m removing key binding rules from the extension by putting a “-” in front of the command name.

Here are the overrides that I have applied in my environment:

// Place your key bindings in this file to override the defaults
[
  // allow arrow keys to work in the find widget
  {
    "key": "right",
    "command": "-emacs-mcx.isearchExit"
  },
  {
    "key": "left",
    "command": "-emacs-mcx.isearchExit"
  },
  {
    "key": "up",
    "command": "-emacs-mcx.isearchExit"
  },
  {
    "key": "down",
    "command": "-emacs-mcx.isearchExit"
  },
  // allow ctrl+f to find next in the find widget
  {
    "key": "ctrl+f",
    "command": "-emacs-mcx.isearchExit",
    "when": "editorFocus && findWidgetVisible"
  },
  // allow other stuff to functional normally in the find widget
  {
    "key": "ctrl+b",
    "command": "-emacs-mcx.isearchExit",
    "when": "editorFocus && findWidgetVisible"
  },
  {
    "key": "ctrl+p",
    "command": "-emacs-mcx.isearchExit",
    "when": "editorFocus && findWidgetVisible"
  },
  {
    "key": "ctrl+n",
    "command": "-emacs-mcx.isearchExit",
    "when": "editorFocus && findWidgetVisible"
  },
  {
    "key": "ctrl+a",
    "command": "-emacs-mcx.isearchExit",
    "when": "editorFocus && findWidgetVisible"
  },
  {
    "key": "ctrl+e",
    "command": "-emacs-mcx.isearchExit",
    "when": "editorFocus && findWidgetVisible"
  },
  {
    "key": "enter",
    "command": "-emacs-mcx.isearchExit"
  },
  // allow curly quotes and ellipses characters on mac
  {
    "key": "alt+shift+[",
    "command": "-emacs-mcx.backwardParagraph"
  },
  {
    "key": "alt+shift+]",
    "command": "-emacs-mcx.forwardParagraph"
  },
  {
    "key": "alt+;",
    "command": "-editor.action.blockComment",
    "when": "editorTextFocus && !config.emacs-mcx.useMetaPrefixMacCmd && !editorReadonly"
  },
  {
    "key": "alt+;",
    "command": "-emacs-mcx.executeCommands",
    "when": "editorFocus && findWidgetVisible && !config.emacs-mcx.useMetaPrefixMacCmd"
  },
  // stop backward kill word from adding to clipboard
  {
    "key": "alt+backspace",
    "command": "-emacs-mcx.backwardKillWord",
    "when": "editorTextFocus && !config.emacs-mcx.useMetaPrefixMacCmd && !editorReadonly"
  }
]

The only snag I’ve encountered is that the extension has updated their commands a couple times since I first set this up, but when that happens I just check back to the keybindings.json file in their repo and updated my command names accordingly (last updated in this post on July 20, 2021).




Did you find this helpful or fun? paypal.me/mrcoles
comments powered by Disqus

Peter Coles

Peter Coles

is a software engineer living in NYC who is building Superset 💪 and also created GoFullPage 📸
more »

github · soundcloud · rss