Bring Your Vim/Tmux Navigation Reflexes to VS Code
Tags: vim, tmux, vscode
Published: 2019-12-31 01:55:05

---
title: Bring Your Vim/Tmux Navigation Reflexes to VS Code
published: true
description: After installing the Vim extension, a few choice keybindings can help VS Code play even nicer with your terminal muscle memory.
tags: vim, tmux, vscode
---

### Introduction

One of the first tmux plugins that changed my brain was Chris Toomey's [vim-tmux-navigator](https://github.com/christoomey/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](https://thepracticaldev.s3.amazonaws.com/i/okv5swksaxj5hjmyel90.gif)

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](https://code.visualstudio.com/docs/getstarted/keybindings) and [extensions gallery](https://code.visualstudio.com/docs/editor/extension-gallery) provide lots of opportunities to make your terminal sensibilities feel at home. Installing the [VSCodeVim](https://github.com/VSCodeVim/Vim) 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:

```json
    {
        "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](https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts):

```json
    {
        "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:

```json
    {
        "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](https://code.visualstudio.com/docs/getstarted/keybindings#_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](https://thepracticaldev.s3.amazonaws.com/i/t0sjnd6xx72rjbju37zq.gif)

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](https://github.com/saulpw/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](https://dev.to/ajkerrigan/exploring-aws-from-the-terminal-with-visidata-10np) 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](https://www.bugsnag.com/blog/tmux-and-vim): 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?](https://dev.to/azure/what-are-your-favorite-vs-code-extensions-and-why-mn): 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](https://marketplace.visualstudio.com/items?itemName=arcsine.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!