Using Neovim as your manpager

If you’re using Unix-like systems, then you’ve most likely dove into the manual pages (manpages) once. It’s a pretty neat offline documentation for those who need it (at least when there are manual pages for the application).

For those whose needs are simple, the default setup should suffice which its go-to manpages reader is less. However, there are different programs for that purpose. One of those is Neovim. And it is very handy.

While most of the things featured here are pretty much laid out from :Man section from Neovim help documents, this post shows some niceties as well as some problems with this setup.

I’ll be featuring Neovim with the factory default settings. Just assume that Neovim is executed with the --clean option enabled.

Also for future references, it is demonstrated with Neovim 0.9 (v0.9.0-dev-f0ee548).

Setting things up

In order to use Neovim as a manual pager in the terminal, we have to modify MANPAGER environment variable. Per the man(1) manual page:

If $MANPAGER or $PAGER is set ($MANPAGER is used in preference), its value is used as the name of the program used to display the manual page. By default, less is used, falling back to cat if less is not found or is not executable.

The value may be a simple command name or a command with arguments, and may use shell quoting (backslashes, single quotes, or double quotes). It may not use pipes to connect multiple commands; if you need that, use a wrapper script, which may take the file to display either as an argument or on standard input.

All you have to do is to set MANPAGER environment variable (e.g., set in your shell profile, invoke with a custom MANPAGER one-time) with Neovim.

Running a manual pager specifically with Neovim in Bash
MANPAGER="nvim +Man!" man systemd.timer

For those who are curious, the above snippet is setting MANPAGER to be Neovim with the :Man! command — which will render the buffer passed to Neovim as a manpage. Take note the +Man! is required because otherwise, the text looks like a jumbled mess like in the following image.

A mangled text buffer of systemd.timer manual page
Neovim as a manpager without the +Man! command

The niceties

There are a lot of good things Neovim has as a manual pager. The biggest thing is, of course, navigating the manual page with Neovim. Among other things, there are some more specific features that makes Neovim stands out as a pager.

For a start, here’s a quickstart:

  • Follow links from manpage to manpage with K which is very handy for navigating a suite of manpages like in systemd.

  • Go back from the previous manpage where the current manpage opened from with Ctrl+t.

  • Keymaps associated with jumplists (i.e., Ctrl+o and Ctrl+i) are very useful to navigate between different manpages.

Here’s a video that shows using Neovim with the previously mentioned keybindings.

You can also navigate an outline of the document with gO which is nice to navigate large documents. The outline will also show the flags and options if the manual page has a single- or double-dashed option at the beginning of a line (i.e., --option, -flag).

Unfortunately by default, gO only works on help and :Man buffers as indicated from the Neovim help document.

Also, this feature is not found in Vim.

A full window of the outline for yt-dlp
The outline of yt-dlp(1)

Additionally, you can also read manpages easily with the :Man command while using Neovim. It also comes with a nice tab completion.

Neovim with `:Man` and tab completion
:Man with tab completion

The problems

With its niceties, there are problems that you have to keep in mind. In particular, the way how Neovim opens.

In the following video, there are two pagers: less and Neovim opening configuration.nix(5) which is at least 150,000 lines, 400,000 words counted, totalling just 9MB in size. It should clearly show the different approach of opening.

Neovim versus less on opening configuration.nix(5)

For comprehension, here are several manpages that are quite big in comparison to the monstrous manual page. [1]

Table 1. Various manual pages and their filesize
Manual page Size (in MB)

systemd(1)

0.055

systemd.index(7)

0.13

bash(1)

0.43

systemd.directives(7)

0.8

ffmpeg-all(1)

1.69

configuration.nix(5)

9.01

As you can see Neovim is magnitudes slower due to the approach of loading the whole file in memory before showing it unlike what less is doing. [2] In practice, the difference can be negligible and only seen in larger documents since most manpages don’t reach even just a single megabyte.

Another problem is some of the rendering for manual pages is not great. Manpages in Neovim are rendered with hard-wrapping by default. This causes some inconvenience with links such as the following image showing a cut link for systemd-resolved.service(8) with hard-wrapping enabled.

Part of the manual page with a cut off manual reference
A hard-wrapped text of the reference causing the link to be cut off

A workaround is to set g:man_hardwrap to false which will cause Neovim to render it with soft-wrapping. You can run let g:man_hardwrap=0 in Ex mode and view a manpage with :Man (for example :Man systemd.unit(5)) to see the difference.

Part of the manual page with soft-wrapping enabled
A soft-wrapped text of the same reference

Take note that by soft-wrapping, you can encounter some new formatting problems. This is more noticeable with manpages that uses tables.

A jumbled text of a table inside of a manpage in Neovim
A soft-wrapped table in the systemd.unit(5) manpage

Another solution for this could be setting up MANWIDTH environment variable to a large number but this will make some formatting to be screwed up. The following image is what happens when you set MANWIDTH to 999.

Neovim manpager with screwed up manual header
Neovim manpager with MANWIDTH=999

Take note you’re also going to encounter the same problem as soft-wrapping it such as the previously shown jumbled tables. Seems like there’s a reason why it hard wraps by default.

Conclusion

Overall, Neovim as a manpager is not without its problems. It is, however, more useful for navigating manual pages compared to the default setup of most distributions.

  • The ability to jump into links alone is worth enough for me suitable for navigating indices like systemd.directives(7).

  • The handy-dandy :Man Ex command with tab completion is indeed handy for quickly checking manpages, bringing less need for a new shell.

  • If you’re familiar with Neovim, you’re already set on navigating between different pages and/or large documents. The additional things to learn is just negligible.

  • You can also take advantage of its plugin ecosystem. There are a variety of plugins (e.g., EasyMotion, harpoon) to make text navigation a nicer experience.


1. This will vary between different systems with different versions and all.
2. To be fair, it’s an issue for Neovim to open large files.