Lua engine
Rustvim :help pages, generated
from source
using the tree-sitter-vimdoc parser.
INTRODUCTION
The Lua 5.1 script engine is builtin and always available. Try this command to
get an idea of what lurks beneath:
:lua vim.print(package.loaded)
Nvim includes a "standard library" lua-stdlib for Lua. It complements the
"editor stdlib" (vimscript-functions + Ex-commands) and the API, all of
which can be used from Lua code (lua-vimscript vim.api). These three
namespaces form the Nvim programming interface.
Lua plugins and user config are automatically discovered and loaded, just like
Vimscript. See lua-guide for practical guidance.
You can also run Lua scripts from your shell using the -l argument:
nvim -l foo.lua [args...]
Lua 5.1 is the permanent interface for Nvim Lua. Plugins should target Lua 5.1
as specified in luaref; later versions (which are essentially different,
incompatible, dialects) are not supported. This includes extensions such as
goto that some Lua 5.1 interpreters like LuaJIT may support.
While Nvim officially only requires Lua 5.1 support, it should be built with
LuaJIT or a compatible fork on supported platforms for performance reasons.
LuaJIT also comes with useful extensions such as
ffi, lua-profile, and
enhanced standard library functions; these cannot be assumed to be available,
and Lua code in init.lua or plugins should check the jit global variable
before using them:if jit then
-- code for luajit
else
-- code for plain lua 5.1
end
One exception is the LuaJIT
bit extension, which is always available: when
built with PUC Lua, Nvim includes a fallback implementation which provides
require("bit"). See lua-bit.
If Nvim is built with LuaJIT, Lua code can be profiled via
-- Start a profiling session:
require('jit.p').start('ri1', '/tmp/profile')
-- Perform arbitrary tasks (use plugins, scripts, etc.) ...
-- Stop the session. Profile is written to /tmp/profile.
require('jit.p').stop()
See https://luajit.org/ext_profiler.html or the p.lua source for details::lua vim.cmd.edit(package.searchpath('jit.p', package.path))
LUA CONCEPTS AND IDIOMS
Lua is very simple, and _consistent_: while there are some quirks, once you
internalize those quirks, everything works the same everywhere. Scopes
(closures) in particular are very consistent, unlike JavaScript or most other
languages.
Lua has three fundamental mechanisms—one for "each major aspect of
programming": tables, closures, and coroutines.
https://www.lua.org/doc/cacm2018.pdf
Tables are the "object" or container datastructure: they represent both
lists and maps, you can extend them to represent your own datatypes and
change their behavior using metatables (like Python's "datamodel").
EVERY scope in Lua is a closure: a function is a closure, a module is
a closure, a
do block (lua-do) is a closure--and they all work the same.
A Lua module is literally just a big closure discovered on the "path"
(where your modules are found: package.cpath).
Stackful coroutines enable cooperative multithreading, generators, and
versatile control for both Lua and its host (Nvim).
Lua functions may throw lua-errors for exceptional (unexpected) failures,
which you can handle with pcall().
When failure is normal and expected, it's idiomatic to return
nil which
signals to the caller that failure is not "exceptional" and must be handled.
This "result-or-message" pattern is expressed as the multi-value return type
any|nil,nil|string, or in LuaLS notation:---@return any|nil # result on success, nil on failure. ---@return nil|string # nil on success, error message on failure.
When a caller can't proceed on failure, it's idiomatic to
assert() the
"result-or-message" result:
local value = assert(fn())
Guidance: use the "result-or-message" pattern for...
Functions where failure is expected, especially when communicating with the
external world. E.g. HTTP requests or LSP requests often fail because of
server problems, even if the caller did everything right.
Functions that return a value, e.g. Foo:new().
When there is a list of known error codes which can be returned as a third
value (like luv-error-handling).
An iterator is just a function that can be called repeatedly to get the "next"
value of a collection (or any other iterable). This interface is expected by
for-in loops, produced by pairs(), supported by vim.iter, etc.
https://www.lua.org/pil/7.1.html
An "iterable" is anything that vim.iter() can consume: tables, dicts, lists,
iterator functions, tables implementing the __call() metamethod, and
vim.iter() objects.
Iterators on lua-list tables have a "middle" and "end", whereas iterators in
general may be logically infinite. Therefore some vim.iter operations (e.g.
IterArray:rev()) make sense only on list-like tables (which are finite by
definition).
Lua functions can be called in multiple ways. Consider the function:
local foo = function(a, b)
print("A: ", a)
print("B: ", b)
end
The first way to call this function is:foo(1, 2)
-- ==== Result ====
-- A: 1
-- B: 2
This way of calling a function is familiar from most scripting languages. In
Lua, any missing arguments are passed as nil, and extra parameters are
silently discarded. Example:foo(1)
-- ==== Result ====
-- A: 1
-- B: nil
When calling a function, you can omit the parentheses if the function takes
exactly one string literal (
"foo") or table literal ({1,2,3}). The latter
is often used to mimic "named parameters" ("kwargs" or "keyword args") as in
languages like Python and C#. Example:local func_with_opts = function(opts)
local will_do_foo = opts.foo
local filename = opts.filename
-- ...
end
func_with_opts { foo = true, filename = "hello.world" }
There's nothing special going on here except that parentheses are implicitly
added. But visually, this small bit of sugar gets reasonably close to a
"keyword args" interface.
Lua intentionally does not support regular expressions, instead it has limited
lua-patterns which avoid the performance pitfalls of extended regex. Lua
scripts can also use Vim regex via vim.regex().
Examples:
print(string.match("foo123bar123", "%d+"))
-- 123
print(string.match("foo123bar123", "[^%d]+"))
-- foo
print(string.match("foo123bar123", "[abc]+"))
-- ba
print(string.match("foo.bar", "%.bar"))
-- .bar
IMPORTING LUA MODULES
Modules are searched for under the directories specified in 'runtimepath' and
packages-runtimepath, in the order they appear in the output of this command
:echo nvim_list_runtime_paths()
Any "." in the module name is treated as a directory separator when searching.
For a module
foo.bar, each directory is searched for lua/foo/bar.lua, then
lua/foo/bar/init.lua. If no files are found, the directories are searched
again for a shared library with a name matching lua/foo/bar.?, where ? is
a list of suffixes (such as so or dll) derived from the initial value of
package.cpath. If still no files are found, Nvim falls back to Lua's default
search mechanism. The first script found is run and require() returns the
value returned by the script if any, else true.
The return value is cached after the first call to
require() for each module,
with subsequent calls returning the cached value without searching for, or
executing any script. For further details see require().
For example, if 'runtimepath' is
foo,bar and package.cpath was
./?.so;./?.dll at startup, require('mod') searches these paths in order
and loads the first module found ("first wins"):foo/lua/mod.lua foo/lua/mod/init.lua bar/lua/mod.lua bar/lua/mod/init.lua foo/lua/mod.so foo/lua/mod.dll bar/lua/mod.so bar/lua/mod.dll
Note:
Although 'runtimepath' is tracked, Nvim does not track current
values of package.path or package.cpath. If you happen to delete some
paths from there you can set 'runtimepath' to trigger an update:
let &runtimepath = &runtimepath
Skipping paths from 'runtimepath' which contain semicolons applies both to
package.path and package.cpath. Given that there are some badly written
plugins using shell, which will not work with paths containing semicolons,
it is better to not have them in 'runtimepath' at all.
To get its own location, Lua scripts/modules can use debug.getinfo():
debug.getinfo(1, 'S').source:gsub('^@', '')
COMMANDS
These commands execute a Lua chunk from either the command line (:lua, :luado)
or a file (:luafile) on the given line [range]. As always in Lua, each chunk
has its own scope (closure), so only global variables are shared between
command calls. The lua-stdlib modules, user modules, and anything else on
package.path are available.
The Lua print() function redirects its output to the Nvim message area, with
arguments separated by " " (space) instead of "\t" (tab).
:lua
{chunk}
Executes Lua chunk {chunk}. If {chunk} starts with "=" the rest of the
chunk is evaluated as an expression and printed. :lua =expr and :=expr
are equivalent to :lua print(vim.inspect(expr)). E5107 E5108
Examples:
:lua vim.api.nvim_command('echo "Hello, Nvim!"')
To see the Lua version:
:lua print(_VERSION)
To see the LuaJIT version:
:lua =jit.version
:{range}lua
Executes buffer lines in
{range} as Lua code. Unlike :source, this
always treats the lines as Lua code.
Example: select the following code and type ":lua<Enter>" to execute it:
print(string.format(
'unix time: %s', os.time()))
:lua << [trim] [
{endmarker}]:lua-heredoc{script}
{endmarker}
Executes Lua script {script} from within Vimscript. You can omit
[endmarker] after the "<<" and use a dot "." after {script} (similar to
:append, :insert). Refer to :let-heredoc for more information.
Example:
function! CurrentLineInfo()
lua << EOF
local linenr = vim.api.nvim_win_get_cursor(0)[1]
local curline = vim.api.nvim_buf_get_lines(0, linenr - 1, linenr, false)[1]
print(string.format('Line [%d] has %d bytes', linenr, #curline))
EOF
endfunction
Note that the
local variables will disappear when the block finishes.
But not globals.
:[range]luado
{body}
Executes Lua chunk "function(line, linenr) {body} end" for each buffer
line in [range], where line is the current line text (without <EOL>),
and linenr is the current line number. If the function returns a string
that becomes the text of the corresponding buffer line. Default [range] is
the whole file: "1,$". E5109 E5110 E5111
Examples:
:luado return string.format("%s\t%d", line:reverse(), #line)
:lua require"lpeg"
:lua -- balanced parenthesis grammar:
:lua bp = lpeg.P{ "(" * ((1 - lpeg.S"()") + lpeg.V(1))^0 * ")" }
:luado if bp:match(line) then return "=>\t" .. line end
:luafile
{file}
Execute Lua script in {file}.
The whole argument is used as the filename (like :edit), spaces do not
need to be escaped. Alternatively you can :source Lua files.
E5111 E5112 E5113
Examples:
:luafile script.lua
:luafile %
luaeval()
The (dual) equivalent of "vim.eval" for passing Lua values to Nvim is
"luaeval". "luaeval" takes an expression string and an optional argument used
for _A inside expression and returns the result of the expression. It is
semantically equivalent in Lua to:
local chunkheader = "local _A = select(1, ...) return "
function luaeval (expstr, arg)
local chunk = assert(loadstring(chunkheader .. expstr, "luaeval"))
return chunk(arg) -- return typval
end
Lua nils, numbers, strings, tables and booleans are converted to their
respective Vimscript types. If a Lua string contains a NUL byte, it will be
converted to a Blob. Conversion of other Lua types is an error.
The magic global "_A" contains the second argument to luaeval().
Example:
:echo luaeval('_A[1] + _A[2]', [40, 2])
" 42
:echo luaeval('string.match(_A, "[a-z]+")', 'XYXfoo123')
" foo
Lua tables are used as both dictionaries and lists, so it is impossible to
decide whether empty table is a list or a dict. Also Lua does not have integer
numbers. To disambiguate these cases, we define:
Empty table is a list. Use vim.empty_dict() to represent empty dict.
Table with N consecutive (no
nil values, aka "holes") integer keys 1…N is
a list. See also list-iterator.
lua-dict
Table with string keys, none of which contains NUL byte, is a dict.
Table with string keys, at least one of which contains NUL byte, is also
considered to be a dictionary, but this time it is converted to
a msgpack-special-map.
lua-special-tbl E5100 E5101 E5102
Table with
vim.type_idx key may be a dictionary, a list or floating-point
value:
{[vim.type_idx]=vim.types.float, [vim.val_idx]=1} is converted to
a floating-point 1.0. Note that by default integral Lua numbers are
converted to Numbers, non-integral are converted to Floats. This
variant allows integral Floats.
{[vim.type_idx]=vim.types.dictionary} is converted to an empty
dictionary, {[vim.type_idx]=vim.types.dictionary, [42]=1, a=2} is
converted to a dictionary {'a': 42}: non-string keys are ignored.
Without vim.type_idx key tables with keys not fitting in 1., 2. or 3.
are errors.
{[vim.type_idx]=vim.types.array} is converted to an empty list. As well
as {[vim.type_idx]=vim.types.array, [42]=1}: integral keys that do not
form a 1-step sequence from 1 to N are ignored, as well as all
non-integral keys.
Examples:
:echo luaeval('math.pi')
:function Rand(x,y) " random uniform between x and y
: return luaeval('(_A.y-_A.x)*math.random()+_A.x', {'x':a:x,'y':a:y})
: endfunction
:echo Rand(1,10)
Note: Second argument to
luaeval is converted ("marshalled") from Vimscript
to Lua, so changes to Lua containers do not affect values in Vimscript. Return
value is also always converted. When converting, msgpack-special-dicts are
treated specially.
Vimscript v:lua interface
From Vimscript the special
v:lua prefix can be used to call Lua functions
which are global or accessible from global tables. The expressioncall v:lua.func(arg1, arg2)
is equivalent to the Lua chunkreturn func(...)
where the args are converted to Lua values. The expressioncall v:lua.somemod.func(args)
is equivalent to the Lua chunkreturn somemod.func(...)
Lua module functions can be accessed like:call v:lua.require'mypack'.func(arg1, arg2)
call v:lua.require'mypack.submod'.func(arg1, arg2)
Note: Only single quote form without parens is allowed. Using
require"mypack" or require('mypack') as a prefix does NOT work.
You can use
v:lua in "func" options like 'tagfunc', 'omnifunc', etc.
For example consider the following Lua omnifunc handler:
function mymod.omnifunc(findstart, base)
if findstart == 1 then
return 0
else
return {'stuff', 'steam', 'strange things'}
end
end
-- Note: The module ("mymod") must be a Lua global, or use require() as
-- shown above to access it from a package.
vim.bo[buf].omnifunc = 'v:lua.mymod.omnifunc'
You can also use v:lua to call Lua functions as Vimscript methods::eval arg1->v:lua.somemod.func(arg2)
Note:
v:lua without a call is not allowed in a Vimscript expression:
Funcrefs cannot represent Lua functions. The following are errors:
let g:Myvar = v:lua.myfunc " Error
call SomeFunc(v:lua.mycallback) " Error
let g:foo = v:lua " Error
let g:foo = v:['lua'] " Error
Lua standard modules
The Nvim Lua "standard library" (stdlib) is the
vim module, which exposes
various functions and sub-modules. It is always loaded, thus require("vim")
is unnecessary.
You can peek at the module properties:
:lua vim.print(vim)
Result is something like this:
{
_os_proc_children = <function 1>,
_os_proc_info = <function 2>,
...
api = {
nvim__id = <function 5>,
nvim__id_array = <function 6>,
...
},
deepcopy = <function 106>,
gsplit = <function 107>,
...
}
To find documentation on e.g. the "deepcopy" function:
:help vim.deepcopy()
Note that underscore-prefixed functions (e.g. "_os_proc_children") are
internal/private and must not be used by plugins.
VIM.UV
vim.uv exposes the "luv" Lua bindings for the libUV library that Nvim uses
for networking, filesystem, and process management, see luvref.txt.
In particular, it allows interacting with the main Nvim luv-event-loop.
It is an error to directly invoke
vim.api functions (except api-fast) in
vim.uv callbacks. For example, this is an error:
local timer = vim.uv.new_timer()
timer:start(1000, 0, function()
vim.api.nvim_command('echomsg "test"')
end)
To avoid the error, schedule the callback:
local timer = vim.uv.new_timer()
timer:start(1000, 0, vim.schedule_wrap(function()
vim.api.nvim_command('echomsg "test"')
end))
(For one-shot timers, see vim.defer_fn(), which automatically adds the
wrapping.)
Example: repeating timer
Save this code to a file.
Execute it with ":luafile %".
-- Create a timer handle (implementation detail: uv_timer_t).
local timer = vim.uv.new_timer()
local i = 0
-- Waits 1000ms, then repeats every 750ms until timer:close().
timer:start(1000, 750, function()
print('timer invoked! i='..tostring(i))
if i > 4 then
timer:close() -- Always close handles to avoid leaks.
end
i = i + 1
end)
print('sleeping');Example: File-change detectionwatch-file
Save this code to a file.
Execute it with ":luafile %".
Use ":Watch %" to watch any file.
Try editing the file from another text editor.
Observe that the file reloads in Nvim (because on_change() calls
:checktime).
local w = vim.uv.new_fs_event()
local function on_change(err, fname, status)
-- Do work...
vim.api.nvim_command('checktime')
-- Debounce: stop/start.
w:stop()
watch_file(fname)
end
function watch_file(fname)
local fullpath = vim.api.nvim_call_function(
'fnamemodify', {fname, ':p'})
w:start(fullpath, {}, vim.schedule_wrap(function(...)
on_change(...) end))
end
vim.api.nvim_command(
"command! -nargs=1 Watch call luaeval('watch_file(_A)', expand('<args>'))")
When on Linux you may need to increase the maximum number of
inotify watches
and queued events as the default limit can be too low. To increase the limit,
run:sysctl fs.inotify.max_user_watches=494462
This will increase the limit to 494462 watches and queued events. These lines
can be added to
/etc/sysctl.conf to make the changes persistent.
Note that each watch is a structure in the Kernel, thus available memory is
also a bottleneck for using inotify. In fact, a watch can take up to 1KB of
space. This means a million watches could result in 1GB of extra RAM usage.
Example: TCP echo-servertcp-server
Save this code to a file.
Execute it with ":luafile %".
Note the port number.
Connect from any TCP client (e.g. "nc 0.0.0.0 36795"):
local function create_server(host, port, on_connect)
local server = vim.uv.new_tcp()
server:bind(host, port)
server:listen(128, function(err)
assert(not err, err) -- Check for errors.
local sock = vim.uv.new_tcp()
server:accept(sock) -- Accept client connection.
on_connect(sock) -- Start reading messages.
end)
return server
end
local server = create_server('0.0.0.0', 0, function(sock)
sock:read_start(function(err, chunk)
assert(not err, err) -- Check for errors.
if chunk then
sock:write(chunk) -- Echo received messages to the channel.
else -- EOF (stream closed).
sock:close() -- Always close handles to avoid leaks.
end
end)
end)
print('TCP echo-server listening on port: '..server:getsockname().port)Multithreadinglua-loop-threading
Plugins can perform work in separate (os-level) threads using the threading
APIs in luv, for instance
vim.uv.new_thread. Each thread has its own
separate Lua interpreter state, with no access to Lua globals on the main
thread. Neither can the editor state (buffers, windows, etc) be directly
accessed from threads.
A subset of the
vim.* stdlib is available in threads, including:
vim.uv with a separate event loop per thread.
vim.mpack and vim.json (useful for serializing messages between threads)
require in threads can use Lua packages from the global package.path
print() and vim.inspect
vim.text.diff
Most utility functions in
vim.* that work with pure Lua values, like
vim.split, vim.tbl_*, vim.list_*, etc.
vim.is_thread() returns true from a non-main thread.
VIM
Invokes Nvim API function
{func} with arguments {...}.
Example: call the "nvim_get_current_line()" API function:print(tostring(vim.api.nvim_get_current_line()))
vim.NILvim.NIL
Special value representing NIL in RPC and v:null in Vimscript
conversion, and similar cases. Lua nil cannot be used as part of a Lua
table representing a Dictionary or Array, because it is treated as
missing: {"foo", nil} is the same as {"foo"}.
vim.type_idxvim.type_idx
Type index for use in lua-special-tbl. Specifying one of the values from
vim.types allows typing the empty table (it is unclear whether empty Lua
table represents empty list or empty array) and forcing integral numbers
to be Float. See lua-special-tbl for more details.
vim.val_idxvim.val_idx
Value index for tables representing Floats. A table representing
floating-point value 1.0 looks like this:{
[vim.type_idx] = vim.types.float,
[vim.val_idx] = 1.0,
}
See also vim.type_idx and lua-special-tbl.
vim.typesvim.types
Table with possible values for vim.type_idx. Contains two sets of
key-value pairs: first maps possible values for vim.type_idx to
human-readable strings, second maps human-readable type names to values
for vim.type_idx. Currently contains pairs for float, array and
dictionary types.
Note: One must expect that values corresponding to
vim.types.float,
vim.types.array and vim.types.dictionary fall under only two following
assumptions:
Value may serve both as a key and as a value in a table. Given the
properties of Lua tables this basically means “value is not
nil”.
For each value in
vim.types table vim.types[vim.types[value]] is the
same as value.
No other restrictions are put on types, and it is not guaranteed that
values corresponding to vim.types.float, vim.types.array and
vim.types.dictionary will not change or that vim.types table will only
contain values for these three types.
Log levels are one of the values defined in
vim.log.levels:
vim.log.levels.DEBUG
vim.log.levels.ERROR
vim.log.levels.INFO
vim.log.levels.TRACE
vim.log.levels.WARN
vim.log.levels.OFF
vim.empty_dict()vim.empty_dict()
Creates a special empty table (marked with a metatable), which Nvim
converts to an empty dictionary when translating Lua values to Vimscript
or API types. Nvim by default converts an empty table {} without this
metatable to an list/array.
Note: If numeric keys are present in the table, Nvim ignores the metatable
marker and converts the dict to a list/array anyway.
Return:
(table)
The result is a String, which is the text
{str} converted from encoding
{from} to encoding {to}. When the conversion fails nil is returned. When
some characters could not be converted they are replaced with "?". The
encoding names are whatever the iconv() library function can accept, see
":Man 3 iconv".
Parameters:
{str} (string) Text to convert
{from} (string) Encoding of {str}
{to} (string) Target encoding
Return:
(string?) Converted string if conversion succeeds, nil otherwise.
vim.in_fast_event()vim.in_fast_event()
Returns true if the code is executing as part of a "fast" event handler,
where most of the API is disabled. These are low-level events (e.g.
lua-loop-callbacks) which can be invoked whenever Nvim polls for input.
When this is false most API functions are callable (but may be subject
to other restrictions such as textlock).
Sends
{event} to {channel} via RPC and returns immediately. If {channel}
is 0, the event is broadcast to all channels.
This function also works in a fast callback lua-loop-callbacks.
Parameters:
{channel} (integer)
{method} (string)
{...} (any?)
Note: Msgpack NIL values in the response are represented as vim.NIL.
Example: see nvim_exec_lua()
Parameters:
{channel} (integer)
{opts} (table?) Optional parameters (can be omitted):
timeout: (integer) Max milliseconds to wait for the
response, else raise an error.
{method} (string)
{...} (any?)
Overloads:
fun(channel: integer, method: string, ...: any): any
vim.schedule(
Schedules {fn})vim.schedule(){fn} to be invoked soon by the main event-loop. Useful to avoid
textlock or other temporary restrictions.
Parameters:
{fn} (fun())
Return (multiple):
(nil) result
(string?) err Error message if scheduling failed, nil otherwise.
Gets the distance (in bytes) from the last byte of the codepoint
(character) that
{index} points to.
Examples:
-- The character 'æ' is stored as the bytes '\xc3\xa6' (using UTF-8)
-- Returns 0 because the index is pointing at the last byte of a character
vim.str_utf_end('æ', 2)
-- Returns 1 because the index is pointing at the penultimate byte of a character
vim.str_utf_end('æ', 1)
Parameters:
{str} (string)
{index} (integer)
Return:
(integer)
vim.str_utf_pos(
Gets a list of the starting byte positions of each UTF-8 codepoint in the
given string.
{str})vim.str_utf_pos()
Embedded NUL bytes are treated as terminating the string.
Parameters:
{str} (string)
Return:
(integer[])
Gets the distance (in bytes) from the starting byte of the codepoint
(character) that
{index} points to.
The result can be added to
{index} to get the starting byte of a
character.
Examples:
-- The character 'æ' is stored as the bytes '\xc3\xa6' (using UTF-8)
-- Returns 0 because the index is pointing at the first byte of a character
vim.str_utf_start('æ', 1)
-- Returns -1 because the index is pointing at the second byte of a character
vim.str_utf_start('æ', 2)
Parameters:
{str} (string)
{index} (integer)
Return:
(integer)
Compares strings case-insensitively.
Parameters:
{a} (string)
{b} (string)
Return:
(0|1|-1) if strings are equal, {a} is greater than {b} or {a} is
lesser than {b}, respectively.
WARNING: This feature is experimental/unstable.
Subscribe to ui-events, similar to nvim_ui_attach() but receive events
in a Lua callback. Used to implement screen elements like popupmenu or
message handling in Lua.
{callback} receives event name plus additional parameters. See
ui-popupmenu and the sections below for event format for respective
events.
Callbacks for
msg_show events originating from internal messages (as
opposed to events from commands or API calls) are executed in api-fast
context; showing the message needs to be scheduled.
Excessive errors inside the callback will result in forced detachment.
WARNING: This api is considered experimental. Usability will vary for
different screen elements. In particular
ext_messages behavior is
subject to further changes and usability improvements. This is expected to
be used to handle messages when setting 'cmdheight' to zero (which is
likewise experimental).
Example (stub for a ui-popupmenu implementation):
ns = vim.api.nvim_create_namespace('my_fancy_pum')
vim.ui_attach(ns, {ext_popupmenu=true}, function(event, ...)
if event == 'popupmenu_show' then
local items, selected, row, col, grid = ...
print('display pum ', #items)
elseif event == 'popupmenu_select' then
local selected = ...
print('selected', selected)
elseif event == 'popupmenu_hide' then
print('FIN')
end
end)
Parameters:
{ns} (integer) Namespace ID
{opts} (table<string, any>) Optional parameters.
{callback} (fun(event: string, ...): any) Function called for each
UI event. A truthy return value signals to Nvim that the
event is handled, in which case it is not propagated to
remote UIs.
vim.ui_detach(
Detach a callback previously attached with vim.ui_attach() for the given
namespace {ns})vim.ui_detach(){ns}.
Parameters:
{ns} (integer) Namespace ID
LUA-VIMSCRIPT BRIDGE
Nvim Lua provides an interface or "bridge" to Vimscript variables and
functions, and editor commands and options.
Objects passed over this bridge are COPIED (marshalled): there are no
"references". lua-guide-variables For example, using
vim.fn.remove() on a
Lua list copies the list object to Vimscript and does NOT modify the Lua list:local list = { 1, 2, 3 }
vim.fn.remove(list, 0)
vim.print(list) --> "{ 1, 2, 3 }"
Invokes vim-function or user-function
{func} with arguments {...}.
See also vim.fn.
Equivalent to:vim.fn[func]({...})
vim.cmd(
{command})
See vim.cmd().
Invokes vim-function or user-function
{func} with arguments {...}.
To call autoload functions, use the syntax:vim.fn['some#function']({...})
Unlike vim.api.nvim_call_function() this converts directly between Vim
objects and Lua objects. If the Vim function returns a float, it will be
represented directly as a Lua number. Empty lists and dictionaries both
are represented by an empty table.
Note: vim.fn keys are generated lazily, thus
pairs(vim.fn) only
enumerates functions that were called at least once.
Note: The majority of functions cannot run in api-fast callbacks with some
undocumented exceptions which are allowed.
The Vim editor global dictionaries g: w: b: t: v: can be accessed
from Lua conveniently and idiomatically by referencing the
vim.* Lua tables
described below. In this way you can easily read and modify global Vimscript
variables from Lua.
Example:
vim.g.foo = 5 -- Set the g:foo Vimscript variable.
print(vim.g.foo) -- Get and print the g:foo Vimscript variable.
vim.g.foo = nil -- Delete (:unlet) the Vimscript variable.
vim.b[2].foo = 6 -- Set b:foo for buffer 2
Note that setting dictionary fields directly will not write them back into
Nvim. This is because the index into the namespace simply returns a copy.
Instead the whole dictionary must be written as one. This can be achieved by
creating a short-lived temporary.
Example:
vim.g.my_dict.field1 = 'value' -- Does not work
local my_dict = vim.g.my_dict --
my_dict.field1 = 'value' -- Instead do
vim.g.my_dict = my_dict --
vim.gvim.g
Global (g:) editor variables.
Key with no value returns nil.
vim.bvim.b
Buffer-scoped (b:) variables for the current buffer.
Invalid or unset key returns nil. Can be indexed with
an integer to access variables for a specific buffer.
vim.wvim.w
Window-scoped (w:) variables for the current window.
Invalid or unset key returns nil. Can be indexed with
an integer to access variables for a specific window.
vim.tvim.t
Tabpage-scoped (t:) variables for the current tabpage.
Invalid or unset key returns nil. Can be indexed with
an integer to access variables for a specific tabpage.
Examples:
To set a boolean toggle:
Vimscript:
set number
Lua: vim.o.number = true
To set a string value:
Vimscript:
set wildignore=*.o,*.a,__pycache__
Lua: vim.o.wildignore = '*.o,*.a,__pycache__'
Lua (alt): vim.o.wildignore = { '*.o', '*.a', '__pycache__' }
To set a key:value type option:
Vimscript:
set listchars=eol:~,space:-
Lua: vim.o.listchars = 'eol:~,space:-'
Lua (alt): vim.o.listchars = { eol = '~', space = '-' }
Similarly, there is vim.bo and vim.wo for setting buffer-scoped and
window-scoped options. Note that this must NOT be confused with
local-options and :setlocal. There is also vim.go that only accesses the
global value of a global-local option, see :setglobal.
A special interface vim.opt exists for conveniently interacting with list-
and map-style options from Lua: It allows accessing them as Lua tables and
offers object-oriented method for adding and removing entries.
Examples:
The following methods of setting a list-style option are equivalent:
In Vimscript:
set wildignore=*.o,*.a,__pycache__
In Lua using
vim.o:vim.o.wildignore = '*.o,*.a,__pycache__'
In Lua using
vim.opt:vim.opt.wildignore = { '*.o', '*.a', '__pycache__' }
To replicate the behavior of :set+=, use:
vim.opt.wildignore:append { "*.pyc", "node_modules" }
To replicate the behavior of :set^=, use:
vim.opt.wildignore:prepend { "new_first_value" }
To replicate the behavior of :set-=, use:
vim.opt.wildignore:remove { "node_modules" }
The following methods of setting a map-style option are equivalent:
In Vimscript:
set listchars=space:_,tab:>~
In Lua using
vim.o:vim.o.listchars = 'space:_,tab:>~'
In Lua using
vim.opt:vim.opt.listchars = { space = '_', tab = '>~' }
Note that vim.opt returns an
Option object, not the value of the option,
which is accessed through vim.opt:get():
Examples:
The following methods of getting a list-style option are equivalent:
In Vimscript:
echo wildignore
In Lua using
vim.o:print(vim.o.wildignore)
In Lua using
vim.opt:vim.print(vim.opt.wildignore:get())
In any of the above examples, to replicate the behavior :setlocal, use
vim.opt_local. Additionally, to replicate the behavior of :setglobal, use
vim.opt_global.
Option:append(
Append a value to string-style options. See :set+=
{value})vim.opt:append()
These are equivalent:
vim.opt.formatoptions:append('j')
vim.opt.formatoptions = vim.opt.formatoptions + 'j'
Parameters:
{value} (string) Value to append
Option:get()vim.opt:get()
Returns a Lua-representation of the option. Boolean, number and string
values will be returned in exactly the same fashion.
For values that are comma-separated lists, an array will be returned with
the values as entries in the array:
vim.cmd [[set wildignore=*.pyc,*.o]]
vim.print(vim.opt.wildignore:get())
-- { "*.pyc", "*.o", }
for _, ignore_pattern in ipairs(vim.opt.wildignore:get()) do
print("Will ignore:", ignore_pattern)
end
-- Will ignore: *.pyc
-- Will ignore: *.o
For values that are comma-separated maps, a table will be returned with
the names as keys and the values as entries:
vim.cmd [[set listchars=space:_,tab:>~]]
vim.print(vim.opt.listchars:get())
-- { space = "_", tab = ">~", }
for char, representation in pairs(vim.opt.listchars:get()) do
print(char, "=>", representation)
end
For values that are lists of flags, a set will be returned with the flags
as keys and
true as entries.vim.cmd [[set formatoptions=njtcroql]]
vim.print(vim.opt.formatoptions:get())
-- { n = true, j = true, c = true, ... }
local format_opts = vim.opt.formatoptions:get()
if format_opts.j then
print("J is enabled!")
end
Return:
(string|integer|boolean|string[]|table<string,string|boolean>?)
value of option
Option:prepend(
Prepend a value to string-style options. See :set^=
{value})vim.opt:prepend()
These are equivalent:
vim.opt.wildignore:prepend('*.o')
vim.opt.wildignore = vim.opt.wildignore ^ '*.o'
Parameters:
{value} (string) Value to prepend
Option:remove(
Remove a value from string-style options. See :set-=
{value})vim.opt:remove()
These are equivalent:
vim.opt.wildignore:remove('*.pyc')
vim.opt.wildignore = vim.opt.wildignore - '*.pyc'
Parameters:
{value} (string) Value to remove
vim.bo[
Gets or sets buffer-scoped options on buffer {bufnr}]vim.bo{bufnr} (or "current
buffer" if 0 or omitted). Like :setlocal. Invalid {bufnr} or key is an
error.
Example:
local bufnr = vim.api.nvim_get_current_buf()
vim.bo[bufnr].buflisted = true -- same as vim.bo.buflisted = true
print(vim.bo.comments)
print(vim.bo.baz) -- error: invalid key
vim.envvim.env
Gets or sets environment variables in the current editor process. See
expand-env and :let-environment for the Vimscript behavior. Invalid or
unset key returns nil.
Example:
vim.env.FOO = 'bar'
print(vim.env.TERM)
Note: unlike vim.o, this accesses the global option value and thus is
mostly useful with global-local options.
Example:
vim.go.cmdheight = 4
print(vim.go.columns)
print(vim.go.bar) -- error: invalid key
vim.ovim.o
Gets or sets options. Works like :set, so buffer/window-scoped options
target the current buffer/window. Invalid key is an error.
Example:
vim.o.cmdheight = 4
print(vim.o.columns)
print(vim.o.foo) -- error: invalid key
Gets or sets window-scoped options on window
{winid} (or "current
window" if 0 or omitted) and buffer {bufnr} (0 for current buffer). Like
:setlocal if setting a global-local option or if {bufnr} is specified,
like :set otherwise. Invalid {winid}, {bufnr}, or key is an error.
Note: only bufnr=0 (current window-buffer) is supported, currently.
Example:
local winid = vim.api.nvim_get_current_win()
vim.wo[winid].number = true -- same as vim.wo.number = true
print(vim.wo.foldmarker)
print(vim.wo.quux) -- error: invalid key
vim.wo[winid][0].spell = false -- like ':setlocal nospell'
Lua module: vim
vim.Ringbufvim.Ringbuf
Fields:
Ringbuf:clear()Ringbuf:clear()
Clear all items
Ringbuf:peek()Ringbuf:peek()
Returns the first unread item without removing it
Return:
(T?)
Ringbuf:pop()Ringbuf:pop()
Removes and returns the first unread item
Return:
(T?)
Ringbuf:push(
Adds an item, overriding the oldest item if the buffer is full.
{item})Ringbuf:push()Parameters:
{item} (T)
vim.cmd(
Executes Vimscript (Ex-commands).
{cmd})vim.cmd()
Can be indexed with a command name to get a function, thus you can write
vim.cmd.echo(…) instead of vim.cmd{cmd='echo',…}.
Examples:
-- Single command:
vim.cmd('echo 42')
-- Multiline script:
vim.cmd([[
augroup my.group
autocmd!
autocmd FileType c setlocal cindent
augroup END
]])
-- Ex command :echo "foo". Note: string literals must be double-quoted.
vim.cmd('echo "foo"')
vim.cmd { cmd = 'echo', args = { '"foo"' } }
vim.cmd.echo({ args = { '"foo"' } })
vim.cmd.echo('"foo"')
-- Ex command :write! myfile.txt
vim.cmd('write! myfile.txt')
vim.cmd { cmd = 'write', args = { 'myfile.txt' }, bang = true }
vim.cmd.write { args = { 'myfile.txt' }, bang = true }
vim.cmd.write { 'myfile.txt', bang = true }
-- Ex command :vertical resize +2
vim.cmd.resize({ '+2', mods = { vertical = true } })
-- Pass arg literally, without needing to escape special chars:
vim.cmd.edit({ '%foo"|bar#baz"', magic = { file = false, bar = false } })
Parameters:
{cmd} (string|table) Command(s) to execute.
The string form supports multiline Vimscript (alias to
nvim_exec2(), behaves like :source).
The table form executes a single command (alias to
nvim_cmd()).
See also:
Deep compare values for equality
Tables are compared recursively unless they both provide the
eq
metamethod. All other types are compared using the equality == operator.
Cyclic tables are supported.
Parameters:
{a} (any) First value
{b} (any) Second value
Return:
(boolean) true if values are equals, else false
Returns a deep copy of the given object. Non-table objects are copied as
in a typical Lua assignment, whereas table objects are copied recursively.
Functions are naively copied, so functions in the copied table point to
the same functions as those in the input table. Userdata and threads are
not copied and will throw an error.
Note:
noref=true is much more performant on tables with unique table
fields, while noref=false is more performant on tables that reuse table
fields.
Parameters:
{orig} (table) Table to copy
{noref} (boolean?) When false (default) a contained table is only
copied once and all references point to this single copy.
When true every occurrence of a table results in a new
copy. This also means that a cyclic reference can cause
deepcopy() to fail.
Return:
(table) Table of copied keys and (nested) values.
vim.defaulttable(
Creates a table whose missing keys are provided by {createfn})vim.defaulttable(){createfn} (like
Python's "defaultdict").
If
{createfn} is nil it defaults to defaulttable() itself, so accessing
nested keys creates nested tables:local a = vim.defaulttable()
a.b.c = 1
Parameters:
{createfn} (fun(key:any):any?) Provides the value for a missing
key.
Return:
(table) Empty table with __index metamethod.
Use to do a one-shot timer that calls
{fn}. Note: The {fn} is scheduled
automatically, so API functions are safe to call.
Parameters:
{fn} (function) Callback to call once timeout expires
{timeout} (integer) Number of milliseconds to wait before calling
fn
Return:
(uv.uv_timer_t) timer luv timer object
Shows a deprecation message to the user.
Parameters:
{name} (string) Deprecated feature (function, API, etc.).
{alternative} (string?) Suggested alternative feature.
{version} (string) Version when the deprecated function will be
removed.
{plugin} (string?) Name of the plugin that owns the deprecated
feature. Defaults to "Nvim".
{backtrace} (boolean?) Prints backtrace. Defaults to true.
Return:
(string?) Deprecation message, or nil if no message was shown.
Parameters:
{s} (string) String
{suffix} (string) Suffix to match
Return:
(boolean) true if suffix is a suffix of s
Gets an iterator that splits a string at each instance of a separator,
in "lazy" fashion (as opposed to vim.split() which is "eager").
Example:
for s in vim.gsplit(':aa::b:', ':', {plain=true}) do
print(s)
end
If you want to also inspect the separator itself (instead of discarding
it), use string.gmatch(). Example:
for word, num in ('foo111bar222'):gmatch('([^0-9]*)(%d*)') do
print(('word: %s num: %s'):format(word, num))
end
Parameters:
{s} (string) String to split
{sep} (string) Separator or pattern
{plain}? (boolean) Use sep literally (as in
string.find).
{trimempty}? (boolean) Discard empty segments at start and
end of the sequence.
Return:
(fun():string?) Iterator over the split components
See also:
Gets a human-readable representation of the given object.
Parameters:
{root} (any)
{options} (table?) A table with the following fields:
{depth}? (integer, default: unlimited) Maximum table
nesting depth. Deeper tables are shown as {...}.
{indent}? (string, default: " ") String repeated for
each level of indentation.
{newline}? (string, default: "\n") String used for
line breaks.
{process}? (fun(item: any, path: any[]): any)
Transforms values, keys, and metatables before
formatting. Return a replacement value, or nil to omit
a table entry. {path} lists the keys leading to {item},
with vim.inspect.KEY appended for keys or
vim.inspect.METATABLE for metatables. The root has an
empty path.
Return:
(string)
vim.is_callable(
Returns true if object {f})vim.is_callable()f can be called as a function.
Parameters:
{f} (any?) Any object
Return:
(boolean) true if f is callable, else false
vim.isarray(
Tests if {t})vim.isarray()t is an "array": a table indexed only by integers (potentially
non-contiguous).
If the indexes start from 1 and are contiguous then the array is also a
list. vim.islist()
Empty table
{} is an array, unless it was created by vim.empty_dict()
or returned as a dict-like API or Vimscript result, for example from
vim.rpcrequest() or vim.fn.
Parameters:
{t} (any?)
Return:
(boolean) true if array-like table, else false.
vim.islist(
Tests if {t})vim.islist()t is a "list": a table indexed only by contiguous integers
starting from 1 (what lua-length calls a "regular array").
Empty table
{} is a list, unless it was created by vim.empty_dict() or
returned as a dict-like API or Vimscript result, for example from
vim.rpcrequest() or vim.fn.
Parameters:
{t} (any?)
Return:
(boolean) true if list-like table, else false.
See also:
Attributes:
Since: 0.13.0
Parameters:
{t} (any?)
Converts keys from key-notation to the internal encoding. Optionally
returns structured key-chord info as retval 2.
Inverse of keytrans(), which converts the internal encoding back to
key-notation.
Examples:
local k = vim.keycode
vim.g.mapleader = k'<bs>'
-- Split a key sequence into chords, e.g. to inspect modifiers.
local _, chords = vim.keycode('<C-w>v', true)
assert(chords[1].key == 'w' and chords[1].mod[1] == 'C')
-- keytrans() is the inverse: internal encoding => key-notation.
assert(vim.fn.keytrans(vim.keycode('<C-a>')) == '<C-A>')
Return (multiple):
(string) Internal representation of the given keys.
(table?) List of parsed key-chords, each with fields:
{key} (string) Key without modifiers. Example: <C-A> has
key="a".
{key_alt} (string?) Alternative spelling of key, or nil if There
Is No Alternative (TINA). Example: "<" has key_alt="lt".
{keys} (string) Full key-chord in canonical key-notation (as
produced by keytrans()), including modifiers. Example: <A-f> has
keys="<M-f>".
{mod} (('M'|'T'|'C'|'S'|'2'|'3'|'4'|'D')[]) List of key-chord
modifiers. Example: <C-S-f> has mod={ 'C', 'S' }.
Search for a position in a sorted lua-list
{t} where {val} can be
inserted while keeping the list sorted.
Use
{bound} to determine whether to return the first or the last position,
defaults to "lower", i.e., the first position.
With
{opts.key}, {val} may differ from the list elements, provided the key
function accepts both. For a string key, that field must exist on both. A
partial record is sufficient if it contains all fields used by the key.
NOTE: The values being compared must support
<, and the list must be
sorted by those values (after applying {opts.key}, if provided).
Example:
local t = { 1, 2, 2, 3, 3, 3 }
local first = vim.list.bisect(t, 3)
-- `first` is `val`'s first index if found,
-- useful for existence checks.
print(t[first]) -- 3
local last = vim.list.bisect(t, 3, { bound = 'upper' })
-- Note that `last` is 7, not 6,
-- this is suitable for insertion.
table.insert(t, last, 4)
-- t is now { 1, 2, 2, 3, 3, 3, 4 }
-- You can use lower bound and upper bound together
-- to obtain the range of occurrences of `val`.
-- 3 is in [first, last)
for i = first, last - 1 do
print(t[i]) -- { 3, 3, 3 }
end
Attributes:
Since: 0.12.0
Parameters:
{t} (any[]) A sorted list.
{val} (any) The value to search.
{opts} (table?) A table with the following fields:
{bound}? ('lower'|'upper', default: 'lower') Specifies
the search variant.
"lower": returns the first position where inserting
{val}
keeps the list sorted.
"upper": returns the last position where inserting
{val}
keeps the list sorted..
{hi}? (integer, default: #t + 1) End index of the list,
exclusive.
{key}? ((string & keyof T)|fun(val: T): any) Applied to
{val} and the list elements being compared. If a string,
index both by this field name. If a function, it must accept
both {val} and the list elements and return mutually
comparable keys.
{lo}? (integer, default: 1) Start index of the list.
Overloads:
fun<T, Q>(t: T[], val: Q, opts: vim.list.bisect.Opts<T|Q> & { key: fun(val: T|Q): any }): integer
fun<T: table, Q: table>(t: T[], val: Q, opts: vim.list.bisect.Opts<T|Q> & { key: string & keyof T & keyof Q }): integer
Return:
(integer) index serves as either the lower bound or the upper bound
position.
Removes duplicate values from a lua-list in-place.
Only the first occurrence of each value is kept. The operation is
performed in-place and the input table is modified.
Accepts an optional
key argument, which if provided is called for each
value in the list to compute a hash key for uniqueness comparison. If
key is a string, it is used as the field name to index each value. This
is useful for deduplicating table values or complex objects. If key
returns nil for a value, that value will be considered unique, even if
multiple values return nil.
Example:
local t = {1, 2, 2, 3, 1}
vim.list.unique(t)
-- t is now {1, 2, 3}
local t = { {id=1}, {id=2}, {id=1} }
vim.list.unique(t, 'id')
-- t is now { {id=1}, {id=2} }
Attributes:
Since: 0.12.0
Parameters:
{t} (any[])
{key} (string|fun(x: T): any?) Optional field name or hash function
to determine uniqueness of values
Return:
(any[]) The deduplicated list
See also:
Checks if a list-like table (integer keys without gaps) contains
value.
Parameters:
{t} (table) Table to check (must be list-like, not validated)
{value} (any) Value to compare
Return:
(boolean) true if t contains value
See also:
vim.tbl_contains() for checking values in general tables
Extends a list-like table with the values of another list-like table.
NOTE: This mutates dst!
Parameters:
{dst} (table) List which will be modified and appended to
{src} (table) List from which values will be inserted
{start} (integer?) (default: 1) Start index on src.
{finish} (integer?) (default: #src) Final index on src.
Return:
(table) dst
See also:
Creates a copy of a table containing only elements from start to end
(inclusive)
Parameters:
{list} (any[]) Table
{start} (integer?) Start range of slice
{finish} (integer?) End range of slice
Return:
(any[]) Copy of table sliced from start to finish (inclusive)
vim.lua_omnifunc(
Omnifunc for completing Lua values from the runtime Lua interpreter,
similar to the builtin completion for the {find_start})vim.lua_omnifunc():lua command.
Activate using
vim.bo.omnifunc = vim.lua_omnifunc in a Lua buffer.
Parameters:
{find_start} (1|0)
vim.nonnil(
Returns the first argument which is not nil.
{...})vim.nonnil()
If all arguments are nil, returns nil.
Example:
local a = nil
local b = nil
local c = 42
local d = true
assert(vim.nonnil(a, b, c, d) == 42)
Attributes:
Since: 0.13.0
Parameters:
{...} (any)
Return:
(any)
Displays a notification to the user.
This function can be overridden by plugins to display notifications using
a custom provider (such as the system notification provider). By default,
writes to :messages.
Parameters:
{msg} (string) Content of the notification to show to the user.
{opts} (table?) Optional parameters. Unused by default.
Displays a notification only one time.
Like vim.notify(), but subsequent calls with the same message will not
display a notification.
Parameters:
{msg} (string) Content of the notification to show to the user.
{opts} (table?) Optional parameters. Unused by default.
Return:
(boolean) true if message was displayed, else false
Attributes:
Since: 0.13.0
Parameters:
{fn} (fun(...):T)
{...} (any?)
Return:
(any) ...
Registers function
{fn} with namespace {ns_id} as a listener to EVERY
input key (except keys consumed by getchar(), by {fn} itself, or by a
<Cmd> payload).
To parse key-chords, see vim.keycode(). Example:
local keychords = vim.keycode(vim.fn.keytrans(key), true)
Note:
If
{fn} returns an empty string, {key} is discarded/ignored; if {key}
is <Cmd> then the "<Cmd>…<CR>" sequence is discarded as a whole.
Non-recursive: if
{fn} itself consumes input, it won't be invoked for
those keys.
Not invoked for keys consumed by getchar()/getcharstr(): they never
reach the main loop.
To UNregister a given
{ns_id}, pass nil {fn}.
{fn} will be removed on error.
{fn} will not be cleared by nvim_buf_clear_namespace()
The -w command-line option is related but does not support callbacks
and cannot be toggled dynamically.
Parameters:
{fn} (fun(key: string, typed: string): string??) Function
invoked for every input key, after mappings have been applied
but before further processing. Arguments {key} and {typed}
are raw input (use keytrans() to get keycodes).
{key} is the key after mappings are applied.
{typed} is the input before mappings are applied; may be
empty if {key} was produced by non-typed key(s) or by the
same typed key(s) that produced a previous {key}.
{opts} (table?) Optional parameters
Return:
(integer) Namespace id associated with {fn}. Or count of all
callbacks if on_key() is called without arguments.
Paste handler, invoked by nvim_paste().
Note: This is provided only as a "hook", don't call it directly; call
nvim_paste() instead, which arranges redo (dot-repeat) and invokes
vim.paste.
Example: To remove ANSI color codes when pasting:
vim.paste = (function(overridden)
return function(lines, phase)
for i,line in ipairs(lines) do
-- Scrub ANSI color codes from paste input.
lines[i] = line:gsub('\27%[[0-9;mK]+', '')
end
return overridden(lines, phase)
end
end)(vim.paste)
Parameters:
{phase} (-1|1|2|3) -1: "non-streaming" paste: the call contains all
lines. If paste is "streamed", phase indicates the stream
state:
1: starts the paste (exactly once)
2: continues the paste (zero or more times)
3: ends the paste (exactly once)
Return:
(boolean) result false if client should cancel the paste.
See also:
vim.pesc(
Escapes magic chars in lua-patterns.
{s})vim.pesc()Parameters:
{s} (string) String to escape
Return:
(string) %-escaped pattern string
See also:
vim.print(
"Pretty prints" the given arguments and returns them unmodified.
{...})vim.print()
Example:
local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' }))
Parameters:
{...} (any)
Return:
(any) given arguments.
vim.ringbuf(
Create a ring buffer limited to a maximal number of items. Once the buffer
is full, adding a new entry overrides the oldest entry.{size})vim.ringbuf()local ringbuf = vim.ringbuf(4)
ringbuf:push("a")
ringbuf:push("b")
ringbuf:push("c")
ringbuf:push("d")
ringbuf:push("e") -- overrides "a"
print(ringbuf:pop()) -- returns "b"
print(ringbuf:pop()) -- returns "c"
-- Can be used as iterator. Pops remaining items:
for val in ringbuf do
print(val)
end
Returns a Ringbuf instance with the following methods:
Parameters:
{size} (integer)
Return:
(vim.Ringbuf<any>) ringbuf
The returned function passes all arguments to
{fn}.
Example:
function notify_readable(_err, readable)
vim.notify("readable? " .. tostring(readable))
end
vim.uv.fs_access(vim.fn.stdpath("config"), "R", vim.schedule_wrap(notify_readable))
Parameters:
{fn} (function)
Return:
(function)
vim.spairs(
Enumerates key-value pairs of a table, ordered by key.
{t})vim.spairs()Parameters:
{t} (table) Dict-like table
Return (multiple):
(fun(table: table<K, V>, index?: K):K, V) for-in iterator over
sorted keys and their values
(table)
See also:
Splits a string at each instance of a separator and returns the result as
a table (unlike vim.gsplit()).
Examples:
split(":aa::b:", ":") --> {'','aa','','b',''}
split("axaby", "ab?") --> {'','x','y'}
split("x*yz*o", "*", {plain=true}) --> {'x','yz','o'}
split("|x|y|z|", "|", {trimempty=true}) --> {'x', 'y', 'z'}
Parameters:
{s} (string) String to split
{sep} (string) Separator or pattern
{plain}? (boolean) Use sep literally (as in
string.find).
{trimempty}? (boolean) Discard empty segments at start and
end of the sequence.
Return:
(string[]) List of split components
Parameters:
{s} (string) String
{prefix} (string) Prefix to match
Return:
(boolean) true if prefix is a prefix of s
Convert UTF-32, UTF-16 or UTF-8
{index} to byte index. If
{strict_indexing} is false then an out of range index will return byte
length instead of throwing an error.
Use
"utf-32" to convert Unicode code-point indices to byte indices.
"utf-8" is Nvim's native string encoding, so this function is idempotent
for that encoding: {index} is already a byte index and is returned
unchanged.
Invalid UTF-8 and NUL is treated like in vim.str_utfindex(). An
{index}
in the middle of a UTF-16 sequence is rounded upwards to the end of that
sequence.
Parameters:
{s} (string)
{encoding} ("utf-8"|"utf-16"|"utf-32")
{index} (integer)
{strict_indexing} (boolean?) default: true
Return:
(integer)
Convert byte index to UTF-32, UTF-16 or UTF-8 indices. If
{index} is not
supplied, the length of the string is used. All indices are zero-based.
If
{strict_indexing} is false then an out of range index will return
string length instead of throwing an error. Invalid UTF-8 bytes, and
embedded surrogates are counted as one code point each. An {index} in the
middle of a UTF-8 sequence is rounded upwards to the end of that sequence.
Parameters:
{s} (string)
{encoding} ("utf-8"|"utf-16"|"utf-32")
{index} (integer?)
{strict_indexing} (boolean?) default: true
Return:
(integer)
Checks if a table contains a given value, specified either directly or via
a predicate that is checked for each value.
Example:
vim.tbl_contains({ 'a', { 'b', 'c' } }, function(v)
return vim.deep_equal(v, { 'b', 'c' })
end, { predicate = true })
-- true
Parameters:
{t} (table) Table to check
{value} (any) Value to compare or predicate function reference
{predicate}? (boolean, default: false) value is a
function reference to be checked
Return:
(boolean) true if t contains value
See also:
vim.list_contains() for checking values in list-like tables
vim.tbl_count(
Counts the number of non-nil values in table {t})vim.tbl_count()t.vim.tbl_count({ a=1, b=2 }) --> 2
vim.tbl_count({ 1, 2 }) --> 2
Parameters:
{t} (table) Table
Return:
(integer) Number of non-nil values in table
Merges two or more tables recursively.
Only lua-dict tables are merged recursively; lua-list tables are
treated as opaque values (overwritten instead of merged). That is
convenient for merging default/user configurations where lists typically
should not be merged together.
Example:
-- Set `config.settings.…` without worrying about whether intermediate dicts exist.
local config = { settings = { tailwindCSS = { foo = 'bar' } } }
local merged = vim.tbl_deep_extend('force',
config,
{ settings = { tailwindCSS = { experimental = { configFile = '/my/config.json' } } } }
)
vim.print(merged)
Parameters:
{behavior} ('error'|'keep'|'force'|fun(key:any, prev_value:any?, value:any): any)
Decides what to do if a key is found in more than one map:
"error": raise an error
"force": use value from the rightmost map
"keep": use value from the leftmost map
If a function, it receives the current key, the previous
value in the currently merged table (if present), the
current value and should return the value for the given
key in the merged table.
{...} (table) Two or more tables
Return:
(table) Merged table
See also:
Merges two or more tables.
Parameters:
{behavior} ('error'|'keep'|'force'|fun(key:any, prev_value:any?, value:any): any)
Decides what to do if a key is found in more than one map:
"error": raise an error
"force": use value from the rightmost map
"keep": use value from the leftmost map
If a function, it receives the current key, the previous
value in the currently merged table (if present), the
current value and should return the value for the given
key in the merged table.
{...} (table) Two or more tables
Return:
(table) Merged table
See also:
Filter a table using a predicate function
Parameters:
{fn} (function) Function
{t} (table) Table
Return:
(any[]) Table of filtered values
Gets a (nested) value from table
o given by a sequence of keys ..., or
nil if not found.
Note: To set deeply nested keys, see vim.tbl_deep_extend().
Example:
local o = { a = { b = true } }
-- Get `o.a.b`.
vim.print(vim.tbl_get(o, 'a', 'b')) -- true
o.a = {}
vim.print(vim.tbl_get(o, 'a', 'b')) -- nil
Parameters:
{o} (table) Table to index
{...} (any) Optional keys (0 or more, variadic) via which to index
the table
Return:
(any) Nested value indexed by key (if it exists), else nil
vim.tbl_isempty(
Checks if a table is empty.
{t})vim.tbl_isempty()Parameters:
{t} (table) Table to check
Return:
(boolean) true if t is empty
vim.tbl_keys(
Return a list of all keys used in a table. However, the order of the
return table of keys is not guaranteed.
{t})vim.tbl_keys()Parameters:
{t} (table) Table
Return:
(any[]) List of keys
Applies function
fn to all values of table t, in pairs() iteration
order (which is not guaranteed to be stable, even when the data doesn't
change).
Parameters:
{fn} (fun(value: T): R) Function
{t} (table<any, T>) Table
Return:
(table<any, R>) Table of transformed values
vim.tbl_values(
Return a list of all values used in a table. However, the order of the
return table of values is not guaranteed.
{t})vim.tbl_values()Parameters:
{t} (table) Table
Return:
(any[]) List of values
vim.trim(
Trim whitespace (Lua pattern "%s") from both sides of a string.
{s})vim.trim()Parameters:
{s} (string) String to trim
Return:
(string) String with whitespace removed from its beginning and end
Validate function arguments.
This function has two valid forms:
vim.validate(name, value, validator[, optional][, message])
Validates that argument {name} with value {value} satisfies
{validator}. If {optional} is given and is true, then {value} may be
nil. If {message} is given, then it is used as the expected type in
the error message.
Example: function vim.startswith(s, prefix)
vim.validate('s', s, 'string')
vim.validate('prefix', prefix, 'string')
-- ...
end
vim.validate(spec) (DEPRECATED) where spec is of type
table<string,[value:any, validator: vim.validate.Validator, optional_or_msg? : boolean|string]>)
Validates a argument specification. Specs are evaluated in alphanumeric
order, until the first failure.
Examples:
vim.validate('arg1', {'foo'}, 'table')
--> NOP (success)
vim.validate('arg2', 'foo', 'string')
--> NOP (success)
vim.validate('arg1', 1, 'table')
--> error('arg1: expected table, got number')
vim.validate('arg1', 3, function(a) return (a % 2) == 0 end, 'even number')
--> error('arg1: expected even number, got 3')
-- If multiple types are valid they can be given as a list:
vim.validate('arg1', {'foo'}, {'table', 'string'})
vim.validate('arg2', 'foo', {'table', 'string'})
-- NOP (success)
vim.validate('arg1', 1, {'string', 'table'})
-- error('arg1: expected string|table, got number')
Note:
validator set to a value returned by lua-type() provides the best
performance.
Parameters:
{name} (string) Argument name
{value} (any) Argument value
{validator} (vim.validate.Validator)
(
string|string[]): Any value that can be returned
from lua-type() in addition to 'callable':
'boolean', 'callable', 'function', 'nil',
'number', 'string', 'table', 'thread',
'userdata'.
(
fun(val:any): boolean, string?) A function that
returns a boolean and an optional string message.
{optional} (boolean?) (default: false) Parameter is optional (may
be omitted or nil)
{message} (string?) message when validation fails
Overloads:
fun(name: string, val: any, validator: vim.validate.Validator, message: string)
fun(spec: table<string,[any, vim.validate.Validator, boolean|string]>)
Waits up to
time milliseconds, until callback returns true
(success). Executes callback immediately, then on user events, internal
events, and approximately every interval milliseconds. Returns true
plus any remaining callback results on success.
Nvim processes other events while waiting. Cannot be called during an
api-fast event.
Examples:
-- Wait for 100 ms, allowing other events to process.
vim.wait(100)
-- Wait up to 1000 ms or until `vim.g.foo` is true, at intervals of ~500 ms.
vim.wait(1000, function() return vim.g.foo end, 500)
-- Wait indefinitely until `vim.g.foo` is true, and get the callback results.
local ok, rv1, rv2, rv3 = vim.wait(math.huge, function()
return vim.g.foo, 'a', 42, { ok = { 'yes' } }
end)
-- Schedule a function to set a value in 100ms. This would wait 10s if blocked, but actually
-- only waits 100ms because `vim.wait` processes other events while waiting.
vim.defer_fn(function() vim.g.timer_result = true end, 100)
if vim.wait(10000, function() return vim.g.timer_result end) then
print('Only waiting a little bit of time!')
end
-- Yield via vim.wait() to allow CTRL-C to interrupt Lua code.
while true do
-- ...work...
local _, code = vim.wait(0, nil, 0)
if code == -2 then -- CTRL-C.
break
end
end
Parameters:
{time} (number) Number of milliseconds to wait. Must be
non-negative number, any fractional part is truncated.
{callback} (fun(): boolean, ...?) Optional callback. Waits until
{callback} returns true
{interval} (integer?) (default: 200) Milliseconds (approximate) to
wait between polls.
Return (multiple):
(boolean)
(-1|-2?)
If callback returns
true before timeout: true, ... (remaining
callback results).
On timeout:
false, -1
On interrupt:
false, -2
On error: the error is raised.
Lua module: vim.inspector
vim.inspect_pos.ExtmarkItemvim.inspect_pos.ExtmarkItem
Extends: vim.inspect_pos.Item
opts.hl_group_link is deprecated; use the top-level hl_group_link
field.
Fields:
{id} (integer) extmark id
{ns} (string) namespace name
{ns_id} (integer) namespace id
{opts} (vim.api.keyset.extmark_details & { hl_group_link?: string })
raw extmark details from nvim_buf_get_extmarks().
vim.inspect_pos.Itemvim.inspect_pos.Item
Fields:
{col} (integer) start byte column (0-based)
{end_col} (integer) end byte column (0-based, exclusive)
{end_row} (integer) end row (0-based)
{hl_group}? (string) highlight group name, if any
{hl_group_link}? (string) resolved highlight group (after following
links), if any
{row} (integer) start row (0-based)
vim.inspect_pos.SyntaxItemvim.inspect_pos.SyntaxItem
Extends: vim.inspect_pos.Item
Fields:
{hl_group} (string) highlight group name
{hl_group_link} (string) resolved highlight group (after following
links)
vim.inspect_pos.TSItemvim.inspect_pos.TSItem
Extends: vim.treesitter.CaptureInfo
Fields:
{hl_group} (string) highlight group name
{hl_group_link} (string) resolved highlight group (after following
links)
Get all the items at a given buffer position.
Can also be pretty-printed with
:Inspect!.:Inspect!
When
end_row and end_col are given in the opts table, items
overlapping the range (row, col) to (end_row, end_col) are returned
instead of only those at a single position. end_col is exclusive
(past-the-end). Empty ranges return no items.
Attributes:
Since: 0.9.0
Parameters:
{buf} (integer?) defaults to the current buffer
{row} (integer?) row to inspect, 0-based. Defaults to the row of
the current cursor
{col} (integer?) col to inspect, 0-based. Defaults to the col of
the current cursor
{opts} (table?) A table with the following fields:
{end_col}? (integer, default: nil, single position) End
column (0-based, exclusive) for range inspection.
{end_row}? (integer, default: nil, single position) End
row (0-based) for range inspection. Must be specified
together with end_col; items overlapping the range from
(row, col) to (end_row, end_col) are returned.
{extmarks}? (boolean|"all", default: true) Include extmark
highlights. When all, also include point marks and
extmarks without a hl_group.
{semantic_tokens}? (boolean, default: true) Include
semantic token highlights.
{syntax}? (boolean, default: true) Include syntax based
highlight groups.
{treesitter}? (boolean, default: true) Include
treesitter based highlight groups.
Return:
(table) Items are in traversal order.
{buf} (integer) buffer number
{col} (integer) queried start column (0-based)
{end_col}? (integer) queried end column (only set for range
queries)
{end_row}? (integer) queried end row (only set for range queries)
{extmarks} (vim.inspect_pos.ExtmarkItem[])
{row} (integer) queried start row (0-based)
{semantic_tokens} (vim.inspect_pos.ExtmarkItem[])
{syntax} (vim.inspect_pos.SyntaxItem[])
{treesitter} (vim.inspect_pos.TSItem[])
Show all the items at a given buffer position.
Can also be shown with
:Inspect.:Inspect:Inspect accepts an Ex range, inspecting all the addressed lines,
including when invoked from Visual mode. Use opts.end_row and
opts.end_col for a byte range.
See also :marks to list all extmarks.
Example: To bind this function to the vim-scriptease inspired
zS in
Normal mode:vim.keymap.set('n', 'zS', vim.show_pos)
Attributes:
Since: 0.9.0
Parameters:
{buf} (integer?) defaults to the current buffer
{row} (integer?) row to inspect, 0-based. Defaults to the row of
the current cursor
{col} (integer?) col to inspect, 0-based. Defaults to the col of
the current cursor
{opts} (table?) A table with the following fields:
{end_col}? (integer, default: nil, single position) End
column (0-based, exclusive) for range inspection.
{end_row}? (integer, default: nil, single position) End
row (0-based) for range inspection. Must be specified
together with end_col; items overlapping the range from
(row, col) to (end_row, end_col) are returned.
{extmarks}? (boolean|"all", default: true) Include extmark
highlights. When all, also include point marks and
extmarks without a hl_group.
{semantic_tokens}? (boolean, default: true) Include
semantic token highlights.
{syntax}? (boolean, default: true) Include syntax based
highlight groups.
{treesitter}? (boolean, default: true) Include
treesitter based highlight groups.
Lua module: vim.base64
vim.base64.decode(
Decode a Base64 encoded string.
{str})vim.base64.decode()Parameters:
{str} (string) Base64 encoded string
Return:
(string) Decoded string
vim.base64.encode(
Encode {str})vim.base64.encode(){str} using Base64.
Parameters:
{str} (string) String to encode
Return:
(string) Encoded string
Lua module: vim.filetype
vim.filetype.add(
Add new filetype mappings.
{filetypes})vim.filetype.add()
Filetype mappings can be added either by extension or by filename (either
the "tail" or the full file path). The full file path is checked first,
followed by the file name. If a match is not found using the filename,
then the filename is matched against the list of lua-patterns (sorted by
priority) until a match is found. Lastly, if pattern matching does not
find a filetype, then the file extension is used. Extension mappings match
only the text after the final dot in the filename.
The filetype can be either a string (in which case it is used as the
filetype directly) or a function. If a function, it takes the full path
and buffer number of the file as arguments (along with captures from the
matched pattern, if any) and should return a string that will be used as
the buffer's filetype. Optionally, the function can return a second
function value which, when called, modifies the state of the buffer. This
can be used to, for example, set filetype-specific buffer variables. This
function will be called by Nvim before setting the buffer's filetype.
Filename patterns can specify an optional priority to resolve cases when a
file path matches multiple patterns. Higher priorities are matched first.
When omitted, the priority defaults to 0. A pattern can contain
environment variables of the form "${SOME_VAR}" that will be automatically
expanded. If the environment variable is not set, the pattern won't be
matched.
See $VIMRUNTIME/lua/vim/filetype.lua for more examples.
Example:
vim.filetype.add({
extension = {
foo = 'fooscript',
bar = function(path, bufnr)
if some_condition() then
return 'barscript', function(bufnr)
-- Set a buffer variable
vim.b[bufnr].barscript_version = 2
end
end
return 'bar'
end,
},
filename = {
['.foorc'] = 'toml',
['/etc/foo/config'] = 'toml',
},
pattern = {
['.*/etc/foo/.*'] = 'fooscript',
-- Using an optional priority
['.*/etc/foo/.*%.conf'] = { 'dosini', { priority = 10 } },
-- A pattern containing an environment variable
['${XDG_CONFIG_HOME}/foo/git'] = 'git',
['.*README.(%a+)'] = function(path, bufnr, ext)
if ext == 'md' then
return 'markdown'
elseif ext == 'rst' then
return 'rst'
end
end,
},
})
To add a fallback match on contents, use
vim.filetype.add {
pattern = {
['.*'] = {
function(path, bufnr)
local content = vim.api.nvim_buf_get_lines(bufnr, 0, 1, false)[1] or ''
if vim.regex([[^#!.*\\<mine\\>]]):match_str(content) ~= nil then
return 'mine'
elseif vim.regex([[\\<drawing\\>]]):match_str(content) ~= nil then
return 'drawing'
end
end,
{ priority = -math.huge },
},
},
}
Parameters:
{filetypes} (table) A table containing new filetype maps (see
example).
{extension}? (vim.filetype.mapping)
{filename}? (vim.filetype.mapping)
{pattern}? (vim.filetype.mapping)
Get the default option value for a
{filetype}.
The returned value is what would be set in a new buffer after 'filetype'
is set, meaning it should respect all FileType autocmds and ftplugin
files.
Example:
vim.filetype.get_option('vim', 'commentstring')
Note: this uses nvim_get_option_value() but caches the result. This
means ftplugin and FileType autocommands are only triggered once and
may not reflect later changes.
Attributes:
Since: 0.9.0
Parameters:
{filetype} (string) Filetype
{option} (string) Option name
Return:
(string|boolean|integer) Option value
vim.filetype.inspect()vim.filetype.inspect()
Inspect the current state of the filetype registry.
Returns a copy of the internal tables used for filetype detection by
extension, filename, or pattern. Note: Due to the dynamic nature of
filetype detection, this is only useful for checking whether a certain
extension, filename, or pattern has been registered so far. In addition,
the
pattern table is in an internal format optimized for fast lookup.
Prefer vim.filetype.match() for checking the detected filetype for a
given pattern.
Return:
({ extension: vim.filetype.mapping, filename: vim.filetype.mapping, pattern: table<string, vim.filetype.mapping> })
vim.filetype.match(
Perform filetype detection.
{args})vim.filetype.match()
The filetype can be detected using one of three methods:
Using an existing buffer
Using only a file name
Using only file contents
Of these, option 1 provides the most accurate result as it uses both the
buffer's filename and (optionally) the buffer contents. Options 2 and 3
can be used without an existing buffer, but may not always provide a match
in cases where the filename (or contents) cannot unambiguously determine
the filetype.
Each of the three options is specified using a key to the single argument
of this function. Example:
-- Using a buffer number
vim.filetype.match({ buf = 42 })
-- Override the filename of the given buffer
vim.filetype.match({ buf = 42, filename = 'foo.c' })
-- Using a filename without a buffer
vim.filetype.match({ filename = 'main.lua' })
-- Using file contents
vim.filetype.match({ contents = {'#!/usr/bin/env bash'} })
Parameters:
{args} (table) Table specifying which matching strategy to use.
Accepted keys are:
{buf}? (integer) Buffer number to use for matching.
Mutually exclusive with {contents}
{contents}? (string[]) An array of lines representing file
contents to use for matching. Can be used with {filename}.
Mutually exclusive with {buf}.
{filename}? (string) Filename to use for matching. When
{buf} is given, defaults to the filename of the given buffer
number. The file need not actually exist in the filesystem.
When used without {buf} only the name of the file is used
for filetype matching. This may result in failure to detect
the filetype in cases where the filename alone is not enough
to disambiguate the filetype.
Return (multiple):
(string?) The matched filetype, if any.
(function?) A function fun(buf: integer) that modifies buffer
state when called (for example, to set some filetype specific buffer
variables).
(boolean?) true if a match was found by falling back to a generic
filetype (i.e., ".conf"), which indicates the filetype should be set
with :setf FALLBACK conf. See :setfiletype.
Lua module: vim.fs
Use filecopy() or uv.fs_copyfile() to performantly copy an existing file.
Example:
vim.fn.filecopy('foo.txt', 'bar.txt')
Use uv.fs_stat() to check a file's type, and whether it exists.
Example:
if vim.uv.fs_stat(file) then
vim.print('file exists')
end
You can use readblob() to get a file's contents without explicitly
opening/closing it. Or use io.lines() to iterate lines in a text file.
Example:
vim.print(vim.fn.readblob('.git/config'))
You can use writefile() to write a file without explicitly opening/closing
it.
Example:
vim.fn.writefile('foo\0bar', 'data.bin', 'b')
Converts
path to an absolute path. Expands tilde (~) at the beginning of
the path (unless plain=true). Does not check if the path exists, normalize
the path, resolve symlinks or hardlinks (including "." and ".."), or
expand environment variables. If the path is already absolute, it is
returned unchanged. Converts \ path separators to /. URLs (e.g.
"fugitive:///a") are returned as-is.
Attributes:
Since: 0.11.0
Parameters:
{path} (string) Path
{opts} (table?) A table with the following fields:
{cwd}? (string) Resolve the path relative to this
directory.
{plain}? (boolean) Do not expand tilde (~).
Return:
(string) Absolute path
vim.fs.basename(
Gets the basename of the given path (not expanded/resolved).
{file})vim.fs.basename()Attributes:
Since: 0.8.0
Parameters:
{file} (string?) Path
Return:
(string?) Basename of file
Gets an iterator over items found in
path (normalized via
vim.fs.normalize()).
Example:
for name, type, err in vim.fs.dir(path, { err = true }) do
if err then
-- Failed to scan directory {name} (may be the root {path} itself).
end
end
Attributes:
Since: 0.8.0
Parameters:
{path} (string) Directory to iterate over, expanded (unless
opts.plain=true) and normalized.
{opts} (table?) A table with the following fields:
{depth}? (integer, default: 1) How deep to traverse.
{err}? (boolean, default: false) Report errors via the
iterator's third value ("err"), instead of silently
skipping.
{follow}? (boolean, default: false) Follow symbolic
links.
{plain}? (boolean, default: false) Do not expand special
forms like "~" and "$" in {path}.
{skip}? (fun(dir_name: string): boolean) Predicate to
control traversal. Return false to stop searching the
current directory. Only useful when depth > 1 Return an
iterator over the items located in {path}
Return:
(fun(): string?, string?, string?) Iterator over items in {path},
yielding (name, type, err):
name: Basename of the item relative to
{path}.
type: One of: "file", "directory", "link", "fifo", "socket", "char",
"block", "unknown".
err: Error string, or nil. Only if
opts.err=true. If the root
{path} itself could not be scanned, yields a single (name, nil, err)
item.
vim.fs.dirname(
Gets the parent directory of the given path (not expanded/resolved, the
caller must do that).
{file})vim.fs.dirname()Attributes:
Since: 0.8.0
Parameters:
{file} (string?) Path
Return:
(string?) Parent directory of file
Return the file's last extension, if any.
Similar to fnamemodify() with the ::e modifier. The extension does not
include a leading period.
Examples:
vim.fs.ext('archive.tar.gz') -- 'gz'
vim.fs.ext('~/.git') -- ''
vim.fs.ext('plugin/myplug.lua') -- 'lua'
Attributes:
Since: 0.12.0
Parameters:
{file} (string) Path
{opts} (table?) Reserved for future use
Return:
(string) Extension of {file}
Find files or directories (or other items as specified by
opts.type) in
the given path.
Finds items given in
{names} starting from {path}. If {upward} is "true"
then the search traverses upward through parent directories; otherwise,
the search traverses downward. Note that downward searches are recursive
and may search through many directories! If {stop} is non-nil, then the
search stops when the directory given in {stop} is reached. The search
terminates when {limit} (default 1) matches are found. You can set {type}
to "file", "directory", "link", "socket", "char", "block", or "fifo" to
narrow the search to find only that type.
Examples:
-- List all test directories under the runtime directory.
local dirs = vim.fs.find(
{ 'test', 'tst', 'testdir' },
{ limit = math.huge, type = 'directory', path = './runtime/' }
)
-- Get all "lib/*.cpp" and "lib/*.hpp" files, using Lua patterns.
-- Or use `vim.glob.to_lpeg(…):match(…)` for glob/wildcard matching.
local files = vim.fs.find(function(name, path)
return name:match('.*%.[ch]pp$') and path:match('[/\\]lib$')
end, { limit = math.huge, type = 'file' })
Attributes:
Since: 0.8.0
Parameters:
{names} (string|string[]|fun(name: string, path: string): boolean)
Names of the items to find. Must be base names, paths and
globs are not supported when {names} is a string or a table.
If {names} is a function, it is called for each traversed
item with args:
name: base name of the current item
path: full path of the directory containing the current
item
The function should return
true if the given item is
considered a match.
{opts} (table?) Optional keyword arguments:
{follow}? (boolean, default: false) Follow symbolic
links.
{limit}? (number, default: 1) Stop searching after this
many matches. Use math.huge for "unlimited".
{stop}? (string) Stop searching when this directory is
reached. The directory itself is not searched.
{type}? (string) Find only items of the given type. If
omitted, all items that match names are included. With
follow, a symlink has the type of its target.
{upward}? (boolean, default: false) Search upward
through parent directories. Otherwise, search child
directories (recursively).
Return (multiple):
(string[]) Normalized paths vim.fs.normalize() of all matching
items.
(string[]) Errors collected while searching.
vim.fs.joinpath(
Concatenates partial paths (one absolute or relative path followed by zero
or more relative paths). Slashes are normalized: redundant slashes are
removed, and (on Windows) backslashes are replaced with forward-slashes.
Empty segments are removed. Paths are not expanded/resolved.
{...})vim.fs.joinpath()
To join URI paths, see vim.uri.join().
Examples:
"foo/", "/bar" => "foo/bar"
"", "after/plugin" => "after/plugin"
Windows: "a\foo\", "\bar" => "a/foo/bar"
Attributes:
Since: 0.10.0
Parameters:
{...} (string)
Return:
(string)
Creates a directory.
Attributes:
Since: 0.13.0
Parameters:
{path} (string) Path to create (not expanded/resolved).
{opts} (table?) Optional keyword arguments.
{mode}? (integer, default: 493) Permission bits for
newly-created directories.
{parents}? (boolean, default: false) Create intermediate
directories as necessary.
Normalize a path to a standard format. Expands environment variables, and
tilde "~" at the beginning of the path. Resolves "." and ".." components,
except when the path is relative and resolving it would produce an
absolute path.
"." as the only part in a relative path:
"." => "."
"././" => "."
".." when it leads outside the current directory
"foo/../../bar" => "../bar"
"../../foo" => "../../foo"
".." in the root directory returns the root directory.
"/../../" => "/"
On Windows, backslashes (
\) are converted to forward slashes (/).
Examples:
[[C:\Users\jdoe]] --> "C:/Users/jdoe"
"~/src/neovim" --> "/home/jdoe/src/neovim"
"$XDG_CONFIG_HOME/nvim/init.vim" --> "/Users/jdoe/.config/nvim/init.vim"
"~/src/nvim/api/../tui/./tui.c" --> "/home/jdoe/src/nvim/tui/tui.c"
"./foo/bar" --> "foo/bar"
"foo/../../../bar" --> "../../bar"
"/home/jdoe/../../../bar" --> "/bar"
"C:foo/../../baz" --> "C:../baz"
"C:/foo/../../baz" --> "C:/baz"
[[\\?\UNC\server\share\foo\..\..\..\bar]] --> "//?/UNC/server/share/bar"
Attributes:
Since: 0.8.0
Parameters:
{path} (string) Path to normalize
{opts} (table?) A table with the following fields:
{plain}? (boolean, default: false) Do not expand
environment variables and leading tildes "~".
{win}? (boolean, default: true in Windows, false
otherwise) Path is a Windows path.
Return:
(string) Normalized path
vim.fs.parents(
Iterate over all the parents of the given path (not expanded/resolved, the
caller must do that).
{start})vim.fs.parents()
Example:
local root_dir
for dir in vim.fs.parents(vim.api.nvim_buf_get_name(0)) do
if vim.fn.isdirectory(dir .. '/.git') == 1 then
root_dir = dir
break
end
end
if root_dir then
print('Found git repository at', root_dir)
end
Attributes:
Since: 0.8.0
Parameters:
{start} (string) Initial path.
Return (multiple):
(fun(_, dir: string): string?) Iterator
(nil)
(string?)
Gets
target path relative to base, or nil if base is not an
ancestor.
Example:
vim.fs.relpath('/var', '/var/lib') -- 'lib'
vim.fs.relpath('/var', '/usr/bin') -- nil
Attributes:
Since: 0.11.0
Parameters:
{base} (string)
{target} (string)
{opts} (table?) Reserved for future use
Return:
(string?)
Removes a file or directory.
Removes symlinks without touching the origin. To remove the origin,
resolve it explicitly with uv.fs_realpath():
vim.fs.rm(vim.uv.fs_realpath('symlink-dir'), { recursive = true })
Attributes:
Since: 0.11.0
Parameters:
{path} (string) Path to remove (not expanded/resolved).
{opts} (table?) A table with the following fields:
{force}? (boolean) Ignore nonexistent files and arguments.
{recursive}? (boolean) Remove directory contents
recursively.
Find the first parent directory containing a specific "marker", relative
to a file path or buffer.
If the buffer is unnamed (has no backing file) or has a non-empty
'buftype' then the search begins from Nvim's current-directory.
Examples:
-- Find the root of a Python project, starting from file 'main.py'
vim.fs.root(vim.fs.joinpath(vim.env.PWD, 'main.py'), {'pyproject.toml', 'setup.py' })
-- Find the root of a git repository
vim.fs.root(0, '.git')
-- Find the parent directory containing any file with a .csproj extension
vim.fs.root(0, function(name, path)
return vim.fs.ext(name) == 'csproj'
end)
-- Find the first ancestor directory containing EITHER "stylua.toml" or ".luarc.json"; if
-- not found, find the first ancestor containing ".git":
vim.fs.root(0, { { 'stylua.toml', '.luarc.json' }, '.git' })
Attributes:
Since: 0.10.0
Parameters:
{source} (integer|string) Buffer number (0 for current buffer),
file path (absolute or relative, expanded via abspath()),
or "file://" URI to begin the search from.
{marker} ((string|string[]|fun(name: string, path: string): boolean)[]|string|fun(name: string, path: string): boolean)
Filename, function, or list thereof, that decides how to
find the root. To indicate "equal priority", specify items
in a nested list { { 'a.txt', 'b.lua' }, … }. A function
item must return true if name and path are a match. Each
item (which may itself be a nested list) is evaluated
in-order against all ancestors, until a match is found.
Return:
(string?) Directory path containing one of the given markers, or nil
if no directory was found.
Gets a filesystem-safe, mnemonic slug (readable prefix + short hash) of an
arbitrary filepath or other "identity string".
The input is normalized so equivalent paths produce the same result.
A hash of the normalized input is appended to prevent collisions.
Unsafe chars are replaced with "-".
$HOME is replaced with "~".
URIs (
scheme://...) are prefixed with "=uri-{scheme}-".
UNC paths (Windows) are prefixed with "=unc-".
If
opts.maxlen is exceeded, the result will be truncated to
{head}~~~{tail}-{hash8}.
If the sanitized name is empty, the reserved label
=special will be
used.
Examples:
vim.print(vim.fs.slug('/tmp/test/foo.md')) --> "tmp-test-foo.md-{hash}"
vim.print(vim.fs.slug('C:/src/project/main.c')) --> "C--src-project-main.c-{hash}"
vim.print(vim.fs.slug(vim.fn.expand('~/file.txt'))) --> "~-file.txt-{hash}"
vim.print(vim.fs.slug('---')) --> "=special-{hash}"
vim.print(vim.fs.slug('term://foo/bar//123:bash')) --> "=uri-term-foo-bar-123-bash-{hash}"
vim.print(vim.fs.slug(('/a/very/long/path'):rep(10) .. '/file.txt', { maxlen = 60 }))
--> "a-very-long-~~~-path-a-very-long-path-file.txt-{hash}"
Attributes:
Since: 0.13.0
Parameters:
{path} (string) Filepath (or other identity string).
{opts} ({ maxlen?: integer }?)
maxlen: (integer, default: 180) Max length (bytes) of the
result.
Return:
(string) Filesystem-safe, mnemonic slug.
Lua module: vim.glob
Glob-to-LPeg Converter (Peglob) This module converts glob patterns to LPeg
patterns according to the LSP 3.17 specification:
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#pattern
Glob grammar overview:
* to match zero or more characters in a path segment
? to match on one character in a path segment
** to match any number of path segments, including none
{} to group conditions (e.g. *.{ts,js} matches TypeScript and JavaScript
files)
[] to declare a range of characters to match in a path segment (e.g.,
example.[0-9] to match on example.0, example.1, …)
[!...] to negate a range of characters to match in a path segment (e.g.,
example.[!0-9] to match on example.a, example.b, but not example.0)
Additional constraints:
A Glob pattern must match an entire path, with partial matches considered
failures.
The pattern only determines success or failure, without specifying which
parts correspond to which characters.
A path segment is the portion of a path between two adjacent path separators
(
/), or between the start/end of the path and the nearest separator.
The
** (globstar) pattern matches zero or more path segments, including
intervening separators (/). Within pattern strings, ** must be delimited
by path separators (/) or pattern boundaries and cannot be adjacent to any
characters other than /. If ** is not the final element, it must be
followed by /.
{} (braced conditions) contains valid Glob patterns as branches, separated
by commas. Commas are exclusively used for separating branches and cannot
appear within a branch for any other purpose. Nested {} structures are
allowed, but {} must contain at least two branches—zero or one branch is
not permitted.
In
[] or [!...], a character range consists of character intervals
(e.g., a-z) or individual characters (e.g., w). A range including /
won’t match that character.
vim.glob.to_lpeg(
Parses a raw glob into an lua-lpeg pattern.
{pattern})vim.glob.to_lpeg()Parameters:
{pattern} (string) The raw glob pattern
Lua module: vim.hl
vim.hl.hl_op(
Highlights the affected text region during a TextYankPost or
TextPutPost event.
{opts})vim.hl.hl_op()
Add this to your
init.vim:autocmd TextYankPost * silent! lua vim.hl.hl_op {higroup='Visual', timeout=300}
autocmd TextPutPost * silent! lua vim.hl.hl_op {higroup='Visual', timeout=300}
Parameters:
{opts} (table?) Optional parameters
event (default: vim.v.event) Event structure.
higroup (default: "IncSearch") Highlight group for the text
region.
on_macro (default: false) Highlight during macro
execution.
on_visual (default: true) Highlight during Visual mode.
priority (default: vim.hl.priorities
.user) Integer
priority.
timeout (default: 150) Time in ms before highlight is
cleared.
vim.hl.prioritiesvim.hl.priorities
Table with default priorities used for highlighting:
syntax: 50, used for standard syntax highlighting
treesitter: 100, used for treesitter-based highlighting
semantic_tokens: 125, used for LSP semantic token highlighting
diagnostics: 150, used for code analysis such as diagnostics
user: 200, used for user-triggered highlights such as LSP document
symbols or hl_op autocommands
Apply highlight group to range of text.
Parameters:
{buf} (integer) Buffer number to apply highlighting to
{ns} (integer) Namespace to add highlight to
{hlgroup} (integer|integer[]|string|string[]) Highlight group used
for the text range. See the hl_group option in
nvim_buf_set_extmark().
{start} ([integer,integer]|string) Start of region as a (line,
column) tuple or string accepted by getpos()
{finish} ([integer,integer]|string) End of region as a (line,
column) tuple or string accepted by getpos()
{opts} (table?) A table with the following fields:
{inclusive}? (boolean, default: false) Indicates
whether the range is end-inclusive
{priority}? (integer, default:
vim.hl.priorities.user) Highlight priority
{timeout}? (integer, default: -1 no timeout) Time in ms
before highlight is cleared
Return (multiple):
(uv.uv_timer_t?) range_timer A timer which manages how much time the
highlight has left
(fun()?) range_clear A function which allows clearing the highlight
manually. nil is returned if timeout is not specified
Lua module: vim.iter
vim.iter() is an interface for iterables: it wraps a table or function
argument into an Iter object with methods (such as Iter:filter() and
Iter:map()) that transform the underlying source data. These methods can be
chained to create iterator "pipelines": the output of each pipeline stage is
input to the next stage. The first stage depends on the type passed to
vim.iter():
Lists or arrays (lua-list) yield only the value of each element.
Holes (nil values) are allowed (but discarded).
Use pairs() to treat array/list tables as dicts (preserve holes and
non-contiguous integer keys):
vim.iter(pairs(…)).
Use Iter:enumerate() to also pass the index to the next stage.
Or initialize with ipairs():
vim.iter(ipairs(…)).
Non-list tables (lua-dict) yield both the key and value of each element.
Function iterators yield all values returned by the underlying function.
Tables with a __call() metamethod are treated as function iterators.
The iterator pipeline terminates when the underlying iterable is exhausted
(for function iterators this means it returned nil).
Note:
vim.iter() scans table input to decide if it is a list or a dict; to
avoid this cost you can wrap the table with an iterator e.g.
vim.iter(ipairs({…})), but that precludes the use of list-iterator
operations such as IterArray:rev()).
Examples:
local it = vim.iter({ 1, 2, 3, 4, 5 })
it:map(function(v)
return v * 3
end)
it:rev()
it:skip(2)
it:totable()
-- { 9, 6, 3 }
-- ipairs() is a function iterator which returns both the index (i) and the value (v)
vim.iter(ipairs({ 1, 2, 3, 4, 5 })):map(function(i, v)
if i > 2 then return v end
end):totable()
-- { 3, 4, 5 }
local it = vim.iter(vim.gsplit('1,2,3,4,5', ','))
it:map(function(s) return tonumber(s) end)
for i, d in it:enumerate() do
print(string.format("Column %d is %d", i, d))
end
-- Column 1 is 1
-- Column 2 is 2
-- Column 3 is 3
-- Column 4 is 4
-- Column 5 is 5
vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v)
return k == 'z'
end)
-- true
local rb = vim.ringbuf(3)
rb:push("a")
rb:push("b")
vim.iter(rb):totable()
-- { "a", "b" }
Iter:all(
Returns true if all items in the iterator match the given predicate.
{pred})Iter:all()Attributes:
Since: 0.10.0
Parameters:
{pred} (fun(v: V1, ...: V...): boolean) Predicate function. Takes
all values returned from the previous stage in the pipeline as
arguments and returns true if the predicate matches.
Iter:any(
Returns true if any of the items in the iterator match the given
predicate.
{pred})Iter:any()Attributes:
Since: 0.10.0
Parameters:
{pred} (fun(v: V1, ...: V...): boolean) Predicate function. Takes
all values returned from the previous stage in the pipeline as
arguments and returns true if the predicate matches.
Iter:count()Iter:count()
Drains the iterator, counting the number of iterations and returning it.
Attributes:
Since: 0.13.0
Return:
(integer)
Iter:each(
Calls a function once for each item in the pipeline, draining the
iterator.
{f})Iter:each()
For functions with side effects. To modify the values in the iterator, use
Iter:map().
Attributes:
Since: 0.10.0
Parameters:
{f} (fun(v: V1, ...: V...)) Function to execute for each item in
the pipeline. Takes all of the values returned by the previous
stage in the pipeline as arguments.
Iter:enumerate()Iter:enumerate()
Yields the item index (count) and value for each item of an iterator
pipeline.
For list tables, this is more efficient:
vim.iter(ipairs(t))
instead of:
vim.iter(t):enumerate()
Example:
local it = vim.iter(vim.gsplit('abc', '')):enumerate()
it:next()
-- 1 'a'
it:next()
-- 2 'b'
it:next()
-- 3 'c'
Attributes:
Since: 0.10.0
Overloads:
fun<V1, V...>(self: vim.IterArray<V1, V...>): vim.IterArray<integer, V1, V...>
Return:
(vim.Iter<integer, V1, V...>)
Iter:filter(
Filters an iterator pipeline.
{f})Iter:filter()
Example:
local bufs = vim.iter(vim.api.nvim_list_bufs()):filter(vim.api.nvim_buf_is_loaded)
Parameters:
{f} (fun(v: V1, ...: V...): boolean) Takes all values returned from
the previous stage in the pipeline and returns false or nil if
the current iterator element should be removed.
Overloads:
fun<V1, V...>(self: vim.IterArray<V1, V...>, f: fun(v: V1, ...: V...): boolean): vim.IterArray<V1, V...>
Return:
(vim.Iter<V1, V...>)
Iter:find(
Find the first value in the iterator that satisfies the given predicate.
{f})Iter:find()
Advances the iterator. Returns nil and drains the iterator if no value is
found.
Examples:
local it = vim.iter({ 3, 6, 9, 12 })
it:find(12)
-- 12
local it = vim.iter({ 3, 6, 9, 12 })
it:find(20)
-- nil
local it = vim.iter({ 3, 6, 9, 12 })
it:find(function(v) return v % 4 == 0 end)
-- 12
Attributes:
Since: 0.10.0
Parameters:
{f} (V1|fun(v: V1, ...: V...): any)
Return (multiple):
(V1?)
(V...)
Folds ("reduces") an iterator into a single value.Iter:reduce()
Examples:
-- Create a new table with only even values
vim.iter({ a = 1, b = 2, c = 3, d = 4 })
:filter(function(k, v) return v % 2 == 0 end)
:fold({}, function(acc, k, v)
acc[k] = v
return acc
end) --> { b = 2, d = 4 }
-- Get the "maximum" item of an iterable.
vim.iter({ -99, -4, 3, 42, 0, 0, 7 })
:fold({}, function(acc, v)
acc.max = math.max(v, acc.max or v)
return acc
end) --> { max = 42 }
Attributes:
Since: 0.10.0
Parameters:
{init} (any) Initial value of the accumulator.
{f} (fun(acc: A, v: V1, ...: V...): A) Accumulation function.
Return:
(any)
Iter:join(
Collect the iterator into a delimited string.
{delim})Iter:join()
Each element in the iterator is joined into a string separated by
{delim}.
Consumes the iterator.
Attributes:
Since: 0.10.0
Parameters:
{delim} (string) Delimiter
Return:
(string)
Iter:last()Iter:last()
Drains the iterator and returns the last item.
Example:
local it = vim.iter(vim.gsplit('abcdefg', ''))
it:last()
-- 'g'
local it = vim.iter({ 3, 6, 9, 12, 15 })
it:last()
-- 15
Attributes:
Since: 0.10.0
Return (multiple):
(V1?)
(V...)
See also:
Iter:map(
Maps the items of an iterator pipeline to the values returned by {f})Iter:map()f.
If the map function returns nil, the value is filtered from the iterator.
Example:
local it = vim.iter({ 1, 2, 3, 4 }):map(function(v)
if v % 2 == 0 then
return v * 3
end
end)
it:totable()
-- { 6, 12 }
Attributes:
Since: 0.10.0
Parameters:
{f} (fun(v: V1, ...: V...): K2, V2...) Mapping function. Takes all
values returned from the previous stage in the pipeline as
arguments and returns one or more new values, which are used in
the next pipeline stage. Nil return values are filtered from the
output.
Overloads:
fun<V1, V..., K1, K...>(self: vim.IterArray<V1, V...>, f: fun(v: V1, ...: V...): K1, K...): vim.IterArray<K1, K...>
Return:
(vim.Iter<K2, V2...>)
Iter:next()Iter:next()
Gets the next value from the iterator.
Example:
local it = vim.iter(string.gmatch('1 2 3', '%d+')):map(tonumber)
it:next()
-- 1
it:next()
-- 2
it:next()
-- 3
Attributes:
Since: 0.10.0
Return (multiple):
(V1?)
(V...)
Iter:nth(
Gets the nth value of an iterator (and advances to it).
{n})Iter:nth()
If
n is negative, offsets from the end of a list-iterator.
Example:
local it = vim.iter({ 3, 6, 9, 12 })
it:nth(2)
-- 6
it:nth(2)
-- 12
local it2 = vim.iter({ 3, 6, 9, 12 })
it2:nth(-2)
-- 9
it2:nth(-2)
-- 3
Attributes:
Since: 0.10.0
Parameters:
Return (multiple):
(V1?)
(V...)
Iter:peek()Iter:peek()
Gets the next value from the iterator without consuming it.
The value returned by Iter:peek() will be returned again by the next
call to Iter:next().
Example:
local it = vim.iter({ 3, 6, 9, 12 })
it:peek()
-- 3
it:peek()
-- 3
it:next()
-- 3
Attributes:
Since: 0.10.0
Return (multiple):
(V1?)
(V...)
Iter:skip(
Skips {n})Iter:skip()n values of an iterator pipeline, or skips values while a
predicate returns lua-truthy.
When a predicate is used, skipping stops at the first value for which the
predicate returns non-truthy. That value is not consumed and will be
returned by the next call to Iter:next()
Example:
local it = vim.iter({ 3, 6, 9, 12 }):skip(2)
it:next()
-- 9
local function pred(x) return x < 10 end
local it2 = vim.iter({ 3, 6, 9, 12 }):skip(pred)
it2:next()
-- 12
Attributes:
Since: 0.10.0
Parameters:
{n} (integer|fun(v: V1, ...: V...): boolean) Number of values to
skip or a predicate.
Overloads:
fun<V1, V...>(self: vim.IterArray<V1, V...>, n: integer|fun(v: V1, ...: V...): boolean): vim.IterArray<V1, V...>
Return:
(vim.Iter<V1, V...>)
Iter:take(
Transforms an iterator to yield only the first n values, or all values
satisfying a predicate.
{n})Iter:take()
Example:
local it = vim.iter({ 1, 2, 3, 4 }):take(2)
it:next()
-- 1
it:next()
-- 2
it:next()
-- nil
local function pred(x) return x < 2 end
local it2 = vim.iter({ 1, 2, 3, 4 }):take(pred)
it2:next()
-- 1
it2:next()
-- nil
Attributes:
Since: 0.10.0
Parameters:
{n} (integer|fun(v: V1, ...: V...): boolean) Number of values to
take or a predicate.
Overloads:
fun<V1, V...>(self: vim.IterArray<V1, V...>, n: integer|fun(v: V1, ...: V...): boolean): vim.IterArray<V1, V...>
Return:
(vim.Iter<V1, V...>)
Iter:totable()Iter:totable()
Collect the iterator into a table.
The resulting table depends on the initial source in the iterator
pipeline. Array-like tables and function iterators will be collected into
an array-like table. If multiple values are returned from the final stage
in the iterator pipeline, each value will be included in a table.
Examples:
vim.iter(string.gmatch('100 20 50', '%d+')):map(tonumber):totable()
-- { 100, 20, 50 }
vim.iter({ 1, 2, 3 }):map(function(v) return v, 2 * v end):totable()
-- { { 1, 2 }, { 2, 4 }, { 3, 6 } }
vim.iter({ a = 1, b = 2, c = 3 }):filter(function(k, v) return v % 2 ~= 0 end):totable()
-- { { 'a', 1 }, { 'c', 3 } }
The generated table is an array-like table with consecutive, numeric
indices. To create a map-like table with arbitrary keys, use
Iter:fold().
Attributes:
Since: 0.10.0
Return:
(any[])
Iter:unique(
Removes duplicate values from an iterator pipeline.
{key})Iter:unique()
Only the first occurrence of each value is kept.
Accepts an optional
key argument, which if provided is called for each
value in the iterator to compute a hash key for uniqueness comparison.
This is useful for deduplicating table values or complex objects. If key
returns nil for a value, that value will be considered unique, even if
multiple values return nil.
If a function-based iterator returns multiple arguments, uniqueness is
checked based on the first return value. To change this behavior, specify
key.
Examples:
vim.iter({ 1, 2, 2, 3, 2 }):unique():totable()
-- { 1, 2, 3 }
vim.iter({ {id=1}, {id=2}, {id=1} })
:unique(function(x)
return x.id
end)
:totable()
-- { {id=1}, {id=2} }
Attributes:
Since: 0.12.0
Parameters:
{key} (fun(v: V1, ...: V...): any?) Optional hash function to
determine uniqueness of values.
Overloads:
fun<V1, V...>(self: vim.IterArray<V1, V...>, key: fun(v: V1, ...: V...): any?): vim.IterArray<V1, V...>
Return:
(vim.Iter<V1, V...>)
See also:
IterArray:flatten(
Flattens a list-iterator, un-nesting nested values up to the given
{depth})IterArray:flatten(){depth}. Errors if it attempts to flatten a dict-like value.
Examples:
vim.iter({ 1, { 2 }, { { 3 } } }):flatten():totable()
-- { 1, 2, { 3 } }
vim.iter({1, { { a = 2 } }, { 3 } }):flatten():totable()
-- { 1, { a = 2 }, 3 }
vim.iter({ 1, { { a = 2 } }, { 3 } }):flatten(math.huge):totable()
-- error: attempt to flatten a dict-like table
Attributes:
Since: 0.10.0
Parameters:
Return:
(vim.IterArray<V1, V...>)
IterArray:pop()IterArray:pop()
"Pops" a value from a list-iterator (gets the last value and decrements
the tail).
Example:
local it = vim.iter({1, 2, 3, 4})
it:pop()
-- 4
it:pop()
-- 3
Attributes:
Since: 0.10.0
Return (multiple):
(V1?)
(V...)
IterArray:rev()IterArray:rev()
Reverses a list-iterator pipeline.
Example:
local it = vim.iter({ 3, 6, 9, 12 }):rev()
it:totable()
-- { 12, 9, 6, 3 }
Attributes:
Since: 0.10.0
Return:
(vim.IterArray<V1, V...>)
IterArray:rfind(
Gets the first value satisfying a predicate, from the end of a
list-iterator.
{f})IterArray:rfind()
Advances the iterator. Returns nil and drains the iterator if no value is
found.
Examples:
local it = vim.iter({ 1, 2, 3, 2, 1 }):enumerate()
it:rfind(1)
-- 5 1
it:rfind(1)
-- 1 1
Attributes:
Since: 0.10.0
Parameters:
{f} (V1|fun(v: V1, ...: V...): boolean)
Return (multiple):
(V1?)
(V...)
See also:
IterArray:rpeek()IterArray:rpeek()
Gets the last value of a list-iterator without consuming it.
Example:
local it = vim.iter({1, 2, 3, 4})
it:rpeek()
-- 4
it:rpeek()
-- 4
it:pop()
-- 4
Attributes:
Since: 0.10.0
Return (multiple):
(V1?)
(V...)
See also:
Example:
local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)
it:next()
-- 1
it:pop()
-- 3
Attributes:
Since: 0.10.0
Parameters:
{n} (integer)
Return:
(vim.IterArray<V1, V...>)
Sets the start and end of a list-iterator pipeline.
Equivalent to
:skip(first - 1):rskip(len - last).
Attributes:
Since: 0.10.0
Parameters:
{first} (integer)
{last} (integer)
Return:
(vim.IterArray<V1, V...>)
Lua module: vim.json
This module provides encoding and decoding of Lua objects to and from
JSON-encoded strings. Supports vim.NIL and vim.empty_dict().
Decodes (or "unpacks") stringified JSON to a Lua object.
Decodes JSON "null" as vim.NIL (controllable by
{opts}, see below).
Decodes empty object as vim.empty_dict().
Decodes empty array as
{} (empty Lua table).
Example:
vim.print(vim.json.decode('{"bar":[],"foo":{},"zub":null}'))
-- { bar = {}, foo = vim.empty_dict(), zub = vim.NIL }
Parameters:
{str} (string) Stringified JSON data.
{opts} (table?) A table with the following fields:
{luanil}? ({ object?: boolean, array?: boolean }, default:
nil) Convert JSON "null" in objects/arrays to Lua nil
instead of vim.NIL.
{skip_comments}? (boolean, default: false) Allows
JavaScript-style comments within JSON data. Comments are
treated as whitespace and may appear anywhere whitespace is
valid in JSON. Supports single-line comments beginning with
'//' and block comments enclosed with '/' and '/'.
Return:
(any)
Encodes (or "packs") a Lua object to stringified JSON.
Example: Implement a basic 'formatexpr' for JSON, so gq with a motion
formats JSON in a buffer. (The motion must operate on a valid JSON
object.)
function _G.fmt_json()
local indent = vim.bo.expandtab and (' '):rep(vim.o.shiftwidth) or '\t'
local lines = vim.api.nvim_buf_get_lines(0, vim.v.lnum - 1, vim.v.lnum + vim.v.count - 1, true)
local o = vim.json.decode(table.concat(lines, '\n'))
local stringified = vim.json.encode(o, { indent = indent, sort_keys = true })
lines = vim.split(stringified, '\n')
vim.api.nvim_buf_set_lines(0, vim.v.lnum - 1, vim.v.count, true, lines)
end
vim.o.formatexpr = 'v:lua.fmt_json()'
Parameters:
{obj} (any)
{opts} (table?) A table with the following fields:
{escape_slash}? (boolean, default: false) Escape slash
characters "/" in string values.
{indent}? (string, default: "") If non-empty, each value
in a JSON object or array starts on a new line and is
prefixed with indent per nesting level. Adds a space after
colons. Does not add a final newline.
{sort_keys}? (boolean, default: false) Sort object keys
in alphabetical order.
Return:
(string)
Lua module: vim.keymap
Removes a mapping, or removes each (mode, lhs) pair if
lhs is a list.
Examples:
vim.keymap.del('n', 'lhs')
vim.keymap.del({'n', 'i', 'v'}, '<leader>w', { buf = 5 })
Parameters:
{modes} (string|string[])
{lhs} (string|string[])
{opts} (table?) A table with the following fields:
{buf}? (integer) Remove a mapping from the given buffer.
0 for current.
{lhs}? (boolean) When true, only match {lhs}, not {rhs}.
See also:
Defines a mapping of keycodes to a function or keycodes. If
lhs is a
list, defines a mapping for each (mode, lhs) pair.
Examples:
-- Map "x" to a Lua function:
vim.keymap.set('n', 'x', function() print('real lua function') end)
-- Map "<leader>x" to multiple modes for the current buffer:
vim.keymap.set({'n', 'v'}, '<leader>x', vim.lsp.buf.references, { buf = 0 })
-- Map <Tab> to an expression (|:map-<expr>|):
vim.keymap.set('i', '<Tab>', function()
return vim.fn.pumvisible() == 1 and '<C-n>' or '<Tab>'
end, { expr = true })
-- Map "[%%" to a <Plug> mapping:
vim.keymap.set('n', '[%%', '<Plug>(MatchitNormalMultiBackward)')
-- Use `getregionpos(getpos('v'))` to get the "current visual selection":
vim.keymap.set('x', 'M', function()
local region = vim.fn.getregionpos(vim.fn.getpos('v'), vim.fn.getpos('.'), {
type = 'v',
exclusive = false,
eol = false,
bounds = true,
})
local line1 = region[1][1][2]
local line2 = region[1][2][2]
vim.print({ line1, line2 })
end)
vim.keymap.set({ 'n', 'i' }, { 'a', 'b' }, '<cmd>echom localtime()<cr>')
-- ... is the same as:
vim.keymap.set('n', 'a', '<cmd>echom localtime()<cr>')
vim.keymap.set('i', 'a', '<cmd>echom localtime()<cr>')
vim.keymap.set('n', 'b', '<cmd>echom localtime()<cr>')
vim.keymap.set('i', 'b', '<cmd>echom localtime()<cr>')
Parameters:
{replace_keycodes} defaults to true if "expr" is true.
{noremap} is not supported; use {remap} instead (see
below).
Also accepts:
{buf}? (integer) Creates buffer-local mapping, 0 for
current buffer.
{remap}? (boolean, default: false) Make the mapping
recursive. Inverse of {noremap}.
Lua module: vim.loader
vim.loader.enable(
WARNING: This feature is experimental/unstable.
{enable})vim.loader.enable()
Enables or disables the experimental Lua module loader:
Enable (
enable=true):
overrides loadfile()
adds the Lua loader using the byte-compilation cache
adds the libs loader
removes the default Nvim loader
Disable (
enable=false):
removes the loaders
adds the default Nvim loader
Parameters:
{enable} (boolean?) true/nil to enable, false to disable
WARNING: This feature is experimental/unstable.
Finds Lua modules for the given module name.
Parameters:
{modname} (string) Module name, or "*" to find the top-level
modules instead
{opts} (table?) Options for finding a module:
{all}? (boolean, default: false) Search for all
matches.
{paths}? (string[], default: {}) Extra paths to
search for modname
{patterns}? (string[], default:
{"/init.lua", ".lua"}) List of patterns to use when
searching for modules. A pattern is a string added to the
basename of the Lua module being searched.
{rtp}? (boolean, default: true) Search for modname in
the runtime path.
Return:
(table[]) A list of objects with the following fields:
{modname} (string) Name of the module
{modpath} (string) Path of the module
{stat}? (uv.fs_stat.result) The fs_stat of the module path. Won't
be returned for modname="*"
vim.loader.reset(
WARNING: This feature is experimental/unstable.
{path})vim.loader.reset()
Resets the cache for the path, or all the paths if path is nil.
Parameters:
{path} (string?) path to reset
Lua module: vim.log
The vim.log module provides file-backed logger instances.
Use
vim.log.new() to create a logger, it exposes five writer functions:
trace(), debug(), info(), warn(), and error(). They are correspond
to log levels defined by vim.log.levels.
Example:
local log = vim.log.new({ name = 'my-plugin', })
-- By default, logs will be written to {name}.log under `stdpath('log')`.
log.error('request failed', 'timeout')
-- This will write a line like the following to the log file:
-- [ERROR][2024-01-01 12:00:00] source.lua:123 request failed timeout
-- Set the log level to `INFO`, otherwise the `info()` call below would be ignored,
-- since the default level is `WARN`.
vim.log.set_level(log, vim.log.levels.INFO)
log.info('starting', { buf = vim.api.nvim_get_current_buf() })
-- This will write a line like the following to the log file:
-- [INFO][2024-01-01 12:01:00] source.lua:124 starting { buf = 1 }
You can also provide a custom formatter function to customize the log output
format.
vim.Logvim.Log
Fields:
{debug} (fun(...:any): boolean?) Writes a message at
vim.log.levels.DEBUG.
{error} (fun(...:any): boolean?) Writes a message at
vim.log.levels.ERROR.
{info} (fun(...:any): boolean?) Writes a message at
vim.log.levels.INFO.
{trace} (fun(...:any): boolean?) Writes a message at
vim.log.levels.TRACE.
{warn} (fun(...:any): boolean?) Writes a message at
vim.log.levels.WARN.
get_level(
Gets the current log level.
{log})vim.log.get_level()Parameters:
{log} (vim.Log)
Return:
(vim.log.levels)
new(
Creates a logger instance.
{opts})vim.log.new()
The logger writes formatted messages to a file, using a per-instance log
level and formatting function.
Parameters:
{opts} (table) A table with the following fields:
{format_func}?
(fun(min_level: vim.log.levels, level: vim.log.levels, ...): string?)
Formatter used for each log entry. Receives the logger's
minimum level, the message level, and the values passed to
the writer. Return a string to write an entry, or nil to
skip it.
{level}? (vim.log.levels, default: vim.log.levels.WARN)
Minimum level that will be written.
{name} (string) Display name used in notifications emitted
by the logger.
Return:
(vim.Log)
Sets the formatter used to produce log entries.
The formatter receives the logger's minimum level, the message level, and
the values passed to the writer method. Return a string to write an entry,
or
nil to skip it.
Parameters:
{log} (vim.Log)
{func} (fun(min_level: vim.log.levels, level: vim.log.levels, ...): string?)
Sets the current log level.
Entries below this level are skipped.
Parameters:
{log} (vim.Log)
{level} (vim.log.levels)
Lua module: vim.lpeg
LPeg is a pattern-matching library for Lua, based on Parsing Expression
Grammars (PEGs). https://bford.info/packrat/
The LPeg library for parsing expression grammars is included as
vim.lpeg
(https://www.inf.puc-rio.br/~roberto/lpeg/).
In addition, its regex-like interface is available as vim.re
(https://www.inf.puc-rio.br/~roberto/lpeg/re.html).
Matches the given
pattern against the subject string. If the match
succeeds, returns the index in the subject of the first character after
the match, or the captured values (if the pattern captured any value). An
optional numeric argument init makes the match start at that position in
the subject string. As usual in Lua libraries, a negative value counts
from the end. Unlike typical pattern-matching functions, match works
only in anchored mode; that is, it tries to match the pattern with a
prefix of the given subject string (at position init), not with an
arbitrary substring of the subject. So, if we want to find a pattern
anywhere in a string, we must either write a loop in Lua or write a
pattern that matches anywhere.
Example:
local pattern = lpeg.R('az') ^ 1 * -1
assert(pattern:match('hello') == 6)
assert(lpeg.match(pattern, 'hello') == 6)
assert(pattern:match('1 hello') == nil)
Parameters:
{subject} (string)
{init} (integer?)
{...} (any)
Return:
(any) ...
vim.lpeg.B(
Returns a pattern that matches only if the input string at the current
position is preceded by {pattern})vim.lpeg.B()patt. Pattern patt must match only strings
with some fixed length, and it cannot contain captures. Like the and
predicate, this pattern never consumes any input, independently of success
or failure.
Parameters:
{pattern} (vim.lpeg.Pattern|string|integer|boolean|table)
Return:
(vim.lpeg.Pattern)
vim.lpeg.C(
Creates a simple capture, which captures the substring of the subject that
matches {patt})vim.lpeg.C()patt. The captured value is a string. If patt has other
captures, their values are returned after this one.
Example:
local function split (s, sep)
sep = lpeg.P(sep)
local elem = lpeg.C((1 - sep) ^ 0)
local p = elem * (sep * elem) ^ 0
return lpeg.match(p, s)
end
local a, b, c = split('a,b,c', ',')
assert(a == 'a')
assert(b == 'b')
assert(c == 'c')
Parameters:
{patt} (vim.lpeg.Pattern|string|integer|boolean|table|function)
Return:
(vim.lpeg.Capture)
vim.lpeg.Carg(
Creates an argument capture. This pattern matches the empty string and
produces the value given as the nth extra argument given in the call to
{n})vim.lpeg.Carg()lpeg.match.
Parameters:
{n} (integer)
Return:
(vim.lpeg.Capture)
vim.lpeg.Cb(
Creates a back capture. This pattern matches the empty string and produces
the values produced by the most recent group capture named {name})vim.lpeg.Cb()name (where
name can be any Lua value). Most recent means the last complete
outermost group capture with the given name. A Complete capture means that
the entire pattern corresponding to the capture has matched. An Outermost
capture means that the capture is not inside another complete capture. In
the same way that LPeg does not specify when it evaluates captures, it
does not specify whether it reuses values previously produced by the group
or re-evaluates them.
Parameters:
{name} (any)
Return:
(vim.lpeg.Capture)
vim.lpeg.Cc(
Creates a constant capture. This pattern matches the empty string and
produces all given values as its captured values.
{...})vim.lpeg.Cc()Parameters:
{...} (any)
Return:
(vim.lpeg.Capture)
Creates a fold capture. If
patt produces a list of captures C1 C2 ...
Cn, this capture will produce the value
func(...func(func(C1, C2), C3)...,Cn), that is, it will fold (or
accumulate, or reduce) the captures from patt using function func.
This capture assumes that patt should produce at least one capture with
at least one value (of any type), which becomes the initial value of an
accumulator. (If you need a specific initial value, you may prefix a
constant capture to patt.) For each subsequent capture, LPeg calls
func with this accumulator as the first argument and all values produced
by the capture as extra arguments; the first result from this call becomes
the new value for the accumulator. The final value of the accumulator
becomes the captured value.
Example:
local number = lpeg.R('09') ^ 1 / tonumber
local list = number * (',' * number) ^ 0
local function add(acc, newvalue) return acc + newvalue end
local sum = lpeg.Cf(list, add)
assert(sum:match('10,30,43') == 83)
Parameters:
{patt} (vim.lpeg.Pattern|string|integer|boolean|table|function)
{func} (fun(acc, newvalue))
Return:
(vim.lpeg.Capture)
Creates a group capture. It groups all values returned by
patt into a
single capture. The group may be anonymous (if no name is given) or named
with the given name (which can be any non-nil Lua value).
Parameters:
{patt} (vim.lpeg.Pattern|string|integer|boolean|table|function)
{name} (string?)
Return:
(vim.lpeg.Capture)
Creates a match-time capture. Unlike all other captures, this one is
evaluated immediately when a match occurs (even if it is part of a larger
pattern that fails later). It forces the immediate evaluation of all its
nested captures and then calls
function. The given function gets as
arguments the entire subject, the current position (after the match of
patt), plus any capture values produced by patt. The first value
returned by function defines how the match happens. If the call returns
a number, the match succeeds and the returned number becomes the new
current position. (Assuming a subject sand current position i, the
returned number must be in the range [i, len(s) + 1].) If the call
returns true, the match succeeds without consuming any input (so, to
return true is equivalent to return i). If the call returns false,
nil, or no value, the match fails. Any extra values returned by the
function become the values produced by the capture.
Parameters:
{patt} (vim.lpeg.Pattern|string|integer|boolean|table|function)
{fn} (fun(s: string, i: integer, ...: any)) (position:
boolean|integer, ...: any)
Return:
(vim.lpeg.Capture)
vim.lpeg.Cp()vim.lpeg.Cp()
Creates a position capture. It matches the empty string and captures the
position in the subject where the match occurs. The captured value is a
number.
Example:
local I = lpeg.Cp()
local function anywhere(p) return lpeg.P({I * p * I + 1 * lpeg.V(1)}) end
local match_start, match_end = anywhere('world'):match('hello world!')
assert(match_start == 7)
assert(match_end == 12)
Return:
(vim.lpeg.Capture)
vim.lpeg.Cs(
Creates a substitution capture. This function creates a substitution
capture, which captures the substring of the subject that matches {patt})vim.lpeg.Cs()patt,
with substitutions. For any capture inside patt with a value, the
substring that matched the capture is replaced by the capture value (which
should be a string). The final captured value is the string resulting from
all replacements.
Example:
local function gsub (s, patt, repl)
patt = lpeg.P(patt)
patt = lpeg.Cs((patt / repl + 1) ^ 0)
return lpeg.match(patt, s)
end
assert(gsub('Hello, xxx!', 'xxx', 'World') == 'Hello, World!')
Parameters:
{patt} (vim.lpeg.Pattern|string|integer|boolean|table|function)
Return:
(vim.lpeg.Capture)
vim.lpeg.Ct(
Creates a table capture. This capture returns a table with all values from
all anonymous captures made by {patt})vim.lpeg.Ct()patt inside this table in successive
integer keys, starting at 1. Moreover, for each named capture group
created by patt, the first value of the group is put into the table with
the group name as its key. The captured value is only the table.
Parameters:
{patt} (vim.lpeg.Pattern|string|integer|boolean|table|function)
Return:
(vim.lpeg.Capture)
vim.lpeg.locale(
Returns a table with patterns for matching some character classes
according to the current locale. The table has fields named {tab})vim.lpeg.locale()alnum,
alpha, cntrl, digit, graph, lower, print, punct, space,
upper, and xdigit, each one containing a correspondent pattern. Each
pattern matches any single character that belongs to its class. If called
with an argument table, then it creates those fields inside the given
table and returns that table.
Example:
lpeg.locale(lpeg)
local space = lpeg.space ^ 0
local name = lpeg.C(lpeg.alpha ^ 1) * space
local sep = lpeg.S(',;') * space
local pair = lpeg.Cg(name * '=' * space * name) * sep ^ -1
local list = lpeg.Cf(lpeg.Ct('') * pair ^ 0, rawset)
local t = list:match('a=b, c = hi; next = pi')
assert(t.a == 'b')
assert(t.c == 'hi')
assert(t.next == 'pi')
local locale = lpeg.locale()
assert(type(locale.digit) == 'userdata')
Parameters:
{tab} (table?)
Return:
(vim.lpeg.Locale)
Matches the given
pattern against the subject string. If the match
succeeds, returns the index in the subject of the first character after
the match, or the captured values (if the pattern captured any value). An
optional numeric argument init makes the match start at that position in
the subject string. As usual in Lua libraries, a negative value counts
from the end. Unlike typical pattern-matching functions, match works
only in anchored mode; that is, it tries to match the pattern with a
prefix of the given subject string (at position init), not with an
arbitrary substring of the subject. So, if we want to find a pattern
anywhere in a string, we must either write a loop in Lua or write a
pattern that matches anywhere.
Example:
local pattern = lpeg.R('az') ^ 1 * -1
assert(pattern:match('hello') == 6)
assert(lpeg.match(pattern, 'hello') == 6)
assert(pattern:match('1 hello') == nil)
Parameters:
{pattern} (vim.lpeg.Pattern|string|integer|boolean|table|function)
{subject} (string)
{init} (integer?)
{...} (any)
Return:
(any) ...
vim.lpeg.P(
Converts the given value into a proper pattern. The following rules are
applied:
{value})vim.lpeg.P() If the argument is a pattern, it is returned unmodified.
If the argument is a string, it is translated to a pattern that matches
the string literally.
If the argument is a non-negative number
n, the result is a pattern
that matches exactly n characters.
If the argument is a negative number
-n, the result is a pattern that
succeeds only if the input string has less than n characters left:
lpeg.P(-n) is equivalent to -lpeg.P(n) (see the unary minus
operation).
If the argument is a boolean, the result is a pattern that always
succeeds or always fails (according to the boolean value), without
consuming any input.
If the argument is a table, it is interpreted as a grammar (see
Grammars).
If the argument is a function, returns a pattern equivalent to a
match-time capture over the empty string.
Parameters:
{value} (vim.lpeg.Pattern|string|integer|boolean|table|function)
Return:
(vim.lpeg.Pattern)
vim.lpeg.R(
Returns a pattern that matches any single character belonging to one of
the given ranges. Each {...})vim.lpeg.R()range is a string xy of length 2, representing
all characters with code between the codes of x and y (both
inclusive). As an example, the pattern lpeg.R('09') matches any digit,
and lpeg.R('az', 'AZ') matches any ASCII letter.
Example:
local pattern = lpeg.R('az') ^ 1 * -1
assert(pattern:match('hello') == 6)
Parameters:
{...} (string)
Return:
(vim.lpeg.Pattern)
vim.lpeg.S(
Returns a pattern that matches any single character that appears in the
given string (the {string})vim.lpeg.S()S stands for Set). As an example, the pattern
lpeg.S('+-*/') matches any arithmetic operator. Note that, if s is a
character (that is, a string of length 1), then lpeg.P(s) is equivalent
to lpeg.S(s) which is equivalent to lpeg.R(s..s). Note also that both
lpeg.S('') and lpeg.R() are patterns that always fail.
Parameters:
{string} (string)
Return:
(vim.lpeg.Pattern)
vim.lpeg.setmaxstack(
Sets a limit for the size of the backtrack stack used by LPeg to track
calls and choices. The default limit is {max})vim.lpeg.setmaxstack()400. Most well-written patterns
need little backtrack levels and therefore you seldom need to change this
limit; before changing it you should try to rewrite your pattern to avoid
the need for extra space. Nevertheless, a few useful patterns may
overflow. Also, with recursive grammars, subjects with deep recursion may
also need larger limits.
Parameters:
{max} (integer)
vim.lpeg.type(
Returns the string {value})vim.lpeg.type()"pattern" if the given value is a pattern, otherwise
nil.
Parameters:
{value} (vim.lpeg.Pattern|string|integer|boolean|table|function)
Return:
("pattern"?)
vim.lpeg.V(
Creates a non-terminal (a variable) for a grammar. This operation creates
a non-terminal (a variable) for a grammar. The created non-terminal refers
to the rule indexed by {v})vim.lpeg.V()v in the enclosing grammar.
Example:
local b = lpeg.P({'(' * ((1 - lpeg.S '()') + lpeg.V(1)) ^ 0 * ')'})
assert(b:match('((string))') == 11)
assert(b:match('(') == nil)
Parameters:
{v} (boolean|string|number|function|table|thread|userdata|lightuserdata)
Return:
(vim.lpeg.Pattern)
vim.lpeg.version()vim.lpeg.version()
Returns a string with the running version of LPeg.
Return:
(string)
Lua module: vim.mpack
This module provides encoding and decoding of Lua objects to and from
msgpack-encoded strings. Supports vim.NIL and vim.empty_dict().
vim.mpack.decode(
Decodes (or "unpacks") the msgpack-encoded {str})vim.mpack.decode(){str} to a Lua object.
Parameters:
{str} (string)
Return:
(any)
vim.mpack.encode(
Encodes (or "packs") Lua object {obj})vim.mpack.encode(){obj} as msgpack in a Lua string.
Parameters:
{obj} (any)
Return:
(string)
Lua module: vim.net
vim.net.request.Responsevim.net.request.Response
Fields:
{body} (string) The HTTP body of the request
Makes an HTTP request to the given URL, asynchronously passing the result
to the specified
on_response, outpath or outbuf.
Examples:
-- Write response body to file.
vim.net.request('https://neovim.io/charter/', {
outpath = 'vision.html',
})
-- Process the response.
vim.net.request(
'https://api.github.com/repos/neovim/neovim',
{},
function (err, res)
if err then return end
local stars = vim.json.decode(res.body).stargazers_count
vim.print(('Neovim currently has %d stars'):format(stars))
end
)
-- Write to both file and current buffer, but cancel it.
local job = vim.net.request('https://neovim.io/charter/', {
outpath = 'vision.html',
outbuf = 0,
})
job:close()
-- Await the response in a task (|lua-async|). Closing the task cancels the request.
vim.async.run(function()
local err, res = vim.async.await(3, vim.net.request, 'https://neovim.io/charter/', {})
end)
-- Add custom headers in the request.
vim.net.request('https://neovim.io/charter/', {
headers = { Authorization = 'Bearer XYZ' },
})
-- POST request with body.
vim.net.request('POST', 'https://example.com/api', {
body = '{"key": "value"}',
headers = {['Content-Type'] = 'application/json' }
})
Parameters:
{method} (vim.net.HttpMethod) (default: GET) The HTTP method
(GET, POST, PUT, PATCH, HEAD, DELETE).
{url} (string) The URL for the request.
{opts} (table?) A table with the following fields:
{body}? (string) Request body for POST/PUT/PATCH
requests.
{headers}? (table<string, string>) Custom headers
to send with the request. Supports basic key/value
headers and empty headers as supported by curl. Does
not support "@filename" style, internal header
deletion ("Header:").
{outbuf}? (integer) Buffer to save the response
body to.
{outpath}? (string) File path to save the response
body to.
{retry}? (integer) Number of retries on transient
failures (default: 3).
{verbose}? (boolean) Enables verbose output.
{on_response} (vim.net.request.ResponseFunc?) Callback invoked on
request completion.
Overloads:
fun(url: string, opts: vim.net.request.Opts, response: vim.net.request.ResponseFunc)
fun(method: vim.net.HttpMethod, url: string, opts: vim.net.request.Opts, response: vim.net.request.ResponseFunc)
Return:
(vim.async.Closable) Cancels the request or checks its status.
Lua module: vim.pos
EXPERIMENTAL: This API is unstable, do not use it. Its semantics are not yet
finalized. Subscribe to this issue to stay updated:
https://github.com/neovim/neovim/issues/25509
Provides operations to compare, calculate, and convert positions represented
by vim.Pos objects.
vim.Posvim.Pos
Represents a buffer position based on api-indexing (0-indexed,
end-exclusive ranges). Call vim.pos() to create a new vim.Pos by
passing the {buf}, {row}, and {col} of a position.
Example:
local pos1 = vim.pos(0, 3, 5)
local pos2 = vim.pos(0, 4, 0)
-- Operators are overloaded for comparing two `vim.Pos` objects.
if pos1 < pos2 then
print("pos1 comes before pos2")
end
if pos1 ~= pos2 then
print("pos1 and pos2 are different positions")
end
It may include optional fields that enable additional capabilities, such
as format conversions.
Fields:
{buf} (integer) buffer handle.
{col} (integer) 0-based byte index.
{row} (integer) 0-based byte index.
If
{pos} is omitted, the first argument is treated as {win} instead of
{buf}, and the current cursor position of {win} is used. If {win} is also
omitted, it defaults to the current window.
Example:
local buf = vim.api.nvim_win_get_buf(0)
local cursor_pos = vim.api.nvim_win_get_cursor(0)
local pos = vim.pos.cursor(buf, cursor_pos)
-- This is equivalent:
local pos = vim.pos.cursor(0)
Parameters:
{buf} (integer)
{pos} ([integer, integer]) (lnum, col) tuple
Overloads:
fun(win?: integer): vim.Pos
Return:
(vim.Pos)
Creates a new vim.Pos from extmark position (see api-indexing).
Example:
local pos = vim.pos.extmark(0, 3, 5)
Parameters:
{buf} (integer)
{row} (integer)
{col} (integer)
Return:
(vim.Pos)
Example:
local lsp_pos = {
line = 3,
character = 5
}
local pos = vim.pos.lsp(0, lsp_pos, 'utf-16')
Parameters:
{buf} (integer)
{pos} (lsp.Position)
{position_encoding} (lsp.PositionEncodingKind)
Return:
(vim.Pos)
Creates a new vim.Pos from mark position (see api-indexing).
Example:
local mark_info = vim.api.nvim_get_mark('M')
local lnum, col, buf, name = unpack(mark_info)
if lnum == 0 and col == 0 and buf == 0 then
return -- mark 'M' is not set.
end
local pos = vim.pos.mark(buf, lnum, col)
Parameters:
{buf} (integer)
{lnum} (integer)
{col} (integer)
Return:
(vim.Pos)
Creates a new vim.Pos from buffer (bytes) offset.
Example:
local offset = vim.api.nvim_buf_get_offset(0, vim.api.nvim_buf_line_count(0))
local pos = vim.pos.offset(0, offset)
Parameters:
{buf} (integer)
{offset} (integer)
Return:
(vim.Pos)
Example:
local pos = vim.pos(0, 3, 5)
-- Convert to cursor position, you can call it in a method style.
local cursor_pos = pos:to_cursor()
vim.api.nvim_win_set_cursor(0, cursor_pos)
Parameters:
{pos} (vim.Pos)
Return:
([integer, integer]) (lnum, col) tuple
Example:
local pos = vim.pos(0, 3, 5)
-- Convert to extmark position, you can call it in a method style.
local extmark_pos = pos:to_extmark()
Parameters:
{pos} (vim.Pos)
Return (multiple):
(integer) row
(integer) col
Example:
local pos = vim.pos(0, 3, 5)
-- Convert to LSP position, you can call it in a method style.
local lsp_pos = pos:to_lsp('utf-16')
Parameters:
{pos} (vim.Pos)
{position_encoding} (lsp.PositionEncodingKind)
Return:
(lsp.Position)
Example:
local pos = vim.pos(0, 3, 5)
-- Convert to mark position, you can call it in a method style.
local lnum, col = pos:to_mark()
vim.api.nvim_buf_set_mark(0, 'M', lnum, col)
Parameters:
{pos} (vim.Pos)
Return (multiple):
(integer) lnum
(integer) col
to_offset(
Converts vim.Pos to buffer (bytes) offset.
{pos})vim.pos.to_offset()
Example:
local p1 = vim.pos(0, 3, 5)
local p2 = vim.pos(0, 4, 0)
-- Convert to buffer offset, you can call it in a method style.
local offset1 = p1:to_offset()
local offset2 = p2:to_offset()
-- Can be used to calculate the distance between two locations.
local distance = offset2 - offset1
Parameters:
{pos} (vim.Pos)
Return:
(integer)
Lua module: vim.range
EXPERIMENTAL: This API is unstable, do not use it. Its semantics are not yet
finalized. Subscribe to this issue to stay updated:
https://github.com/neovim/neovim/issues/25509
Provides operations to compare, calculate, and convert ranges represented by
vim.Range objects.
vim.Rangevim.Range
Represents a range based on api-indexing (0-indexed, end-exclusive).
Call vim.range() to create a new range by passing start and end
positions (vim.Pos).
Both positions must have the same optional fields, which may enable
additional capabilities (such as format conversions).
Example:
local pos1 = vim.pos(0, 3, 5)
local pos2 = vim.pos(0, 4, 0)
-- Create a range from two positions.
local range1 = vim.range(pos1, pos2)
-- Or create a range from four integers representing start and end positions.
local range2 = vim.range(0, 3, 5, 4, 0)
-- Because `vim.Range` is end exclusive, `range1` and `range2` both represent
-- a range starting at the row 3, column 5 and ending at where the row 3 ends
-- (including the newline at the end of line 3).
-- Operators are overloaded for comparing two `vim.Pos` objects.
if range1 == range2 then
print("range1 and range2 are the same range")
end
Fields:
{buf} (integer) Optional buffer handle.
{end_col} (integer) 0-based byte index.
{end_row} (integer) 0-based byte index.
{start_col} (integer) 0-based byte index.
{start_row} (integer) 0-based byte index.
Creates a new vim.Range from extmark range (see api-indexing).
Example:
local range = vim.range.extmark(0, 3, 5, 4, 0)
Parameters:
{buf} (integer)
{start_row} (integer)
{start_col} (integer)
{end_row} (integer)
{end_col} (integer)
Return:
(vim.Range)
Checks whether
{outer} range contains {inner} range or position.
Parameters:
{outer} (vim.Range)
{inner} (vim.Range|vim.Pos)
Return:
(boolean) true if {outer} range fully contains {inner} range or
position.
Computes the common range shared by the given ranges.
Parameters:
{r1} (vim.Range) First range to intersect.
{r2} (vim.Range) Second range to intersect
Return:
(vim.Range?) range that is present inside both r1 and r2. nil
if such range does not exist.
is_empty(
Checks whether the given range is empty; i.e., start >= end.
{range})vim.range.is_empty()Parameters:
{range} (vim.Range)
Return:
(boolean) true if the given range is empty.
Example:
local lsp_range = {
['start'] = { line = 3, character = 5 },
['end'] = { line = 4, character = 0 }
}
local range = vim.range.lsp(0, lsp_range, 'utf-16')
Parameters:
{buf} (integer)
{range} (lsp.Range)
{position_encoding} (lsp.PositionEncodingKind)
Return:
(vim.Range)
Creates a new vim.Range from "mark-indexed" range (see api-indexing).
Example:
-- A range represented by marks may be end-inclusive (decided by 'selection' option).
local start_lnum, start_col = unpack(api.nvim_buf_get_mark(bufnr, '<'))
local end_lnum, end_col = unpack(api.nvim_buf_get_mark(bufnr, '>'))
-- Create an end-exclusive range.
local range = vim.range.mark(0, start_lnum, start_col, end_lnum, end_col)
Parameters:
{buf} (integer)
{start_lnum} (integer)
{start_col} (integer)
{end_lnum} (integer)
{end_col} (integer)
Return:
(vim.Range)
Example:
local range = vim.range(0, 3, 5, 4, 0)
-- Convert to extmark range, you can call it in a method style.
local extmark_range = range:to_extmark()
Parameters:
{range} (vim.Range)
Return (multiple):
(integer) start_row
(integer) start_col
(integer) end_row
(integer) end_col
Example:
local range = vim.range(0, 3, 5, 4, 0)
-- Convert to LSP range, you can call it in a method style.
local lsp_range = range:to_lsp('utf-16')
Parameters:
{range} (vim.Range)
{position_encoding} (lsp.PositionEncodingKind)
Return:
(lsp.Range)
Example:
local range = vim.range(0, 3, 5, 4, 0)
-- Convert to mark range, you can call it in a method style.
local start_lnum, start_col, end_lnum, end_col = range:to_mark()
Parameters:
{range} (vim.Range)
Return (multiple):
(integer) start_lnum
(integer) start_col
(integer) end_lnum
(integer) end_col
Lua module: vim.re
The
vim.re module provides a conventional regex-like syntax for pattern
usage within LPeg vim.lpeg. (Unrelated to vim.regex which provides Vim
regexp from Lua.)
See https://www.inf.puc-rio.br/~roberto/lpeg/re.html for the original
documentation including regex syntax and examples.
Compiles the given
{string} and returns an equivalent LPeg pattern. The
given string may define either an expression or a grammar. The optional
{defs} table provides extra Lua values to be used by the pattern.
Parameters:
{string} (string)
{defs} (table?)
Return:
(vim.lpeg.Pattern)
Searches the given
{pattern} in the given {subject}. If it finds a match,
returns the index where this occurrence starts and the index where it
ends. Otherwise, returns nil.
An optional numeric argument
{init} makes the search starts at that
position in the subject string. As usual in Lua libraries, a negative
value counts from the end.
Parameters:
{subject} (string)
{pattern} (vim.lpeg.Pattern|string)
{init} (integer?)
Return (multiple):
(integer?) the index where the occurrence starts, nil if no match
(integer?) the index where the occurrence ends, nil if no match
Does a global substitution, replacing all occurrences of
{pattern} in the
given {subject} by {replacement}.
Parameters:
{subject} (string)
{pattern} (vim.lpeg.Pattern|string)
{replacement} (string)
Return:
(string)
Matches the given
{pattern} against the given {subject}, returning all
captures.
Parameters:
{subject} (string)
{pattern} (vim.lpeg.Pattern|string)
{init} (integer?)
Return:
(integer|vim.lpeg.Capture?)
See also:
vim.lpeg.match()
vim.re.updatelocale()vim.re.updatelocale()
Updates the pre-defined character classes to the current locale.
Lua module: vim.regex
The
vim.regex interface allows Lua code to use Vim regexes.
Matches within a single line.
Does not check for interrupts (
CTRL-C), so can be used from an api-fast
context.
Matches line at
line_idx (zero-based) in buffer buf. Match is
restricted to byte index range start and end_ if given, otherwise see
regex:match_str(). Returned byte indices are relative to start if
given.
Parameters:
{buf} (integer)
{line_idx} (integer)
{start} (integer?)
{end_} (integer?)
Return (multiple):
(integer?) match start (byte index) relative to start, or nil if
no match
(integer?) match end (byte index) relative to start, or nil if
no match
regex:match_str(
Matches string {str})regex:match_str()str against this regex. To match the string precisely,
surround the regex with "^" and "$". Returns the byte indices for the
start and end of the match, or nil if there is no match. Because any
integer is "truthy", regex:match_str() can be directly used as a
condition in an if-statement.
Parameters:
{str} (string)
Return (multiple):
(integer?) match start (byte index), or nil if no match
(integer?) match end (byte index), or nil if no match
vim.regex(
Parses the Vim regex {re})vim.regex()re and returns a regex object. Regexes are "magic"
and case-sensitive by default, regardless of 'magic' and 'ignorecase'.
They can be controlled with flags, see /magic and /ignorecase.
Parameters:
{re} (string)
Return:
(vim.regex)
Lua module: vim.secure
vim.secure.read(
If {path})vim.secure.read(){path} is a file: attempt to read the file, prompting the user if the
file should be trusted.
If
{path} is a directory: return true if the directory is trusted
(non-recursive), prompting the user as necessary.
The user's choice is persisted in a trust database at
$XDG_STATE_HOME/nvim/trust.
Attributes:
Since: 0.9.0
Parameters:
{path} (string) Path to a file or directory to read.
Return:
(boolean|string?) If {path} is not trusted or does not exist,
returns nil. Otherwise, returns the contents of {path} if it is a
file, or true if {path} is a directory.
See also:
vim.secure.trust(
Manage the trust database.
{opts})vim.secure.trust()
The trust database is located at $XDG_STATE_HOME/nvim/trust.
Attributes:
Since: 0.9.0
Parameters:
{opts} (table) A table with the following fields:
{action} ('allow'|'deny'|'remove') One of:
'allow' to add a file to the trust database and trust
it,
'deny' to add a file to the trust database and deny it,
'remove' to remove file from the trust database
{bufnr}? (integer) Buffer number to update. Mutually
exclusive with {path}.
{path}? (string) Path to a file to update. Mutually
exclusive with {bufnr}.
Return (multiple):
(boolean) success true if operation was successful
(string) msg full path if operation was successful, else error
message
Lua module: vim.snippet
Snippet expansion and navigation.
Internal autocmds live in the
nvim.snippet augroup. To disable them (e.g. to
manage sessions yourself), clear it:vim.api.nvim_clear_autocmds({ group = 'nvim.snippet', buffer = 0 })
Heads-up: vim.snippet.jump() re-registers them on every jump.
vim.snippet.ActiveFiltervim.snippet.ActiveFilter
Fields:
{direction} (vim.snippet.Direction) Navigation direction. -1 for
previous, 1 for next.
vim.snippet.active(
Returns {filter})vim.snippet.active()true if there's an active snippet in the current buffer,
applying the given filter if provided.
Parameters:
{filter} (vim.snippet.ActiveFilter?) Filter to constrain the search
with:
direction (vim.snippet.Direction): Navigation direction.
Will return true if the snippet can be jumped in the
given direction.
Return:
(boolean)
vim.snippet.expand(
Expands the given snippet text. Refer to
https://microsoft.github.io/language-server-protocol/specification/#snippet_syntax
for the specification of valid input.
{input})vim.snippet.expand()
Tabstops are highlighted with hl-SnippetTabstop and
hl-SnippetTabstopActive.
Parameters:
{input} (string)
vim.snippet.jump(
Jumps to the next (or previous) placeholder in the current snippet, if
possible.
{direction})vim.snippet.jump()
By default
<Tab> is setup to jump if a snippet is active. The default
mapping looks like:vim.keymap.set({ 'i', 's' }, '<Tab>', function()
if vim.snippet.active({ direction = 1 }) then
return '<Cmd>lua vim.snippet.jump(1)<CR>'
else
return '<Tab>'
end
end, { desc = '...', expr = true, silent = true })
Parameters:
{direction} (vim.snippet.Direction) Navigation direction. -1 for
previous, 1 for next.
vim.snippet.stop()vim.snippet.stop()
Exits the current snippet.
Lua module: vim.spell
vim.spell.check(
Check {str})vim.spell.check(){str} for spelling errors. Similar to the Vimscript function
spellbadword().
Note: The behaviour of this function is dependent on: 'spelllang',
'spellfile', 'spellcapcheck' and 'spelloptions' which can all be local to
the buffer. Consider calling this with nvim_buf_call().
Example:
vim.spell.check("the quik brown fox")
-- =>
-- {
-- {'quik', 'bad', 5}
-- }
Parameters:
{str} (string)
Return:
([string, 'bad'|'rare'|'local'|'caps', integer][]) List of tuples
with three items:
The badly spelled word.
The type of the spelling error: "bad" spelling mistake "rare" rare
word "local" word only valid in another region "caps" word should
start with Capital
The position in
{str} where the word begins.
Lua module: vim.system
vim.SystemCompletedvim.SystemCompleted
Fields:
{code} (integer)
{signal} (integer)
{stderr}? (string) nil if stderr is disabled or has a custom
handler.
{stdout}? (string) nil if stdout is disabled or has a custom
handler.
vim.SystemObjvim.SystemObj
Fields:
{cmd} (string[]) Command name and args
{pid} (integer) Process ID
{wait} (fun(self: vim.SystemObj, timeout: integer?, cond: fun(stdout: string, stderr: string): boolean?): vim.SystemCompleted)
See SystemObj:wait().
SystemObj:close(
Stops the process (SIGTERM, escalates to SIGKILL after 2s). On
process-exit, closes its output pipes without waiting for EOF (see
{on_close})SystemObj:close()on_exit), and calls on_close. Implements vim.async.Closable, so
closing a task that awaits vim.system() stops the process.
Example:
local task = vim.async.run(function()
return vim.async.await(3, vim.system, { 'sleep', '10' }, {})
end)
task:close() -- Stops `sleep`.
Parameters:
{on_close} (fun()?)
SystemObj:is_closing()SystemObj:is_closing()
Checks if the process handle is closing or already closed.
This method returns
true if the underlying process handle is either
nil or is in the process of closing. It is useful for determining
whether it is safe to perform operations on the process handle.
Return:
(boolean)
SystemObj:kill(
Sends a signal to the process.
{signal})SystemObj:kill()
The signal can be specified as an integer or as a string.
Example:
local obj = vim.system({'sleep', '10'})
obj:kill('sigterm') -- sends SIGTERM to the process
Parameters:
Waits for the process to complete, and stops it on timeout or
CTRL-C.
Blocks until the process exits and its output pipes close, or until
timeout (ms) or CTRL-C. If timeout is not given it defaults to
opts.timeout, else waits indefinitely.
On timeout:
Stops the process (SystemObj:close()) if it is running, and sets exit
code 124.
Waits for process exit (max 2s, escalates to SIGKILL), but not its
output pipes (a descendant may inherit them and keep them open, e.g. a
browser started by
xdg-open).
Returns the output collected so far.
On
CTRL-C:
Stops the process (see above).
Raises error "interrupted".
Example:
local obj = vim.system({'echo', 'hello'}, { text = true })
local result = obj:wait(1000) -- waits up to 1000ms
print(result.code, result.signal, result.stdout, result.stderr)
-- Monitor a long-lived process that prints "READY".
local result = vim.system({ 'ssh', '-L', … }):wait(nil, function(stdout)
return stdout:find('READY') ~= nil
end)
Parameters:
{timeout} (integer?) Wait duration (ms).
{cond} (fun(stdout: string, stderr: string): boolean?) Stops
waiting when it returns true, without terminating the
process. The stdout and stderr args have the
accumulated output so far. The result has no code or
signal.
Return:
(vim.SystemCompleted)
SystemObj:write(
Writes data to the stdin of the process or closes stdin.
{data})SystemObj:write()
If
data is a list of strings, each string is written followed by a
newline.
If
data is a string, it is written as-is.
If
data is nil, the write side of the stream is shut down and the pipe
is closed.
Example:
local obj = vim.system({'cat'}, { stdin = true })
obj:write({'hello', 'world'}) -- writes 'hello\nworld\n' to stdin
obj:write(nil) -- closes stdin
Parameters:
{data} (string[]|string?)
Runs a system command or throws an error if
{cmd} cannot be run.
The command runs directly (not in 'shell') so shell builtins such as
"echo" in cmd.exe, cmdlets in powershell, or "help" in bash, will not work
unless you actually invoke a shell:
vim.system({'bash', '-c', 'help'}).
Examples:
local on_exit = function(obj)
print(obj.code)
print(obj.signal)
print(obj.stdout)
print(obj.stderr)
end
-- Runs asynchronously:
vim.system({'echo', 'hello'}, { text = true }, on_exit)
-- Runs synchronously:
local obj = vim.system({'echo', 'hello'}, { text = true }):wait()
-- { code = 0, signal = 0, stdout = 'hello\n', stderr = '' }
See uv.spawn() for more details. Note: unlike uv.spawn(), vim.system
throws an error if
{cmd} cannot be run.
Parameters:
{cmd} (string[]) Command to execute
{opts} (table?) A table with the following fields:
{clear_env}? (boolean) env defines the job
environment exactly, instead of merging current
environment. Note: if env is nil, the current
environment is used but without NVIM set.
{cwd}? (string) Set the current working directory for
the sub-process.
{detach}? (boolean) Spawn the child process in a
detached state - this will make it a process group
leader, and will effectively enable the child to keep
running after the parent exits. Note that the child
process will still keep the parent's event loop alive
unless the parent process calls uv.unref() on the
child's process handle.
{env}? (table<string,string|number>) Set environment
variables for the new process. Inherits the current
environment with NVIM set to v:servername.
{stderr}? (fun(err:string?, data: string?)|boolean,
default: true) Handle output from stderr.
{stdin}? (string|string[]|true) If true, then a pipe
to stdin is opened and can be written to via the
write() method to SystemObj. If string or string[]
then will be written to stdin and closed.
{stdout}? (fun(err:string?, data: string?)|boolean,
default: true) Handle output from stdout.
{text}? (boolean) Handle stdout and stderr as text.
Normalizes line endings by replacing \r\n with \n.
{timeout}? (integer) Run the command with a time limit
(ms). Upon timeout the process is stopped
(SystemObj:close()) and exit code is 124.
{on_exit} (fun(out: vim.SystemCompleted)?) Called with the result
on process exit and output pipes closed. Delayed (possibly
indefinitely) if a descendant process inherits the pipes
and does not close them (e.g. cmd & in a shell script).
Note that SystemObj:close() closes pipes, thus ensuring
on_exit is called.
Overloads:
fun(cmd: string[], on_exit: fun(out: vim.SystemCompleted)): vim.SystemObj
Return:
(vim.SystemObj)
Lua module: vim.text
Run diff on strings
{a} and {b}. Any indices returned by this function,
either directly or via callback arguments, are 1-based.
Examples:
vim.text.diff('a\n', 'b\nc\n')
-- =>
-- @@ -1 +1,2 @@
-- -a
-- +b
-- +c
vim.text.diff('a\n', 'b\nc\n', {result_type = 'indices'})
-- =>
-- {
-- {1, 1, 1, 2}
-- }
Parameters:
{a} (string) First string to compare
{b} (string) Second string to compare
{opts} (table?) Optional parameters:
{algorithm}? ('myers'|'minimal'|'patience'|'histogram',
default: 'myers') Diff algorithm to use. Values:
myers: the default algorithm
minimal: spend extra time to generate the smallest
possible diff
patience: patience diff algorithm
histogram: histogram diff algorithm
{ctxlen}? (integer) Context length
{ignore_blank_lines}? (boolean) Ignore blank lines
{ignore_cr_at_eol}? (boolean) Ignore carriage return at
end-of-line
{ignore_whitespace}? (boolean) Ignore whitespace
{ignore_whitespace_change}? (boolean) Ignore whitespace
change
{ignore_whitespace_change_at_eol}? (boolean) Ignore
whitespace change at end-of-line.
{indent_heuristic}? (boolean) Use the indent heuristic for
the internal diff library.
{interhunkctxlen}? (integer) Inter hunk context length
{linematch}? (boolean|integer) Run linematch on the
resulting hunks from xdiff. When integer, only hunks upto
this size in lines are run through linematch. Requires
result_type = indices, ignored otherwise.
{on_hunk}?
(fun(start_a: integer, count_a: integer, start_b: integer, count_b: integer): integer?)
Invoked for each hunk in the diff. Return a negative number
to cancel the callback for any remaining hunks. Arguments:
start_a (integer): Start line of hunk in {a}.
count_a (integer): Hunk size in {a}.
start_b (integer): Start line of hunk in {b}.
count_b (integer): Hunk size in {b}.
{result_type}? ('unified'|'indices', default: 'unified')
Form of the returned diff:
unified: String in unified format.
indices: Array of hunk locations. Note: This option is
ignored if on_hunk is used.
Return:
(string|integer[][]?) See {opts.result_type}. nil if
{opts.on_hunk} is given.
vim.text.hexdecode(
Hex decode a string.
{enc})vim.text.hexdecode()Parameters:
{enc} (string) String to decode
Return (multiple):
(string?) Decoded string
(string?) Error message, if any
vim.text.hexencode(
Hex encode a string.
{str})vim.text.hexencode()Parameters:
{str} (string) String to encode
Return:
(string) Hex encoded string
Sets the indent (i.e. the common leading whitespace) of non-empty lines in
text to size spaces/tabs.
Indent is calculated by number of consecutive indent chars.
The first indented, non-empty line decides the indent char (space/tab):
SPC SPC TAB … = two-space indent.
TAB SPC … = one-tab indent.
Set
opts.expandtab to treat tabs as spaces.
To "dedent" (remove the common indent), pass
size=0:vim.print(vim.text.indent(0, ' a\n b\n'))
To adjust relative-to an existing indent, call indent() twice:
local indented, old_indent = vim.text.indent(0, ' a\n b\n')
indented = vim.text.indent(old_indent + 2, indented)
vim.print(indented)
To ignore the final, blank line when calculating the indent, use gsub()
before calling indent():
local text = ' a\n b\n '
vim.print(vim.text.indent(0, (text:gsub('\n[\t ]+\n?$', '\n'))))
Parameters:
{size} (integer) Number of spaces.
{text} (string) Text to indent.
{opts} ({ expandtab?: integer }?)
Return (multiple):
(string) Indented text.
(integer) Indent size before modification.
Lua module: vim.ui
Prompts the user for input, allowing arbitrary (potentially asynchronous)
work until
on_confirm.
Example:
local opts = { prompt = 'Enter value for shiftwidth: ', scope = 'buffer' }
vim.ui.input(opts, function(input)
vim.o.shiftwidth = tonumber(input)
end)
Parameters:
{completion}? (string) Specifies type of completion
supported for input. Supported types are the same that
can be supplied to a user-defined command using the
"-complete=" argument. See :command-completion
{default}? (string) Default reply to the input
{highlight}? (function) Function that will be used
for highlighting user inputs.
{prompt}? (string) Text of the prompt
{scope}?
('cursor'|'line'|'buffer'|'window'|'tabpage'|'editor'|'project')
Input scope, as in "This input is for something at
cursor/line/etc scope". Can be used by vim.ui.input
implementations to tweak behavior and presentation.
For example, the input may adjust the floating window
position: near the cursor if cursor, in window
corner if buffer or window, etc.
{on_confirm} (fun(input?: string)) Called once the user confirms or
abort the input. input is what the user typed (it
might be an empty string if nothing was entered), or
nil if the user aborted the dialog.
Opens
path with the system default handler (macOS open, Windows
explorer.exe, Linux xdg-open, …), or returns (but does not show) an
error message on failure.
Can also be invoked with
:Open.:Open
Expands "~/" and environment variables in filesystem paths.
Examples:
-- Asynchronous.
vim.ui.open("https://neovim.io/")
vim.ui.open("~/path/to/file")
-- Use the "osurl" command to handle the path or URL.
vim.ui.open("gh#neovim/neovim!29490", { cmd = { 'osurl' } })
-- Synchronous (wait until the process exits).
local cmd, err = vim.ui.open("$VIMRUNTIME")
if cmd then
cmd:wait()
end
Parameters:
{path} (string) Path or URL to open
{opt} (table?) Options
{cmd}? (string[]) Command used to open the path or URL.
Return (multiple):
(vim.SystemObj?) Command object, or nil if not found.
(string?) Error message on failure, or nil on success.
See also:
vim.ui.progress_status()vim.ui.progress_status()
Gets a status description summarizing currently running progress messages.
Convenient for inclusion in 'statusline'.
Return:
(string) Progress status
Prompts the user to pick from a list of items, allowing arbitrary
(potentially asynchronous) work until
on_choice. This is the standard
"picker" interface, used by z=, :tselect, etc.
Plugins may override
vim.ui.select to provide a custom picker; they are
expected to call the format_item and preview_item handlers (if any)
provided by the caller. They may also use the kind hint (if provided by
the caller) to decide how to handle some items.
Note: the default
vim.ui.select currently doesn't support preview.
Example:
vim.ui.select({ 'tabs', 'spaces' }, {
prompt = 'Select tabs or spaces:',
format_item = function(item)
return ('I choose %s!'):format(item)
end,
preview_item = function(item)
local lines = { 'This is ' .. vim.inspect(item) }
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines)
vim.bo[buf].bufhidden = 'wipe'
return { buf = buf }
end,
}, function(choice)
vim.o.expandtab = choice == 'spaces'
vim.print(('Selected "%s" => expandtab=%s'):format(choice, vim.o.expandtab))
end)
Parameters:
{items} (any[]) Arbitrary items
{opts} (table) Options
{format_item}? (fun(item: any):string, default:
tostring) Decides how to format items when displayed
in the picker.
{kind}? (string) Arbitrary hint string indicating the
item shape. The picker may wish to use this to infer
the structure or semantics of items, or the context
in which select() was called.
{preview_item}?
(fun(item: any):{buf?:integer, pos?:[integer,integer], pos_end?:[integer,integer]})
Decides how to preview an item by preparing a scratch
buffer with the item details (including text,
highlighting, etc.). When the picker decides to
"preview" an item, it should call this function. Must
return a table with these keys:
{buf}? (integer) Buffer containing the previewed
item details, or nil if no preview should be shown.
{pos}? ([integer, integer]) Specifies the
(1,0)-indexed cursor position in the preview buffer.
If nil, should be treated as { 1, 0 }.
{pos_end}? ([integer, integer]) Specifies the
(1,0)-indexed (end-exclusive) end position of the
preview range. If nil, no range is intended for a
preview.
{prompt}? (string, default: "Select one of:")
Prompt text.
{on_choice} (fun(item: T?, idx: integer?)) Called once the user
made a choice. idx is the 1-based index of item
within items, or nil if the user aborted the dialog.
Lua module: vim.ui.img
EXPERIMENTAL: This API may change in the future. Its semantics are not yet
finalized.
This provides a functional API for displaying images in Nvim. Currently
supports PNG images via the Kitty graphics protocol.
To override the image backend, replace
vim.ui.img with your own
implementation providing set/get/del.
Examples:
-- Load image bytes from disk and display at row 5, column 10
local id = vim.ui.img.set(
vim.fn.readblob('/path/to/img.png'),
{ row = 5, col = 10, width = 40, height = 20, zindex = 50 }
)
-- Update the image position
vim.ui.img.set(id, { row = 8, col = 12 })
-- Retrieve the current image opts
local opts = vim.ui.img.get(id)
-- Remove the image
vim.ui.img.del(id)
-- Remove all images
vim.ui.img.del(math.huge)
vim.ui.img.del(
Delete an image, or all images if {id})vim.ui.img.del()math.huge is given as the id.
Parameters:
{id} (integer) image id, or math.huge to delete all images
Return:
(boolean) found true if any image existed
vim.ui.img.get(
Get the opts for an image.
{id})vim.ui.img.get()Parameters:
{id} (integer)
Return:
(table?) opts copy of image opts, or nil if not found
{col}? (integer) starting column (1-indexed)
{height}? (integer) height in cells
{row}? (integer) starting row (1-indexed)
{width}? (integer) width in cells
{zindex}? (integer) stacking order (higher = on top)
Display an image or update an existing one.
When
{data_or_id} is a string, displays the image bytes at the position
given by {opts}. Returns an integer id for later use.
When
{data_or_id} is an integer (a previously returned id), updates the
image with new {opts}.
Parameters:
{data_or_id} (string|integer) image bytes (string) or existing id
(integer)
{opts} (table?) A table with the following fields:
{col}? (integer) starting column (1-indexed)
{height}? (integer) height in cells
{row}? (integer) starting row (1-indexed)
{width}? (integer) width in cells
{zindex}? (integer) stacking order (higher = on top)
Return:
(integer) id
Lua module: vim.uri
vim.Urivim.Uri
URI components (see vim.uri.parse()). tostring() gives the URI as a
string. Can be compared for equality (==):vim.uri.parse('HTTP://h/a') == vim.uri.new({ scheme = 'http', host = 'h', path = '/a' }) --> true
Fields:
{fragment}? (string) Fragment (URI-encoded): "https://h#a%20b" =>
"a%20b".
{host}? (string) Host (lowercase, URI-decoded):
ssh://Me@[::1]:22 => "::1", "https://Example.com" =>
"example.com". Empty for "file:///a", nil for "file:/a".
{password}? (string) Password (URI-decoded):
"https://u:p%40ss@host" => "p@ss".
{path} (string) Path (URI-encoded): "https://h/a%20b" =>
"/a%20b". Empty for "https://h".
{port}? (integer) Port: "https://example.com:8080" => 8080.
{query}? (table<string, string|string[]>) Query (decoded by
vim.uri.decode_query()): "https://h?q=a+b" =>
{ q = "a b" }.
{querystr}? (string) Querystring (URI-encoded): "https://h?q=a+b"
=> "q=a+b". Takes precedence over query in
tostring().
{scheme} (string) Scheme (lowercase): "HTTPS://example.com" =>
"https".
{user}? (string) User (URI-decoded): "ssh://a%40b@host" =>
"a@b".
vim.uri.decode(
Decodes a URI-encoded string. (Use vim.uri.parse() to get the structured
form.)
{str})vim.uri.decode()Attributes:
Since: 0.13.0
Parameters:
{str} (string) URI-encoded string.
Return:
(string) Decoded string.
vim.uri.decode_query(
Decodes a querystring ({query})vim.uri.decode_query()application/x-www-form-urlencoded, as HTML forms
send it): "+" is space, and a repeated key gives a list.
Example:
vim.uri.decode_query('q=a+b%26c&tag=x&tag=y&flag')
--> { q = 'a b&c', tag = { 'x', 'y' }, flag = '' }
Attributes:
Since: 0.13.0
Parameters:
{query} (string?) Querystring, e.g. a form body.
Return:
(table<string, string|string[]>)
URI-encodes (percent-encodes) a string. For a querystring, use
vim.uri.encode_query().
Example:
vim.uri.encode('/a b?') --> '/a%20b%3f'
vim.uri.encode('/a b?', 'rfc2396') --> '%2fa%20b%3f'
Attributes:
Since: 0.13.0
Parameters:
{str} (string) Arbitrary string.
{rfc} ("rfc2396"|"rfc2732"|"rfc3986"?) Chars to keep:
"rfc2396": only
A-Za-z0-9-_.!~*'().
"rfc2732": "rfc2396" plus
[ and ].
"rfc3986" (default): those valid in a path, e.g. "/", ":",
"@", "&", "=".
Return:
(string) URI-encoded string.
vim.uri.encode_query(
Encodes {params})vim.uri.encode_query()params as a querystring (application/x-www-form-urlencoded, as
HTML forms send it): space is "+", and a list value repeats its key. Sorts
the keys.
Example:
vim.uri.encode_query({ q = 'a b&c', tag = { 'x', 'y' }, n = 1 })
--> 'n=1&q=a+b%26c&tag=x&tag=y'
Attributes:
Since: 0.13.0
Parameters:
{params} (table<string, string|number|boolean|(string|number|boolean)[]>)
Return:
(string)
vim.uri.from_buf(
Gets a URI from a buffer.
{buf})vim.uri.from_buf()Attributes:
Since: 0.13.0
Parameters:
{buf} (integer)
Return:
(string) URI
vim.uri.from_fname(
Gets a URI from a file path, or returns {path})vim.uri.from_fname()path if already a URI. Relative
paths are resolved to current-directory (RFC 8089 disallows relative
URIs).
Example:
vim.uri.from_fname('/a b/c#') --> 'file:///a%20b/c%23'
vim.uri.from_fname('C:\\a\\b') --> 'file:///C:/a/b'
vim.uri.from_fname('//server/share/a') --> 'file://server/share/a' (UNC)
vim.uri.from_fname('a') --> 'file:///home/user/a' (if CWD is "/home/user")
vim.uri.from_fname('jdt://a/b') --> 'jdt://a/b'
Attributes:
Since: 0.13.0
Parameters:
{path} (string) Path to file
Return:
(string) URI
Appends path segments to the path of
base, like vim.fs.joinpath(), and
removes "." and ".." segments, but never above the root or a Windows drive
letter. Each segment is URI-encoded, so "#" or "?" in a file name is part
of the path.
Example:
tostring(vim.uri.join('file:///home/u/proj', 'src', 'a#1.lua'))
--> 'file:///home/u/proj/src/a%231.lua'
tostring(vim.uri.join('file:///C:/a', '../../x')) --> 'file:///C:/x'
tostring(vim.uri.join('https://h/api/?v=1', 'users/')) --> 'https://h/api/users/?v=1'
vim.uri.join('file:///a', 'file:///b') --> error: a segment can't be a URI
Attributes:
Since: 0.13.0
Parameters:
{base} (string|vim.Uri)
{...} (string) Path segments (not URI-encoded), not URIs.
Return:
(vim.Uri)
vim.uri.new(
Creates a vim.Uri from components.
{uri})vim.uri.new()
Example:
tostring(vim.uri.new({ scheme = 'https', host = '::1', port = 8080, path = '/a' }))
--> 'https://[::1]:8080/a'
tostring(vim.uri.new({ scheme = 'https', host = 'h', path = '/s', query = { q = 'a b' } }))
--> 'https://h/s?q=a+b'
Attributes:
Since: 0.13.0
Parameters:
{uri} (vim.Uri) path defaults to "".
Return:
(vim.Uri)
vim.uri.normalize(
Normalizes {uri})vim.uri.normalize()uri (RFC 3986 6), so equivalent URIs are equal (==).
Besides the normalizations of vim.uri.parse() and tostring(), it
normalizes percent-encoding, removes "." and ".." segments, and drops a
default port.
Example:
tostring(vim.uri.normalize('HTTPS://Example.COM:443/a/./b/../%7e%2f'))
--> 'https://example.com/a/~%2F'
vim.uri.normalize('HTTP://h:80') == vim.uri.normalize('http://h/') --> true
Attributes:
Since: 0.13.0
Parameters:
{uri} (string|vim.Uri)
Return:
(vim.Uri)
vim.uri.parse(
Parses a URI into its RFC 3986 components. Exception: a one-letter scheme
is a drive letter, "C:/a" is not a URI.
{uri})vim.uri.parse()
Example:
vim.uri.parse('https://u:p%40ss@example.com:80/a%20b?q=1#section')
--> { scheme = 'https', user = 'u', password = 'p@ss', host = 'example.com', port = 80,
path = '/a%20b', query = { q = '1' }, querystr = 'q=1', fragment = 'section' }
vim.uri.parse('/a/b') --> nil
vim.uri.parse('C:/a') --> nil
vim.uri.parse('https://h:x') --> nil
-- tostring() builds the URI from the fields.
local u = vim.uri.parse('https://example.com/a')
u.host, u.port = '::1', 8080
tostring(u) --> 'https://[::1]:8080/a'
Attributes:
Since: 0.13.0
Parameters:
{uri} (string)
Return:
(vim.Uri?) URI components, or nil if invalid.
vim.uri.to_buf(
Gets the buffer for a uri. Creates a new unloaded buffer if no buffer for
the uri already exists.
{uri})vim.uri.to_buf()Attributes:
Since: 0.13.0
Parameters:
{uri} (string|vim.Uri)
Return:
(integer) buf
vim.uri.to_fname(
Gets a filename from a URI. Drops the query and fragment, so "?" and "#"
in a filename must be percent-encoded.
{uri})vim.uri.to_fname()
Example:
vim.uri.to_fname('file:///a%3Fb?c#d') --> '/a?b'
vim.uri.to_fname('file:///C:/a/b') --> 'C:/a/b'
vim.uri.to_fname('file://server/share/a') --> '//server/share/a'
vim.uri.to_fname('jdt://a/b') --> 'jdt://a/b'
Attributes:
Since: 0.13.0
Parameters:
{uri} (string|vim.Uri)
Return:
(string) filename or unchanged URI for non-file URIs
Lua module: vim.version
The
vim.version module provides functions for comparing versions and ranges
conforming to the https://semver.org spec. Plugins, and plugin managers, can
use this to check available tools and dependencies on the current system.
Example:
local v = vim.version.parse(vim.system({'tmux', '-V'}):wait().stdout, {strict=false})
if vim.version.gt(v, {3, 2, 0}) then
-- ...
end
vim.version() returns the version of the current Nvim process.
VERSION RANGE SPEC
A version "range spec" defines a semantic version range which can be tested
against a version, using vim.version.range().
Supported range specs are shown in the following table. Note: suffixed
versions (1.2.3-rc1) are not matched.
1.2.3 is 1.2.3 =1.2.3 is 1.2.3 >1.2.3 greater than 1.2.3 <1.2.3 before 1.2.3 >=1.2.3 at least 1.2.3 <=1.2.3 at most 1.2.3 ~1.2.3 is >=1.2.3 <1.3.0 "reasonably close to 1.2.3" ^1.2.3 is >=1.2.3 <2.0.0 "compatible with 1.2.3" ^0.2.3 is >=0.2.3 <0.3.0 (0.x.x is special) ^0.0.1 is =0.0.1 (0.0.x is special) ^1.2 is >=1.2.0 <2.0.0 (like ^1.2.0) ~1.2 is >=1.2.0 <1.3.0 (like ~1.2.0) ^1 is >=1.0.0 <2.0.0 "compatible with 1" ~1 same "reasonably close to 1" 1.x same 1.* same 1 same * any version x same 1.2.3 - 2.3.4 is >=1.2.3 <2.3.4 Partial right: missing pieces treated as x (2.3 => 2.3.x). 1.2.3 - 2.3 is >=1.2.3 <2.4.0 1.2.3 - 2 is >=1.2.3 <3.0.0 Partial left: missing pieces treated as 0 (1.2 => 1.2.0). 1.2 - 2.3.0 is 1.2.0 - 2.3.0
vim.VersionRangevim.VersionRange
Fields:
{from} (vim.Version)
{to}? (vim.Version)
VersionRange:has(
Check if a version is in the range (inclusive {version})VersionRange:has()from, exclusive to).
Example:
local r = vim.version.range('1.0.0 - 2.0.0')
print(r:has('1.9.9')) -- true
print(r:has('2.0.0')) -- false
print(r:has(vim.version())) -- check against current Nvim version
Or use cmp(), le(), lt(), ge(), gt(), and/or eq() to compare a version
against
.to and .from directly:local r = vim.version.range('1.0.0 - 2.0.0') -- >=1.0, <2.0
print(vim.version.ge({1,0,3}, r.from) and vim.version.lt({1,0,3}, r.to))
Attributes:
Since: 0.9.0
Parameters:
{version} (string|vim.Version)
Return:
(boolean)
vim.version()vim.version()
Returns the current Nvim version.
Return:
(vim.Version)
Parses and compares two version objects (the result of
vim.version.parse(), or specified literally as a
{major, minor, patch}
tuple, e.g. {1, 0, 3}).
Example:
if vim.version.cmp({1,0,3}, {0,2,1}) == 0 then
-- ...
end
local v1 = vim.version.parse('1.0.3-pre')
local v2 = vim.version.parse('0.2.1')
if vim.version.cmp(v1, v2) == 0 then
-- ...
end
Note:
Per semver, build metadata is ignored when comparing two
otherwise-equivalent versions.
Attributes:
Since: 0.9.0
Parameters:
{v1} (vim.Version|number[]|string) Version object.
{v2} (vim.Version|number[]|string) Version to compare with v1.
Return:
(integer) -1 if v1 < v2, 0 if v1 == v2, 1 if v1 > v2.
Returns
true if the given versions are equal. See vim.version.cmp()
for usage.
Attributes:
Since: 0.9.0
Parameters:
{v1} (vim.Version|number[]|string)
{v2} (vim.Version|number[]|string)
Return:
(boolean)
Attributes:
Since: 0.10.0
Parameters:
{v1} (vim.Version|number[]|string)
{v2} (vim.Version|number[]|string)
Return:
(boolean)
Attributes:
Since: 0.9.0
Parameters:
{v1} (vim.Version|number[]|string)
{v2} (vim.Version|number[]|string)
Return:
(boolean)
Computes the common range shared by the given ranges.
Attributes:
Since: 0.12.0
Parameters:
{r1} (vim.VersionRange) First range to intersect.
{r2} (vim.VersionRange) Second range to intersect.
Return:
(vim.VersionRange?) Maximal range that is present inside both r1
and r2. nil if such range does not exist.
vim.version.last(
TODO: generalize this, move to func.lua
{versions})vim.version.last()Parameters:
{versions} (vim.Version[])
Return:
(vim.Version?)
Attributes:
Since: 0.10.0
Parameters:
{v1} (vim.Version|number[]|string)
{v2} (vim.Version|number[]|string)
Return:
(boolean)
Attributes:
Since: 0.9.0
Parameters:
{v1} (vim.Version|number[]|string)
{v2} (vim.Version|number[]|string)
Return:
(boolean)
Parses a semantic version string and returns a version object which can be
used with other
vim.version functions. For example "1.0.1-rc1+build.2"
returns:{ major = 1, minor = 0, patch = 1, prerelease = "rc1", build = "build.2" }
Attributes:
Since: 0.9.0
Parameters:
{version} (string) Version string to parse.
{opts} (table?) Options for parsing.
{strict}? (boolean, default: false) If true, no
coercion is attempted on input not conforming to semver
v2.0.0. If false, parse() attempts to coerce input
such as "1.0", "0-x", "tmux 3.2a" into valid versions.
Return:
(vim.Version?) Version object or nil if input is invalid.
See also:
vim.version.range(
Parses a semver version-range "spec" and returns vim.VersionRange
object:
{spec})vim.version.range()Attributes:
Since: 0.9.0
Parameters:
{spec} (string) Version range "spec"
Return:
(vim.VersionRange?)
UI2
WARNING: This is an experimental feature intended to replace the builtin
message + cmdline presentation layer.
To enable this feature (default opts shown, see also 'messagesopt'):
require('vim._core.ui2').enable({
enable = true, -- Whether to enable or disable the UI.
msg = { -- Options related to the message module.
---@type string|table<string, 'cmd'|'msg'|'pager'> Default message target
---or table mapping |ui-messages| kinds, triggers and IDs to a target.
---Table keys are matched as a Lua pattern to the message ID. 'default'
---mapping applies to any omitted kind: { default = 'cmd', progress = 'msg' }.
targets = 'cmd',
dialog = { -- Options related to dialog window.
height = 0.5, -- Maximum height.
},
msg = { -- Options related to msg window.
height = 0.5, -- Maximum height.
},
pager = { -- Options related to message window.
height = 0.999, -- Maximum height.
},
},
})
ui2 behavior is also configured by these 'messagesopt' items: "pager",
"timeout". Example:
set messagesopt+=maxheight:50,pager:<CR>,timeout:4000
There are four special windows/buffers for presenting messages and cmdline:
"msg": Message window. Shows ephemeral messages; useful if 'cmdheight' is 0.
"pager": Pager window. Shows :messages, allows navigating all messages.
"dialog": Dialog window. Shows modal prompts that wait for user input.
In each of the special buffers, 'filetype' is set as listed above ("cmd",
"msg", …). Handle the FileType event to configure any local options for
these windows/buffers.
Unlike the legacy hit-enter prompt, messages exceeding 'cmdheight' are
collapsed, followed by a
[+x] "spill" indicator, where x is number of
overflow lines. To see all messages, do either:
g< at any time.
Type the "pager" char (if configured in 'messagesopt'), immediately after an
interactive : command.