Introduction

One of the first tmux plugins that changed my brain was Chris Toomey’s vim-tmux-navigator. Sure it makes things more convenient, but the core idea is that switching between sections of a terminal window should feel natural and consistent. It shouldn’t matter whether those sections are tmux panes or vim splits:

vim-tmux-navigator demo

It’s an idea that seems obvious in retrospect. In this post, we’ll walk through a couple ways to apply that mindset to VS Code keybindings.

Terminal Muscle Memory in a GUI World

VS Code’s customizable keybindings and extensions gallery provide lots of opportunities to make your terminal sensibilities feel at home. Installing the VSCodeVim extension is a great start! But if you feel at home at the terminal, you’ll probably be missing a few of your favorite shortcuts.

To keep this post manageable, I’ll focus on a few key bindings I use so often in tmux that not having them in VS Code makes my fingers cry:

  • Ctrl-(h|j|k|l)
  • Bounce around between panes
  • Ctrl-a
|
Create a vertical split
Ctrl-a
-
Create a horizontal split
Ctrl-a
x
Close a pane

Keybindings for Navigation

At a glance, this seems like a simple request. Ctrl plus a vim direction key should take my focus in that direction. So I can add a few key bindings:

    {
        "key": "ctrl+k",
        "command": "workbench.action.navigateUp"
    },
    {
        "key": "ctrl+j",
        "command": "workbench.action.navigateDown"
    },
    {
        "key": "ctrl+h",
        "command": "workbench.action.navigateLeft"
    },
    {
        "key": "ctrl+l",
        "command": "workbench.action.navigateRight"
    }

And… done, right? Except I’m picky, so that doesn’t quite cover it. When my focus is in the panel below my open editors, I want Ctrl-(h|l) to move left/right between panel tabs. Fortunately, we can cover that by taking advantage of “when” clause contexts:

    {
        "key": "ctrl+h",
        "command": "workbench.action.previousPanelView",
        "when": "panelFocus"
    },
    {
        "key": "ctrl+l",
        "command": "workbench.action.nextPanelView",
        "when": "panelFocus"
    }

VS Code will use that “when” context to find the most specific matching key binding. So if my focus is in the panel, Ctrl-h will move to the previous panel tab. Otherwise, it will navigate left by one view. Ah… much better, feeling more comfy all the time.

But there’s still a tiny thing bugging me. If I move focus into the sidebar when I’ve got the Explorer viewlet visible, I want to use Ctrl-(j|k) to move between the file explorer and open editors view. If I’m being honest, this isn’t even something I really need! I just want it because I noticed it’s not there, and it felt like bumping into an invisible wall in a video game.

Again, “when” clause contexts can satisfy even this silly requirement:

    {
        "key": "ctrl+k",
        "command": "workbench.files.action.focusOpenEditorsView",
        "when": "sideBarFocus && explorerViewletVisible"
    },
    {
        "key": "ctrl+j",
        "command": "workbench.files.action.focusFilesExplorer",
        "when": "sideBarFocus && explorerViewletVisible && !filesExplorerFocus"
    }

The “when” clause is a little more complex in this case, but the core concept is the same. Things can get progressively more wild and powerful, combining out-of-the-box contexts with additional contexts from extensions. But that’s a story for another day, for the purposes of this post my fingers are happy!

Watch it Work

With these keybindings in place, I can hop around VS Code in a way that maps nicely to my tmux expectations:

VS Code navigation demo

Terminal-lovers, I doubt that your preferences will exactly match mine. Still, I hope that some of the examples in this post will help you tweak VS Code to suit you.

Note: For the record, the codebase I have open there is VisiData. That’s not an entirely random choice - if you’re happy in the terminal, you’ll probably find some handy uses for VisiData. I’ll dig into that more in a separate post…

Update (2020-Oct): Here’s a separate post :).

In the meantime, thanks for reading! Criticism, comments and questions are all welcome. So fire away in the comments!

References

  • Tmux and Vim - even better together: I’m pretty sure this is the first place I saw the idea to rebind keys for horizontal/vertical splits using | and - . It seemed so obvious in retrospect, I made the change immediately and never looked back.
  • What are your favorite VS Code extensions and why?: There are lots of VS Code extension posts around, it can be overwhelming. Your projects and personal preference will guide this though, so linking to a discussion post seems fitting.
  • Chronicler: I used this VS Code extension to record my session, after a few other methods yielded unreasonably large files and/or messed up colors. Chronicler was less work for better results, nice!

This post is also available on DEV.