In Neovim, we can use the virtual text
feature to place virtual text anywhere in the current buffer,
which is not possible with normal text.
A bit of history#
Initially, the Nvim core dev bfredl introduced nvim_buf_set_virtual_text()
to add virtual text to a buffer in this PR.
Over the time, the code is refactored and deprecated,
in favor of the new API function nvim_buf_set_extmark()
1.
Plugins utilizing virtual text#
Plugins have been using virtual text feature to do various things. Here is a non-exhaustive list:
- IndentBlankLine.nvim: Show indent guides even on blank lines. Previously, it is not possible to place text on blank lines. So there will be a gap in indent lines when there is a blank line, see this issue.
- nvim-cmp: show function signature using virtual text.
- nvim-hlslens: Show search count and index at EOL, an excellent alternative to vim-anzu and the likes.
- blamer.nvim: Show line blame messages at EOL2.
- Nvim-lspconfig: Show diagnostics as virtual text in the end of a line.
- virt-column.nvim: replace option
colorcolumn
using virtual text. - virtual-type.nvim: show variable type using virtual text.
- Extmark-toy.nvim: Showing cool visual effects.
Using extmarks#
The nvim_buf_set_extmark()
function has a lot of parameters,
and some of them can be confusing for users due to the conciseness of its documentation.
Here is a working example to demonstrate its usage:
local api = vim.api
local bnr = vim.fn.bufnr('%')
local ns_id = api.nvim_create_namespace('demo')
local line_num = 5
local col_num = 5
local opts = {
end_line = 10,
id = 1,
virt_text = {{"demo", "IncSearch"}},
virt_text_pos = 'overlay',
-- virt_text_win_col = 20,
}
local mark_id = api.nvim_buf_set_extmark(bnr, ns_id, line_num, col_num, opts)
In the above, line_num
specifies which line we want to put the virtual text.
col_num
specifies which column we want to put virtual text (but this is actually only half true, since we can put virtual text at any position).
col_num
shouldn’t exceed the actual column number of the line indicated by line_num
.
Otherwise, we get the following error message:
E5113: Error while calling lua chunk: test.lua:17: col value outside range
In the opts
parameter, there are more options to change the behavior of this function.
virt_text
is a table of table, where each sub-table contains some text and the highlight group for it.
The option virt_text_pos
has three possible values:
overlay
: overlay the virtual text on the column specified withcol_num
, this is actually the only case wherecol_num
really works.eol
: virtual text is placed at the end of the line (col_num
does not take effect).right_align
: virtual text is placed on the right of current line (col_num
does not take effect).
Check the title image for a comparison between the three position method.
To actually put virtual text on any column, we should use virt_text_win_col
in the opts table.
If we use virt_text_win_col
, virt_text_pos
does not take effect any more.
To delete a virtual text, use API function nvim_buf_del_extmark(bnr, ns_id, id)
,
where id
is the id used in opts
.