Vim-Plugins: Part 2 - Master Motion With vim-sneak and quick-scope
Vim-Plugins: Part 2 - Mastering motion with vim-sneak and quick-scope⌗
As vim is more often used for editing existing documents, one of the primary things you’ll do in vim normal mode is move the cursor around. Using hjkl
to navigate is one of the first things we learn in vim, but it only moves the cursor one space at a time: not very efficient! Of course, we can prepend our hjkl
with a number, indicating how many spaces or lines we wish the cursor to move. But this can be awkward, as it forces us to take a hand off of the home keys.
Vanilla vim offers many ways to move around a document more quickly and I highly recommend you read up on them. This post however, is about two of my favorite vim-plugins that have really increased my speed and efficiency in vim by allowing me to quickly move to a specific character anywhere on the screen: vim-sneak and quick-scope.
vim-sneak⌗
s{char}{char}
vim-sneak remaps s
in normal mode to its invocation; follow s
with two characters and it will jump your cursor to the next occurence of those two characters. If there are multiple occurences, it will jump to the first occurrence, and highlight the other subsequent occurrences. You can then move to the next highlighted occurence with ;
(or s
if you set let g:sneak#s_next = 1
as I have). S
will search backwards.
I’ve tried a variety of plugins and workflows to solve the problem of getting the cursor to a desired location on the screen, but have found vim-sneak to be the most efficient and simplest solution. The classic vanilla vim solution that most people use is /
which will search the entire document. This is still incredibly useful and I’ve not modified it with any plugins and use it often … but it does take more keystrokes than vim-sneak.
Also, searching a document and moving the cursor to a specific place on the screen are two different actions and I don’t like to conflate that functionality. Searching a document usually involves a pause in editing and thought while I consider what it is I need to search for. Moving the cursor around is an “in the moment” type of action for me: I know where I want the cursor to be without thinking about it and just want to get there as fast as possible. With vim-sneak, you begin the cursor movement with s
, a home key. That’s followed by the two characters vim-sneak will jump to. These are already known before invoking s
as they can be seen at the location on the screen where we wish the cursor to move. With vim’s built in vanilla search, the same is also true: you know what you want to search for before searching it … but you also have to press <enter>
: 4 keystrokes vs 3.
vim-easymotion⌗
Another contender in this space is vim-easymotion. It adds a ton of new functionality beyond simply moving the cursor to a specific position on the screen, which I won’t cover here (but I do recommend you check out their README). When I found vim-easymotion, I switched to it immediately from vim-sneak … but in the end, I came back to vim-sneak: it just felt simpler and more natural to me. Their replacement functionality to vim-sneak is invoked in the same way: s{char}{char}
, but then it highlights all instances of those two characters anywhere on the screen, and displays random characters overlaid on the occurrences. Typing these random characters will then move the cursor to their location. The benefit to this method is searching both forwards and backwards simultaneously. The downside though is twofold: more key strokes and you can’t know ahead of time what characters it will display over the matches.
And this latter downside is what pushed me back to vim-sneak in the end: pausing to consider the random characters it displays over the desired cursor position, and then typing them just causes too much delay and breaks my flow. With vim-sneak, there is almost no pause. Only when I find that another instance of the two characters I passed to vim-sneak exists before the one I was considering. But even in these scenarios, the solution is to just hit s
again to jump to the next occurence (or ;
if you keep the default mapping). I may come back to vim-easymotion again in the future for some of its other functionality though, as it is quite a compelling plugin.
quick-scope⌗
quick-scope is a very simple, yet helpful vim plugin. It doesn’t actally change any of vim’s default behavior: it simply adds color highlighting for when the f
key is invoked in normal mode. f{char}
will move the cursor to the next occurence of {char}
on the current line, while F
does the same but in reverse. It’s a very useful feature, but on larger lines, or cases where the {char}
is a commonly used letter like e
, it can be quite confusing picking a {char}
to jump to that doesn’t have an existing occurrence before the desires position.
Usually, when I use f
to jump around on a line, I have a specific word I want to edit, replace, or delete. I’m not actually concerned with jumping to a specific character, but a word. With quick-scope, pressing f
will now highlight a unique character, that doesn’t have preceeding occurences, in each word. This makes it very easy to determine what to press to get your cursor to a specific word.
Why not just use vim-sneak? Well, sometimes I do just that. But using f
and F
to jump around a line are vim built vanilla vim motions that I learned long before I ever learned of vim-sneak (or even that there were plugins for vim!). The functionality is already built in to vim, quick-scope just makes it easier and more pleasant to use.
set relativenumber⌗
Though we’ve spend this post discussing superior alternatives to moving around with hjkl
in vim, sometimes I do still rely on those motions to move around: in particular, moving up or down by line with j
and k
by preceeding them with a number, i.e., 5j
to move down 5 lines. set nu
will display line numbers, but moving down or up to a specific line then involves math to determine what number to preceed j
or k
with (or d
and y
for deleting and yanking by line). set relativenumber
will display the absolute line number of the current line, but will display the relative numbers above and below the current line, i.e., the first line above the current line is numbered 1
, the second line above current is numbered 2
, etc. This makes it quite easy to know how many lines away a particular line is from the current line.
Bring it all together⌗
With vim-sneak and quick-scope, we now have 2 very easy, efficient, and intuitive ways of moving the cursor to a specific location on the screen. Horizontal motion is still handled via f
and F
as in vanilla vim, but now we have the lovely highlighting provided by quick-scope to ease the process. Vertical motion is now handled by vim-sneak with s
and S
making it trivial to move to a specific location on the screen with as few as 3 key strokes.