When I write, I want proper curly quotes, with the correct opening and closing ‘single’ and “double” quote marks. However, the standard QWERTY keyboard doesn’t have these keys, having only straight 'single' and "double" quotes. Microsoft Office and Apple Pages “Smart Quotes” will automatically fix this, but since I write this blog in Visual Studio Code, here is how I setup my keyboard.

macOS has a plethora of keyboard shortcuts, but alas, these are missing on Windows 10:

Keystroke Output
Option ⌥+[
Shift+Option ⌥+[
Option ⌥+]
Shift+Option ⌥+]

Fortunately, this is easy to setup in Visual Studio Code, simply by editing the key bindings configuration file:

  • On Windows, File > Preferences > Keyboard Shortcuts
  • On macOS, Code > Preferences > Keyboard Shortcuts
  • Next to the Keyboard Shortcuts tab, hit this button to “Open Keyboard Shortcuts (JSON)”.
  • Edit and save keybindings.json file, then restart Visual Studio Code.

For VS Code in Windows to behave exactly the same way as macOS:

Keystroke Output
Alt+[
Shift+Alt+[
Alt+]
Shift+Alt+]
[{
    "key": "alt+[",
    "command": "type",
    "args": {"text": "“"},
    "when": "editorTextFocus"
},{
    "key": "alt+]",
    "command": "type",
    "args": {"text": "‘"},
    "when": "editorTextFocus"
},{
    "key": "shift+alt+[",
    "command": "type",
    "args": {"text": "”"},
    "when": "editorTextFocus"
},{
    "key": "shift+alt+]",
    "command": "type",
    "args": {"text": "’"},
    "when": "editorTextFocus"
}]

But I want something even better:

  • If there is text selected the keystroke should enclose the text in the desired single or double curly quote.
  • In addition, since the single closing quote is often used (e.g. don’t, won’t), I also want to map it to another key, so that:
Keystroke Output
Alt+'

Luckily, VS Code is very flexible, the trick is to use the insertSnippet command instead of type. I got the idea from issue #26820 on the VS Code GitHub:

[{
    "key": "alt+[",
    "command": "editor.action.insertSnippet",
    "args": {"snippet": "“$TM_SELECTED_TEXT$0”"},
    "when": "editorTextFocus&&editorHasSelection"
},{
    "key": "alt+[",
    "command": "type",
    "args": {"text": "“"},
    "when": "editorTextFocus&&!editorHasSelection"
},{
    "key": "alt+]",
    "command": "editor.action.insertSnippet",
    "args": {"snippet": "‘$TM_SELECTED_TEXT$0’"},
    "when": "editorTextFocus&&editorHasSelection"
},{
    "key": "alt+]",
    "command": "type",
    "args": {"text": "‘"},
    "when": "editorTextFocus&&!editorHasSelection"
},{
    "key": "shift+alt+[",
    "command": "type",
    "args": {"text": "”"},
    "when": "editorTextFocus"
},{
    "key": "shift+alt+]",
    "command": "type",
    "args": {"text": "’"},
    "when": "editorTextFocus"
},{
    "key": "alt+'",
    "command": "type",
    "args": {"text": "’"},
    "when": "editorTextFocus"
}]

A few of notes:

  • I don’t mind that these keys apply for all file types, but it’s also possible to limit it to only MarkDown files in VS Code. Just append &&editorLangId==markdown to all the "when" conditions.
  • On macOS, I actually apply similar settings too, specifically for Alt+[, ] and ' (the first and third and last lines)!
  • Be aware that on macOS, the last line would overwrite the standard behaviour, but that’s ok since I never use æ.

Helpful?