loading...

Bring Your Vim/Tmux Navigation Reflexes to VS Code

ajkerrigan profile image AJ Kerrigan ・4 min read

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

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...

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!

Discussion

markdown guide
 

As someone who isn't fully immersed in modern javascript development but is a content user of vim/tmux (including vim-tmux-navigator), I can't imagine there being such a difference as to be worth giving up vim for. I suspect it has something to do with shortcomings with vim language server integration. Is it more than that? What's the motivation for moving to VS Code?

 

Hey Jeff, I wouldn't try to convince someone to give up vim for VS Code. I still happily use both myself, I just prefer VS Code more often these days and brought some vim muscle memory along for the ride.

Some of the work I prefer to handle in VS Code (testing and debugging for example) are just personal preference, and someone with a good set of vim skills/plugins/configuration would have no reason to switch. Other bits of functionality (like having side-by-side Markdown previews or Jupyter notebooks in the same editor as your regular code) work more nicely in a graphical environment... but not everybody wants or needs that.

I guess this is a bad sales job - I'd say keep using vim :).

 

Thanks for the reply AJ.

I'd heard a few people I trust mention either switching or a desire to so it seems like there must be something to this but I haven't probed deeper. I listened to a podcast interview where Chris Toomey himself said as much to my surprise. I've heard that some of the front end tooling is better and IIRC Chris mentioned the language server completion stuff. I just haven't seen what the difference is in practice. If I get more into modern front end development, I'll look further.

Anyways, cheers.