· 6 min read

How I Boost Development Productivity with VSCodeVim

This article was auto-translated from Chinese. Some nuances may be lost in translation.

Around early 2021, I started using Vim for VSCode.

The reason was simple: after switching to an HHKB keyboard, there were no dedicated arrow keys (you have to hold Fn with your pinky), so I naturally wanted to minimize arrow key usage when editing text. Additionally, the Control key on an HHKB sits where Caps Lock usually is, making it much easier to press Control. Influenced by these external factors, I started learning Vim and found that pairing it with VSCode worked really well. Here, I’d like to share some thoughts and tips for anyone interested. If you’re curious about the HHKB keyboard, you can also check out my previous post — HHKB HYBRID Type-S Electrostatic Capacitive Keyboard Review.

VSCodeVim

VSCodeVim is an extension for VSCode that lets developers use Vim keybindings and motions inside VSCode. Using standalone Vim requires spending a lot of time tweaking configurations, and I didn’t want to leave the VSCode ecosystem, so pairing it directly with VSCode felt much smoother. This is also why I don’t recommend using standalone Vim alone: while tools are just aids, VSCode’s navigation, terminal integration, extensions, autocompletion, and other features can all effectively boost productivity.

This extension integrates very well with VSCode, allowing you to configure custom shortcuts bound to internal VSCode commands. Below, I’ll share several setups I use frequently. Rather than a Vim tutorial, this is more of a share on how I integrate this extension with other features.

Note that this article is simply recommending the combination of Vim and VSCodeVim; I’m not hard-selling Vim or insisting that every developer must use it.

(This article contains many GIF files. There is currently no image zoom feature, so if an image is too small, please open it in a new tab.)

Go to definition

When tracing source code, you often look at a function and its implementation at the same time. With the gd and gf bindings, I can navigate to implementations directly in normal mode without having to move the mouse, or quickly peek at types via preview, which is extremely convenient.

gd

Merge Conflict

When conflicts occur while merging a Pull Request, several options appear at the top right to help resolve them, allowing you to choose incoming, current, or both. Again, to keep all operations on the keyboard, I set up custom shortcuts for them.

conflict

Copy GitHub File URL

Suppose I find a file implementation in VSCode and want to share it with team members; navigating manually on GitHub would be too tedious. The GitLens extension actually already integrates this feature (gitlens.copyRemoteFileUrlFrom), so you can bind it to a shortcut. You can also configure it to open your browser and jump straight to the GitHub tab.

gitlen-copy

Quickly Prettify Code

I mapped the format document action to ff in normal mode, so simply pressing f twice immediately prettifies the file, which is very handy. Of course, you can also just enable “format on save”.

Git Blame

While Git Blame on GitHub is convenient, being able to do it inside VSCode is even better. GitLens already provides this functionality, so we just need to bind a shortcut to it. Like this, I can trace specific code using the keyboard, blaming step by step until I find the culprit. (I’m using my own project as an example, but it’s even more useful in collaborative team projects.)

blame

Open File in Finder (revealFileInOS)

Sometimes it’s useful to jump directly to the file’s path in the OS to make adjustments, so I also mapped this to a Vim shortcut.

reveal

Splitting 2 Tabs Side-by-Side (or Top-and-Bottom)

If you have a 27-inch external monitor, placing tabs side-by-side when writing HTML and CSS simultaneously makes them easier to view and switch between. In VSCodeVim, you can achieve this with :vs or :sp. You can also switch between panes using <C-w> + arrow keys.

split

If you’re interested, feel free to refer to the JSON configuration below. Everyone has their own preferred keybindings, so feel free to modify it according to your needs.

"vim.normalModeKeyBindings": [
    {
      "before": [
        "g", "l"
      ],
      "commands": [
        "cmake.build"
      ]
    },
    {
      "before": [
        "<leader>",
        "q"
      ],
      "commands": [
        "workbench.action.openRecent"
      ]
    },
    {
      "before": [
        "g",
        "f"
      ],
      "commands": [
        "editor.action.peekDefinition"
      ]
    },
    {
      "before": [
        "g",
        "n"
      ],
      "commands": [
        "cmake.build"
      ]
    },
    {
      "before": [
        "<leader>",
        "<leader>",
        "c"
      ],
      "commands": [
        "merge-conflict.accept.current"
      ]
    },
    {
      "before": [
        "<leader>",
        "o"
      ],
      "commands": [
        "gitlens.openFileOnRemoteFrom"
      ]
    },
    {
      "before": [
        "<leader>",
        "<leader>",
        "i"
      ],
      "commands": [
        "merge-conflict.accept.incoming"
      ]
    },
    {
      "before": [
        "<leader>",
        "<leader>",
        "b"
      ],
      "commands": [
        "merge-conflict.accept.both"
      ]
    },
    {
      "before": [
        "<leader>",
        "s"
      ],
      "commands": [
        "workbench.action.quickOpenTerm"
      ]
    },
    {
      "before": [
        "<leader>",
        "c"
      ],
      "commands": [
        "gitlens.copyRemoteFileUrlFrom"
      ]
    },
    {
      "before": [
        "<leader>",
        "b"
      ],
      "commands": [
        "gitlens.toggleFileBlame"
      ]
    },
    {
      "before": [
        "<leader>",
        "p"
      ],
      "commands": [
        "gitlens.openBlamePriorToChange"
      ]
    },
    {
      "before": [
        "<leader>",
        "a"
      ],
      "commands": [
        "workbench.view.explorer"
      ]
    },
    {
      "before": [
        "<leader>",
        "<leader>",
        "r"
      ],
      "commands": [
        "revealFileInOS"
      ]
    },
    {
      "before": [
        "f",
        "f"
      ],
      "commands": [
        "editor.action.formatDocument"
      ]
    },
    {
      "before": [
        "+",
        "+"
      ],
      "commands": [
        "workbench.action.increaseViewSize"
      ]
    },
    {
      "before": [
        "-",
        "-"
      ],
      "commands": [
        "workbench.action.decreaseViewSize"
      ]
    }
 ]

Other Handy Tips

  • vit vat to select tag blocks: Selects the block enclosed by tags directly, such as code wrapped inside a <div>.
    • By extension, cit, dit, etc., can all be used to modify or delete the content respectively.
  • dst to remove the outer tag: In frontend work, you often have a wrapper div that you suddenly don’t need anymore; this command removes it easily.
  • cstt to change tags, e.g., from p to div: This is my favorite command—it makes changing tags super fast. change-tag
  • .: Repeat the previous action.
  • yssb: Surround the text block with ().
  • yiw ciw: Delete / change a single word.
  • cs"': Replace " with '.
  • dgn: Delete the search match.

I won’t list every other Vim trick here. VSCodeVim also supports macro recording—for more complex operations, you can record a macro first and replay it to save keystrokes.

Related Posts

Explore Other Topics