Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Advanced Hop

Dimitri Sabadie edited this page Jul 5, 2022 · 7 revisions

Advanced Hop motions

You have made it so far. It is time for you to learn how to use more advanced features of Hop by calling the various Lua API functions.

Note: if you need more information on the various Lua API functions, you can always use the embedded documentation with :h hop-lua-api.

Lua equivalents of Hop commands

Every Hop command is actually implemented as a Lua call to the associated Lua API function. Here is a mapping between Hop commands and the associated Lua function:

Hop command Lua API function
HopAnywhere require'hop'.hint_anywhere()
HopChar1 require'hop'.hint_char1()
HopChar2 require'hop'.hint_char2()
HopLine require'hop'.hint_lines()
HopLineStart require'hop'.hint_lines_skip_whitespace()
HopVertical require'hop'.hint_vertical()
HopPattern require'hop'.hint_patterns()
HopWord require'hop'.hint_words()

You will need those Lua functions to build more sophisticated motions. All those commands take a single, optional argument, called opts. That argument is the same as the one passed to require'hop'.setup. However, the one passed to those functions takes precedence on the one passed to the setup function, so it’s the right place to override and customize a single call invocation. It allows you to test a specific kind of option while calling the function. For instance, if you want to see what it looks like to run hint_words with keys changed to something else, you can still run a command like this, using the : Neovim command line:

:lua require'hop'.hint_words({ keys = 'abcd' })

From now on, it is highly recommended that you first test your commands using this UX, as it is much faster to run Lua code in the command line rather than binding them to a key and restarting Neovim.

Before providing you some useful examples, we need to talk about command variations.

Hop command variations

As you might have read in the Commands page, most of Hop commands have variations. There is no black magic here and you should already start to understand how they are made. A clue: they are just regular Lua API calls with some opts options overridden, as seen above.

Here is a table showing how variations are made:

Hop command variation Lua API function
Hop*BC require'hop'.*({ direction = require'hop.hint'.HintDirection.BEFORE_CURSOR })
Hop*AC require'hop'.*({ direction = require'hop.hint'.HintDirection.AFTER_CURSOR })
Hop*CurrentLine require'hop'.*({ current_line_only = true })
Hop*MW require'hop'.*({ multi_windows = true })

It’s as simple as that.

Building advanced Hop motions

By leveraging everything you now know about Hop commands, variations and the Lua API, you can already make very powerful and acute motions. Let’s see a couple of them.

Reimplement f / F

The f and F Neovim motions are very important kind of motions, as they are built-ins allowing to quickly move on the current line. f goes after the cursor, and F goes backwards, before the cursor. You might already see how you could reimplement those motions, right?

Let’s do f (put everything on the same line; we break it on multiple lines for readability):

:lua require'hop'.hint_char1({
  direction = require'hop.hint'.HintDirection.AFTER_CURSOR,
  current_line_only = true
})

And let’s do F:

:lua require'hop'.hint_char1({
  direction = require'hop.hint'.HintDirection.BEFORE_CURSOR,
  current_line_only = true
})

Reimplement t / T

The t and T Neovim motions are very useful. They are very similar to f and F but instead of moving on the actual target, they move one character before. If you have read the Configuration page and the previous section, you already know how to reimplement both motions.

For t:

:lua require'hop'.hint_char1({
  direction = require'hop.hint'.HintDirection.AFTER_CURSOR,
  current_line_only = true,
  hint_offset = -1
})

And T:

:lua require'hop'.hint_char1({
  direction = require'hop.hint'.HintDirection.BEFORE_CURSOR,
  current_line_only = true,
  hint_offset = -1
})

It’s so simple.

It’s HopWord, but only for the current line

:lua require'hop'.hint_word({
  direction = require'hop.hint'.HintDirection.BEFORE_CURSOR,
  current_line_only = true,
})

A f / F, but that jumps one character after

:lua require'hop'.hint_char1({
  direction = require'hop.hint'.HintDirection.AFTER_CURSOR,
  current_line_only = true,
  hint_offset = 1
})
:lua require'hop'.hint_char1({
  direction = require'hop.hint'.HintDirection.BEFORE_CURSOR,
  current_line_only = true,
  hint_offset = 1
})