In my search to find the best jumping plugin, I have tried flash.nvim, leap.nvim, and now hop.nvim. Here’s what I found when using that plugin.
Intro
From the Github page:
Hop is an EasyMotion-like plugin allowing you to jump anywhere in a document with as few keystrokes as possible. It does so by annotating text in your buffer with hints, short string sequences for which each character represents a key to type to jump to the annotated text. Most of the time, those sequences’ lengths will be between 1 to 3 characters, making every jump target in your document reachable in a few keystrokes.
I haven’t tried EasyMotion either so I suppose that will be in a future article / experiment.
Seems very promising and having to only type a couple keys to jump anywhere is certainly functionality that anyone using Neovim is interested in.
When researching hop.nvim I found that the original repo is not maintained and there is a fork that is being actively maintained. So when installing make sure you use the new repo.
Original repo — https://github.com/hadronized/hop.nvim
New repo — https://github.com/smoka7/hop.nvim
Run :checkhealth
to verify everything is working correctly after installation.
Note: I saw a couple deprecation warnings around report_start() in case you see the same. But everything worked alright.
Installation
Let’s get hop.nvim installed and up and running so we can go through how to use it.
Install using lazy.nvim:
{
'smoka7/hop.nvim',
version = "*",
opts = {
keys = 'etovxqpdygfblzhckisuran'
}
}
Installation here is pretty straight forward, make sure you restart Neovim to get the plugin installed.
If you want to tweak the hop keys that show up when using the different commands, update the string of random looking characters under opts
and keys
.
Usage
Now the fun part!
Default keymaps
There are none!
The way you use hop.nvim is by leveraging the various commands and running them after different Vim motions (probably by mapping them to different keybindings).
It is important to note, not everything hop.nvim can do is exposed by commands: only the mostly used commands have an exported Neovim command. Some features might require you to go through the Lua API instead.
You can then map commands to different keybindings
https://github.com/smoka7/hop.nvim/wiki/Commands
Here are a list of commands that you can make use of:
Go to anywhere (:HopAnywhere)
- most powerful but usually means you will need to type multiple characters (personally I would use :HopWord or :HopChar1 or :HopChar2 instead of this command)
- when triggering this one you will see a jump character over EVERYTHING in the buffer
Go to any word in the current buffer (:HopWord)
- probably most useful command. hints all words in your buffer
Go to any camelCase word in the current buffer (:HopCamelCase)
- similar to :HopWord but specific to camel case words
Go to any character in the current buffer (:HopChar1)
- good to have mapped to a quick keybinding
- starts matching after 1 character and will hop if only 1 match (see first GIF)
Go to any bigrams in the current buffer (:HopChar2)
- good to have mapped to a quick keybinding; matches just about anywhere with two characters (MUST TYPE 2 characters)
You can update the highlight color to have both be highlighted instead of partially subdued if you prefer seeing both characters more clearly
vim.api.nvim_create_autocmd('ColorScheme', {
callback = function()
vim.api.nvim_set_hl(0, 'HopNextKey', { fg = '#ff9900', bold = true, ctermfg = 198, cterm = { bold = true } })
vim.api.nvim_set_hl(0, 'HopNextKey1', { fg = '#ff9900', bold = true, ctermfg = 198, cterm = { bold = true } })
vim.api.nvim_set_hl(0, 'HopNextKey2', { fg = '#ff9900', bold = true, ctermfg = 198, cterm = { bold = true } })
end,
})
Note: I am using ‘brenoprata10/nvim-highlight-colors’ to show colors within Neovim
Make an arbitrary search akin to /
and go to any occurrences (:HopPattern).
- similar to what flash.nvim offers
Go to any line and any line start (:HopLine, :HopLineStart).
- allows you to hop to any line or any non-blank line start, respectively
- :HopVertical works similarly but tries to keep your cursor position
Paste text in the hinted position without jumping (:HopPasteChar1).
- paste without jumping
- similar to what flash remote does
Yank the text between two hinted position without jumping (:HopYankChar1).
- yank without jumping
- similar to what flash remote does
- provide start and end character (to me this feels like a LOT to yank some text without jumping)
Go to treesitter nodes (:HopNodes)
- jump to treesitter nodes
Now that we have an idea about many of the commands, we can use them in conjunction with Vim motions like like v, d, c, y to visually select/delete/change/yank.
For example, you might type v
and :HopWord
(or a keybinding for that command) to highlight from where you are to another location above or below your cursor.
You can do the same thing with any of the other motions and commands. Play around with different combinations and see what works best for you!
Command Variations
In addition to the commands we just went over, there are even MORE Command variations for constraining / adapting how each command works.
A variation is more restricted or more general version of the command without the variation. For instance, the
HopWord
command can have variations allowing to run that command across all visible buffers (and not only the current one) or on the portion of text before the cursor. Not all commands have the same variations and if you don’t find it, the Lua API can still do it.
Here are examples of how you can adapt a command:
Hop*BC: run Hop* before the cursor.
Hop*AC: run Hop* after the cursor.
Hop*CurrentLine: run Hop* on the current line only.
Hop*MW: run Hop* across all visible buffers.
As an example, I use this multi window for HopWord
:
vim.keymap.set({“n”, “x”, “o”}, “s”, “<cmd>HopWordMW<CR>”, { desc = “Hop Word” })
Here is what I settled on using in my config:
vim.keymap.set({"n", "x", "o"}, "s", "<cmd>HopWordMW<CR>", { desc = "Hop Word" })
vim.keymap.set({"n", "x", "o"}, "S", "<cmd>HopNodes<CR>", { desc = "Hop Nodes" })
Lua API
In addition to the defined commands and command variations, there are even MORE options using the Lua API.
require'hop'.hint_anywhere() -- HopAnywhere
require'hop'.hint_char1() -- HopChar1
require'hop'.hint_char2() -- HopChar2
require'hop'.hint_lines() -- HopLine
require'hop'.hint_lines_skip_whitespace() -- HopLineStart
require'hop'.hint_vertical() -- HopVertical
require'hop'.hint_patterns() -- HopPattern
require'hop'.hint_words() -- HopWord
Note: if you need more information on the various Lua API functions, you can always use the embedded documentation with
:h hop-lua-api
.
Here are a few examples from the Github page on using the Lua API to extend f, t, F, T
to provide hints when there are multiple matches in a line:
local hop = require("hop")
local directions = require("hop.hint").HintDirection
vim.keymap.set("", "f", function()
hop.hint_char1({ direction = directions.AFTER_CURSOR, current_line_only = true })
end, { remap = true })
vim.keymap.set("", "F", function()
hop.hint_char1({ direction = directions.BEFORE_CURSOR, current_line_only = true })
end, { remap = true })
vim.keymap.set("", "t", function()
hop.hint_char1({ direction = directions.AFTER_CURSOR, current_line_only = true, hint_offset = -1 })
end, { remap = true })
vim.keymap.set("", "T", function()
hop.hint_char1({ direction = directions.BEFORE_CURSOR, current_line_only = true, hint_offset = 1 })
end, { remap = true })
Advanced Usage
If all of this ability to customize and configure hop.nvim wasn’t enough for you with using Commands, Command Variations, and the Lua API.
You can go even further:
Check out the wiki page here: https://github.com/smoka7/hop.nvim/wiki
Create new Hop commands using the Lua API mentioned above
Create Hop extensions
:h hop-extension
Thoughts
I can tell why people really love hop.nvim. The amount of customization is incredible and you can really adapt this plugin to whatever you want you workflow to be and how you want to jump or combine with Vim motions.
I like the hints for f, F, t, T
if there are multiple matches and NO hint if there is only one match. Feels pretty nice. And this is all part of the extreme customization.
HopWord
seems good
- like that is gives you both hints visually and you can hop right to a word sometimes
- the difference between HopCamelCase
, HopChar1
, HopChar2
wasn’t enough for me to want to have them over using HopWord
.
The amount of ways you can configure and use Hop is both impressive and overwhelming. For me it leaned more on the excessive side and had features and options that I likely won’t really use.
I personally don’t like how HopNodes
works. The matches that it provides is not as good and intuitive as flash treesitter in my experience.
After trying out hop.nvim for awhile and exploring some of it’s features, I still prefer using flash.nvim.
I like that you can keep typing characters after triggering the jump capability in flash and it feels less abrupt than triggering the jump command and then trying to figure out what key combination I need to type next.
Conclusion
Even though I still like flash nvim the best because of the searching and then jumping aspect, I did really like the enhanced f, t, F, T
hints and will see if I can customize flash to have that same capability. If you use hop.nvim or I missed a key feature that you really enjoy then please let me know! Stay tuned for the next jump plugin experiment as we continue to search for the best one!
If you enjoy topics like this then you might also like my Youtube channel. Have a great day!