Nvim:help
pages,generated fromsource using thetree-sitter-vimdoc parser.
:lua vim.print(package.loaded)
Nvim includes a "standard library"lua-stdlib for Lua. It complements the"editor stdlib" (vimscript-functions +Ex-commands) and theAPI, all ofwhich can be used from Lua code (lua-vimscriptvim.api). These threenamespaces form the Nvim programming interface.nvim -l foo.lua [args...]
goto
that some Lua 5.1 interpreters like LuaJIT may support.ffi
,lua-profile, andenhanced standard library functions; these cannot be assumed to be available,and Lua code ininit.lua or plugins should check thejit
global variablebefore using them:if jit then -- code for luajitelse -- code for plain lua 5.1end
bit
extension, which is always available: whenbuilt with PUC Lua, Nvim includes a fallback implementation which providesrequire("bit")
. Seelua-bit.-- 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()
Seehttps://luajit.org/ext_profiler.html or thep.lua
source for details::lua vim.cmd.edit(package.searchpath('jit.p', package.path))
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).nil
whichsignals to the caller that failure is not "exceptional" and must be handled.This "result-or-message" pattern is expressed as the multi-value return typeany|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.
assert()
the"result-or-message" result:local value = assert(fn())
Guidance: use the "result-or-message" pattern for...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. InLua, any missing arguments are passed asnil
, and extra parameters aresilently discarded. Example:foo(1)-- ==== Result ====-- A: 1-- B: nil
"foo"
) or table literal ({1,2,3}
). The latteris often used to mimic "named parameters" ("kwargs" or "keyword args") as inlanguages like Python and C#. Example:local func_with_opts = function(opts) local will_do_foo = opts.foo local filename = opts.filename -- ...endfunc_with_opts { foo = true, filename = "hello.world" }
print(string.match("foo123bar123", "%d+"))-- 123print(string.match("foo123bar123", "[^%d]+"))-- fooprint(string.match("foo123bar123", "[abc]+"))-- baprint(string.match("foo.bar", "%.bar"))-- .bar
:echo nvim_list_runtime_paths()
foo.bar
, each directory is searched forlua/foo/bar.lua
, thenlua/foo/bar/init.lua
. If no files are found, the directories are searchedagain for a shared library with a name matchinglua/foo/bar.?
, where?
isa list of suffixes (such asso
ordll
) derived from the initial value ofpackage.cpath. If still no files are found, Nvim falls back to Lua's defaultsearch mechanism. The first script found is run andrequire()
returns thevalue returned by the script if any, elsetrue
.require()
for each module,with subsequent calls returning the cached value without searching for, orexecuting any script. For further details seerequire().foo,bar
andpackage.cpath was./?.so;./?.dll
at startup,require('mod')
searches these paths in orderand loads the first module found ("first wins"):foo/lua/mod.luafoo/lua/mod/init.luabar/lua/mod.luabar/lua/mod/init.luafoo/lua/mod.sofoo/lua/mod.dllbar/lua/mod.sobar/lua/mod.dll
let &runtimepath = &runtimepath
{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))
.:lua vim.api.nvim_command('echo "Hello, Nvim!"')
:lua print(_VERSION)
:lua =jit.version
{range}
as Lua code. Unlike:source, this always treats the lines as Lua code.print(string.format( 'unix time: %s', os.time()))
{endmarker}
]{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.function! CurrentLineInfo()lua << EOFlocal 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))EOFendfunction
local
variables will disappear when the block finishes. But not globals.{body}
Executes Lua chunk "function(line, linenr){body}
end" for each buffer line in [range], whereline
is the current line text (without<EOL>
), andlinenr
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,$".: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
{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.:luafile script.lua:luafile %
local chunkheader = "local _A = select(1, ...) return "function luaeval (expstr, arg) local chunk = assert(loadstring(chunkheader .. expstr, "luaeval")) return chunk(arg) -- return typvalend
:echo luaeval('_A[1] + _A[2]', [40, 2])" 42:echo luaeval('string.match(_A, "[a-z]+")', 'XYXfoo123')" foo
nil
values, aka "holes") integer keys 1…N is a list. See alsolist-iterator.lua-dictvim.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 toNumbers, non-integral are converted toFloats. This variant allows integralFloats.{[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. Withoutvim.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.: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)
luaeval
is converted ("marshalled") from Vimscriptto Lua, so changes to Lua containers do not affect values in Vimscript. Returnvalue is also always converted. When converting,msgpack-special-dicts aretreated specially.v:lua
prefix can be used to call Lua functionswhich 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. Usingrequire"mypack"
orrequire('mypack')
as a prefix does NOT work.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'} endend-- 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 usev:lua
to call Lua functions as Vimscriptmethods::eval arg1->v:lua.somemod.func(arg2)
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 " Errorcall SomeFunc(v:lua.mycallback) " Errorlet g:foo = v:lua " Errorlet g:foo = v:['lua'] " Error
vim
module, which exposesvarious functions and sub-modules. It is always loaded, thusrequire("vim")
is unnecessary.: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") areinternal/private and must not be used by plugins.vim.uv
exposes the "luv" Lua bindings for the libUV library that Nvim usesfor networking, filesystem, and process management, seeluvref.txt.In particular, it allows interacting with the main Nvimluv-event-loop.vim.api
functions (exceptapi-fast) invim.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)
local timer = vim.uv.new_timer()timer:start(1000, 0, vim.schedule_wrap(function() vim.api.nvim_command('echomsg "test"')end))
-- 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 + 1end)print('sleeping');
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)endfunction watch_file(fname) local fullpath = vim.api.nvim_call_function( 'fnamemodify', {fname, ':p'}) w:start(fullpath, {}, vim.schedule_wrap(function(...) on_change(...) end))endvim.api.nvim_command( "command! -nargs=1 Watch call luaeval('watch_file(_A)', expand('<args>'))")
inotify
watchesand queued events as the default limit can be too low. To increase the limit,run:sysctl fs.inotify.max_user_watches=494462
/etc/sysctl.conf
to make the changes persistent.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 serverendlocal 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)
vim.uv.new_thread
. Each thread has its ownseparate Lua interpreter state, with no access to Lua globals on the mainthread. Neither can the editor state (buffers, windows, etc) be directlyaccessed from threads.vim.*
stdlib is available in threads, including:vim.uv
with a separate event loop per thread.vim.mpack
andvim.json
(useful for serializing messages between threads)require
in threads can use Lua packages from the globalpackage.pathprint()
andvim.inspect
vim.diff
vim.*
that work with pure Lua values, likevim.split
,vim.tbl_*
,vim.list_*
, etc.vim.is_thread()
returns true from a non-main thread.init.vim
:autocmd TextYankPost * silent! lua vim.hl.on_yank {higroup='Visual', timeout=300}
{opts}
(table?
) Optional parameters.user
)syntax
:50
, used for standard syntax highlightingtreesitter
:100
, used for treesitter-based highlightingsemantic_tokens
:125
, used for LSP semantic token highlightingdiagnostics
:150
, used for code analysis such as diagnosticsuser
:200
, used for user-triggered highlights such as LSP document symbols oron_yank
autocommands{bufnr}
,{ns}
,{higroup}
,{start}
,{finish}
,{opts}
) Apply highlight group to range of text.{bufnr}
(integer
) Buffer number to apply highlighting to{ns}
(integer
) Namespace to add highlight to{higroup}
(string
) Highlight group to use for highlighting{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 cleareduv.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{a}
,{b}
,{opts}
)vim.diff(){a}
and{b}
. Any indices returned by this function, either directly or via callback arguments, are 1-based.vim.diff('a\n', 'b\nc\n')-- =>-- @@ -1 +1,2 @@-- -a-- +b-- +cvim.diff('a\n', 'b\nc\n', {result_type = 'indices'})-- =>-- {-- {1, 1, 1, 2}-- }
{a}
(string
) First string to compare{b}
(string
) Second string to compare{opts}
(table?
) Optional parameters:{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 ifon_hunk
is used.{linematch}
(boolean|integer
) Run linematch on the resulting hunks from xdiff. When integer, only hunks upto this size in lines are run through linematch. Requiresresult_type = indices
, ignored otherwise.{algorithm}
('myers'|'minimal'|'patience'|'histogram'
, default:'myers'
) Diff algorithm to use. Values:myers
: the default algorithmminimal
: spend extra time to generate the smallest possible diffpatience
: patience diff algorithmhistogram
: histogram diff algorithm{ctxlen}
(integer
) Context length{interhunkctxlen}
(integer
) Inter hunk context length{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.{ignore_cr_at_eol}
(boolean
) Ignore carriage return at end-of-line{ignore_blank_lines}
(boolean
) Ignore blank lines{indent_heuristic}
(boolean
) Use the indent heuristic for the internal diff library.string|integer[][]?
) See{opts.result_type}
.nil
if{opts.on_hunk}
is given.{str}
)vim.mpack.decode(){str}
to a Lua object.{str}
(string
)any
){obj}
)vim.mpack.encode(){obj}
as msgpack in a Lua string.{obj}
(any
)string
){str}
,{opts}
)vim.json.decode(){str}
to a Lua object.{opts}
, see below).{}
(empty Lua table).vim.print(vim.json.decode('{"bar":[],"foo":{},"zub":null}'))-- { bar = {}, foo = vim.empty_dict(), zub = vim.NIL }
{str}
(string
) Stringified JSON data.{opts}
(table<string,any>?
) Options table with keys:any
){obj}
,{opts}
)vim.json.encode(){obj}
as JSON in a Lua string.{obj}
(any
){opts}
(table<string,any>?
) Options table with keys:string
){str}
(string
) Base64 encoded stringstring
) Decoded string{str}
(string
) String to encodestring
) Encoded string{str}
)vim.spell.check(){str}
for spelling errors. Similar to the Vimscript functionspellbadword().vim.spell.check("the quik brown fox")-- =>-- {-- {'quik', 'bad', 5}-- }
{str}
(string
)[string, 'bad'|'rare'|'local'|'caps', integer][]
) List of tuples with three items:{str}
where the word begins.{...}
)vim.api{func}
with arguments{...}
. Example: call the "nvim_get_current_line()" API function:print(tostring(vim.api.nvim_get_current_line()))
vim.NILvim.NILnil
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_idx] = vim.types.float, [vim.val_idx] = 1.0,}
float
,array
anddictionary
types.vim.types.float
,vim.types.array
andvim.types.dictionary
fall under only two following assumptions: 1. 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 notnil
”. 2. For each value invim.types
tablevim.types[vim.types[value]]
is the same asvalue
. No other restrictions are put on types, and it is not guaranteed that values corresponding tovim.types.float
,vim.types.array
andvim.types.dictionary
will not change or thatvim.types
table will only contain values for these three types.{}
without this metatable to an list/array.table
){str}
,{from}
,{to}
)vim.iconv(){str}
converted from encoding{from}
to encoding{to}
. When the conversion failsnil
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".{str}
(string
) Text to convert{from}
(string
) Encoding of{str}
{to}
(string
) Target encodingstring?
) Converted string if conversion succeeds,nil
otherwise.false
most API functions are callable (but may be subject to other restrictions such astextlock).{channel}
,{method}
,{...}
)vim.rpcnotify(){event}
to{channel}
viaRPC and returns immediately. If{channel}
is 0, the event is broadcast to all channels.{channel}
(integer
){method}
(string
){...}
(any?
){channel}
,{method}
,{...}
)vim.rpcrequest(){channel}
to invoke{method}
viaRPC and blocks until a response is received.{channel}
(integer
){method}
(string
){...}
(any?
){fn}
)vim.schedule(){fn}
to be invoked soon by the main event-loop. Useful to avoidtextlock or other temporary restrictions.{fn}
(fun()
){str}
,{index}
)vim.str_utf_end(){index}
points to.-- 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 charactervim.str_utf_end('æ', 2)-- Returns 1 because the index is pointing at the penultimate byte of a charactervim.str_utf_end('æ', 1)
{str}
(string
){index}
(integer
)integer
){str}
)vim.str_utf_pos(){str}
(string
)integer[]
){str}
,{index}
)vim.str_utf_start(){index}
points to.{index}
to get the starting byte of a character.-- 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 charactervim.str_utf_start('æ', 1)-- Returns -1 because the index is pointing at the second byte of a charactervim.str_utf_start('æ', 2)
{str}
(string
){index}
(integer
)integer
){a}
(string
){b}
(string
)0|1|-1
) if strings are equal,{a}
is greater than{b}
or{a}
is lesser than{b}
, respectively.{ns}
,{opts}
,{callback}
)vim.ui_attach(){callback}
receives event name plus additional parameters. Seeui-popupmenu and the sections below for event format for respective events.msg_show
events are executed inapi-fast context; showing the message should be scheduled.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).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') endend)
{ns}
(integer
) Namespace ID{opts}
(table<string, any>
) Optional parameters.{callback}
(fun(event: string, ...)
) Function called for each UI event{ns}
)vim.ui_detach(){ns}
.{ns}
(integer
) Namespace ID{time}
,{callback}
,{interval}
,{fast_only}
)vim.wait(){time}
in milliseconds until{callback}
returnstrue
.{callback}
immediately and at approximately{interval}
milliseconds (default 200). Nvim still processes other events during this time.----- Wait for 100 ms, allowing other events to processvim.wait(100, function() end)----- Wait for 100 ms or until global variable set.vim.wait(100, function() return vim.g.waiting_for_var end)----- Wait for 1 second or until global variable set, checking every ~500 msvim.wait(1000, function() return vim.g.waiting_for_var end, 500)----- Schedule a function to set a value in 100msvim.defer_fn(function() vim.g.timer_result = true end, 100)-- Would wait ten seconds if results blocked. Actually only waits 100 msif vim.wait(10000, function() return vim.g.timer_result end) then print('Only waiting a little bit of time!')end
{time}
(integer
) Number of milliseconds to wait{callback}
(fun(): boolean?
) Optional callback. Waits until{callback}
returns true{interval}
(integer?
) (Approximate) number of milliseconds to wait between pollsboolean
) (-1|-2?
){callback}
returnstrue
during the{time}
:true, nil
{callback}
never returnstrue
during the{time}
:false, -1
{callback}
is interrupted during the{time}
:false, -2
{callback}
errors, the error is raised.vim.fn.remove()
on aLua 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 }"
{func}
,{...}
)vim.call(){func}
with arguments{...}
. See alsovim.fn. Equivalent to:vim.fn[func]({...})
{command}
) Seevim.cmd().{...}
)vim.fn{func}
with arguments{...}
. To call autoload functions, use the syntax:vim.fn['some#function']({...})
pairs(vim.fn)
only enumerates functions that were called at least once.vim.*
Lua tablesdescribed below. In this way you can easily read and modify global Vimscriptvariables from Lua.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
vim.g.my_dict.field1 = 'value' -- Does not worklocal my_dict = vim.g.my_dict --my_dict.field1 = 'value' -- Instead dovim.g.my_dict = my_dict --
vim.gvim.gnil
.nil
. Can be indexed with an integer to access variables for a specific buffer.nil
. Can be indexed with an integer to access variables for a specific window.nil
. Can be indexed with an integer to access variables for a specific tabpage.set number
Lua:vim.o.number = true
set wildignore=*.o,*.a,__pycache__
Lua:vim.o.wildignore = '*.o,*.a,__pycache__'
set wildignore=*.o,*.a,__pycache__
vim.o
:vim.o.wildignore = '*.o,*.a,__pycache__'
vim.opt
:vim.opt.wildignore = { '*.o', '*.a', '__pycache__' }
vim.opt.wildignore:append { "*.pyc", "node_modules" }
vim.opt.wildignore:prepend { "new_first_value" }
vim.opt.wildignore:remove { "node_modules" }
set listchars=space:_,tab:>~
vim.o
:vim.o.listchars = 'space:_,tab:>~'
vim.opt
:vim.opt.listchars = { space = '_', tab = '>~' }
Option
object, not the value of the option,which is accessed throughvim.opt:get():echo wildignore
vim.o
:print(vim.o.wildignore)
vim.opt
:vim.print(vim.opt.wildignore:get())
vim.opt_local
. Additionally, to replicate the behavior of:setglobal, usevim.opt_global
.vim.opt.formatoptions:append('j')vim.opt.formatoptions = vim.opt.formatoptions + 'j'
{value}
(string
) Value to appendvim.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
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
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
string|integer|boolean?
) value of optionvim.opt.wildignore:prepend('*.o')vim.opt.wildignore = vim.opt.wildignore ^ '*.o'
{value}
(string
) Value to prependvim.opt.wildignore:remove('*.pyc')vim.opt.wildignore = vim.opt.wildignore - '*.pyc'
{value}
(string
) Value to remove{bufnr}
]vim.bo{bufnr}
. Like:setlocal
. If{bufnr}
is omitted then the current buffer is used. Invalid{bufnr}
or key is an error.local bufnr = vim.api.nvim_get_current_buf()vim.bo[bufnr].buflisted = true -- same as vim.bo.buflisted = trueprint(vim.bo.comments)print(vim.bo.baz) -- error: invalid key
nil
.vim.env.FOO = 'bar'print(vim.env.TERM)
vim.go.cmdheight = 4print(vim.go.columns)print(vim.go.bar) -- error: invalid key
:set
, so buffer/window-scoped options target the current buffer/window. Invalid key is an error.vim.o.cmdheight = 4print(vim.o.columns)print(vim.o.foo) -- error: invalid key
{winid}
][{bufnr}
]vim.wo{winid}
and buffer with number{bufnr}
. Like:setlocal
if setting aglobal-local option or if{bufnr}
is provided, like:set
otherwise. If{winid}
is omitted then the current window is used. Invalid{winid}
,{bufnr}
or key is an error.{bufnr}
with value0
(the current buffer in the window) is supported.local winid = vim.api.nvim_get_current_win()vim.wo[winid].number = true -- same as vim.wo.number = trueprint(vim.wo.foldmarker)print(vim.wo.quux) -- error: invalid keyvim.wo[winid][0].spell = false -- like ':setlocal nospell'
vim.cmd
can be indexed with a command name to return a callable function to the command.vim.cmd('echo 42')vim.cmd([[ augroup My_group autocmd! autocmd FileType c setlocal cindent augroup END]])-- Ex command :echo "foo"-- Note string literals need to 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.txtvim.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 :colorscheme bluevim.cmd('colorscheme blue')vim.cmd.colorscheme('blue')
{command}
(string|table
) Command(s) to execute. If a string, executes multiple lines of Vimscript at once. In this case, it is an alias tonvim_exec2(), whereopts.output
is set to false. Thus it works identical to:source. If a table, executes a single command. In this case, it is an alias tonvim_cmd() whereopts
is empty.{fn}
Note: The{fn}
isvim.schedule_wrap()ped automatically, so API functions are safe to call.{fn}
(function
) Callback to call oncetimeout
expires{timeout}
(integer
) Number of milliseconds to wait before callingfn
table
) timer luv timer object{name}
,{alternative}
,{version}
,{plugin}
,{backtrace}
) Shows a deprecation message to the user.{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.string?
) Deprecated message, or nil if no message was shown.string
)local k = vim.keycodevim.g.mapleader = k'<bs>'
{str}
(string
) String to be converted.string
){find_start}
)vim.lua_omnifunc():lua
command.set omnifunc=v:lua.vim.lua_omnifunc
in a Lua buffer.{find_start}
(1|0
){msg}
(string
) Content of the notification to show to the user.{opts}
(table?
) Optional parameters. Unused by default.{msg}
(string
) Content of the notification to show to the user.{opts}
(table?
) Optional parameters. Unused by default.boolean
) true if message was displayed, else false{fn}
,{ns_id}
,{opts}
)vim.on_key(){fn}
with namespace id{ns_id}
as a listener to every, yes every, input key.{fn}
will be removed on error.{fn}
won't be invoked recursively, i.e. if{fn}
itself consumes input, it won't be invoked for those keys.{fn}
will not be cleared bynvim_buf_clear_namespace(){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 keycodes, where{key}
is the key after mappings are applied, and{typed}
is the key(s) before mappings are applied.{typed}
may be empty if{key}
is produced by non-typed key(s) or by the same typed key(s) that produced a previous{key}
. If{fn}
returns an empty string,{key}
is discarded/ignored. When{fn}
isnil
, the callback associated with namespace{ns_id}
is removed.{ns_id}
(integer?
) Namespace ID. If nil or 0, generates and returns a newnvim_create_namespace() id.{opts}
(table?
) Optional parametersinteger
) Namespace id associated with{fn}
. Or count of all callbacks if on_key() is called without arguments.vim.paste
.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) endend)(vim.paste)
{phase}
(-1|1|2|3
) -1: "non-streaming" paste: the call contains all lines. If paste is "streamed",phase
indicates the stream state:boolean
) result false if client should cancel the paste.local hl_normal = vim.print(vim.api.nvim_get_hl(0, { name = 'Normal' }))
{...}
(any
)any
) given arguments.{fn}
.function notify_readable(_err, readable) vim.notify("readable? " .. tostring(readable))endvim.uv.fs_access(vim.fn.stdpath("config"), "R", vim.schedule_wrap(notify_readable))
{fn}
(function
)function
){s}
,{encoding}
,{index}
,{strict_indexing}
) Convert UTF-32, UTF-16 or UTF-8{index}
to byte index. If{strict_indexing}
is false then then an out of range index will return byte length instead of throwing an error.{index}
in the middle of a UTF-16 sequence is rounded upwards to the end of that sequence.{s}
(string
){encoding}
("utf-8"|"utf-16"|"utf-32"
){index}
(integer
){strict_indexing}
(boolean?
) default: trueinteger
){s}
,{encoding}
,{index}
,{strict_indexing}
) 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.{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.{s}
(string
){encoding}
("utf-8"|"utf-16"|"utf-32"
){index}
(integer?
){strict_indexing}
(boolean?
) default: trueinteger
){cmd}
,{opts}
,{on_exit}
)vim.system(){cmd}
cannot be run.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 = '' }
{cmd}
cannot be run.{cmd}
(string[]
) Command to execute{opts}
(vim.SystemOpts?
) Options:NVIM
set tov:servername.env
defines the job environment exactly, instead of merging current environment.true
, then a pipe to stdin is opened and can be written to via thewrite()
method to SystemObj. If string or string[] then will be written to stdin and closed. Defaults tofalse
.fun(err: string, data: string)
. Defaults totrue
fun(err: string, data: string)
. Defaults totrue
.\r\n
with\n
.{on_exit}
(fun(out: vim.SystemCompleted)?
) Called when subprocess exits. When provided, the command runs asynchronously. Receives SystemCompleted object, see return of SystemObj:wait().vim.SystemObj
) Object with the fields:stdin=true
. Passnil
to close the stream.{bufnr}
,{row}
,{col}
,{filter}
)vim.inspect_pos(){bufnr}
(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{filter}
(table?
) Table with key-value pairs to filter the items{syntax}
(boolean
, default:true
) Include syntax based highlight groups.{treesitter}
(boolean
, default:true
) Include treesitter based highlight groups.{extmarks}
(boolean|"all"
, default: true) Include extmarks. Whenall
, then extmarks without ahl_group
will also be included.{semantic_tokens}
(boolean
, default: true) Include semantic token highlights.table
) a table with the following key-value pairs. Items are in "traversal order":{bufnr}
,{row}
,{col}
,{filter}
)vim.show_pos()zS
in Normal mode:vim.keymap.set('n', 'zS', vim.show_pos)
{bufnr}
(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{filter}
(table?
) A table with the following fields:{syntax}
(boolean
, default:true
) Include syntax based highlight groups.{treesitter}
(boolean
, default:true
) Include treesitter based highlight groups.{extmarks}
(boolean|"all"
, default: true) Include extmarks. Whenall
, then extmarks without ahl_group
will also be included.{semantic_tokens}
(boolean
, default: true) Include semantic token highlights.any?
)any?
){item}
(any
)eq
metamethod. All other types are compared using the equality==
operator.{a}
(any
) First value{b}
(any
) Second valueboolean
)true
if values are equals, elsefalse
{orig}
,{noref}
)vim.deepcopy()noref=true
is much more performant on tables with unique table fields, whilenoref=false
is more performant on tables that reuse table fields.{orig}
(table
) Table to copy{noref}
(boolean?
) Whenfalse
(default) a contained table is only copied once and all references point to this single copy. Whentrue
every occurrence of a table results in a new copy. This also means that a cyclic reference can causedeepcopy()
to fail.table
) Table of copied keys and (nested) values.{createfn}
)vim.defaulttable(){createfn}
(like Python's "defaultdict").{createfn}
isnil
it defaults to defaulttable() itself, so accessing nested keys creates nested tables:local a = vim.defaulttable()a.b.c = 1
{createfn}
(fun(key:any):any?
) Provides the value for a missingkey
.table
) Empty table with__index
metamethod.{s}
(string
) String{suffix}
(string
) Suffix to matchboolean
)true
ifsuffix
is a suffix ofs
{s}
,{sep}
,{opts}
)vim.gsplit()for s in vim.gsplit(':aa::b:', ':', {plain=true}) do print(s)end
for word, num in ('foo111bar222'):gmatch('([^0-9]*)(%d*)') do print(('word: %s num: %s'):format(word, num))end
{s}
(string
) String to split{sep}
(string
) Separator or pattern{plain}
(boolean
) Usesep
literally (as in string.find).{trimempty}
(boolean
) Discard empty segments at start and end of the sequence.fun():string?
) Iterator over the split components{f}
(any
) Any objectboolean
)true
iff
is callable, elsefalse
{t}
)vim.isarray()t
is an "array": a table indexed only by integers (potentially non-contiguous).{}
is an array, unless it was created byvim.empty_dict() or returned as a dict-likeAPI or Vimscript result, for example fromrpcrequest() orvim.fn.{t}
(table?
)boolean
)true
if array-like table, elsefalse
.{t}
)vim.islist()t
is a "list": a table indexed only by contiguous integers starting from 1 (whatlua-length calls a "regular array").{}
is a list, unless it was created byvim.empty_dict() or returned as a dict-likeAPI or Vimscript result, for example fromrpcrequest() orvim.fn.{t}
(table?
)boolean
)true
if list-like table, elsefalse
.{t}
,{value}
)vim.list_contains()value
.{t}
(table
) Table to check (must be list-like, not validated){value}
(any
) Value to compareboolean
)true
ift
containsvalue
{dst}
,{src}
,{start}
,{finish}
)vim.list_extend(){dst}
(table
) List which will be modified and appended to{src}
(table
) List from which values will be inserted{start}
(integer?
) Start index on src. Defaults to 1{finish}
(integer?
) Final index on src. Defaults to#src
table
) dst{list}
,{start}
,{finish}
)vim.list_slice(){list}
(any[]
) Table{start}
(integer?
) Start range of slice{finish}
(integer?
) End range of sliceany[]
) Copy of table sliced from start to finish (inclusive){s}
(string
) String to escapestring
) %-escaped pattern string{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
{size}
(integer
){t}
(table
) Dict-like tablefun(table: table<K, V>, index?: K):K, V
)for-in iterator over sorted keys and their values (table
){s}
,{sep}
,{opts}
)vim.split()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'}
{s}
(string
) String to split{sep}
(string
) Separator or pattern{plain}
(boolean
) Usesep
literally (as in string.find).{trimempty}
(boolean
) Discard empty segments at start and end of the sequence.string[]
) List of split components{s}
(string
) String{prefix}
(string
) Prefix to matchboolean
)true
ifprefix
is a prefix ofs
{t}
,{value}
,{opts}
)vim.tbl_contains()vim.tbl_contains({ 'a', { 'b', 'c' } }, function(v) return vim.deep_equal(v, { 'b', 'c' })end, { predicate = true })-- true
{t}
(table
) Table to check{value}
(any
) Value to compare or predicate function reference{predicate}
(boolean
)value
is a function reference to be checked (default false)boolean
)true
ift
containsvalue
{t}
)vim.tbl_count()t
.vim.tbl_count({ a=1, b=2 }) --> 2vim.tbl_count({ 1, 2 }) --> 2
{t}
(table
) Tableinteger
) Number of non-nil values in table{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:{...}
(table
) Two or more tablestable
) Merged table{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:{...}
(table
) Two or more tablestable
) Merged table{func}
(function
) Function{t}
(table
) Tableany[]
) Table of filtered values{o}
,{...}
)vim.tbl_get()nil
if the key does not exist.vim.tbl_get({ key = { nested_key = true }}, 'key', 'nested_key') == truevim.tbl_get({ key = {}}, 'key', 'nested_key') == nil
{o}
(table
) Table to index{...}
(any
) Optional keys (0 or more, variadic) via which to index the tableany
) Nested value indexed by key (if it exists), else nil{t}
(table
) Table to checkboolean
)true
ift
is empty{t}
)vim.tbl_keys(){t}
(table
) Tableany[]
) List of keys{func}
(fun(value: T): any
) Function{t}
(table<any, T>
) Tabletable
) Table of transformed values{t}
)vim.tbl_values(){t}
(table
) Tableany[]
) List of values{s}
(string
) String to trimstring
) String with whitespace removed from its beginning and end{name}
,{value}
,{validator}
,{optional}
,{message}
) Validate function arguments.vim.validate(name, value, validator[, optional][, message])
Validates that argument{name}
with value{value}
satisfies{validator}
. If{optional}
is given and istrue
, then{value}
may benil
. 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) wherespec
is of typetable<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. Example: function user.new(name, age, hobbies) vim.validate{ name={name, 'string'}, age={age, 'number'}, hobbies={hobbies, 'table'}, } -- ...end
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')
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')
validator
set to a value returned bylua-type() provides the best performance.{name}
(string
) Argument name{value}
(any
) Argument value{validator}
(vim.validate.Validator
)string|string[]
): Any value that can be returned fromlua-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?
) Argument is optional (may be omitted){message}
(string?
) message when validation failsenable=true
):enable=false
):{enable}
(boolean?
) true/nil to enable, false to disable{modname}
(string
) Module name, or"*"
to find the top-level modules instead{opts}
(table?
) Options for finding a module:{rtp}
(boolean
, default:true
) Search for modname in the runtime path.{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.{all}
(boolean
, default:false
) Search for all matches.table[]
) A list of objects with the following fields:{modpath}
(string
) Path of the module{modname}
(string
) Name of the module{stat}
(uv.fs_stat.result
) The fs_stat of the module path. Won't be returned formodname="*"
{path}
(string?
) path to reset{str}
(string
) string to decodestring
) decoded string{str}
(string
) string to encode{rfc}
("rfc2396"|"rfc2732"|"rfc3986"?
)string
) encoded string{bufnr}
(integer
)string
) URI{path}
(string
) Path to filestring
) URI{uri}
)vim.uri_to_bufnr(){uri}
(string
)integer
) bufnr{uri}
(string
)string
) filename or unchanged URI for non-file URIs{opts}
,{on_confirm}
)vim.ui.input()on_confirm
.vim.ui.input({ prompt = 'Enter value for shiftwidth: ' }, function(input) vim.o.shiftwidth = tonumber(input)end)
{on_confirm}
(function
) ((input|nil) -> ()) 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), ornil
if the user aborted the dialog.{path}
,{opt}
)vim.ui.open()path
with the system default handler (macOSopen
, Windowsexplorer.exe
, Linuxxdg-open
, …), or returns (but does not show) an error message on failure.-- 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
{path}
(string
) Path or URL to open{opt}
({ cmd?: string[] }?
) Optionsvim.SystemObj?
) Command object, or nil if not found. (string?
) Error message on failure, or nil on success.{items}
,{opts}
,{on_choice}
)vim.ui.select()on_choice
.vim.ui.select({ 'tabs', 'spaces' }, { prompt = 'Select tabs or spaces:', format_item = function(item) return "I'd like to choose " .. item end,}, function(choice) if choice == 'spaces' then vim.o.expandtab = true else vim.o.expandtab = false endend)
{items}
(any[]
) Arbitrary items{opts}
(table
) Additional optionsSelect one of:
items
. Defaults totostring
.vim.ui.select
may wish to use this to infer the structure or semantics ofitems
, or the context in which select() was called.{on_choice}
(fun(item: T?, idx: integer?)
) Called once the user made a choice.idx
is the 1-based index ofitem
withinitems
.nil
if the user aborted the dialog.require('vim._extui').enable({ enable = true, -- Whether to enable or disable the UI. msg = { -- Options related to the message module. ---@type 'box'|'cmd' Type of window used to place messages, either in the ---cmdline or in a separate message box window with ephemeral messages. pos = 'cmd', box = { -- Options related to the message box window. timeout = 4000, -- Time a message is visible. }, },})
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, },})
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 }, }, },}
{filetypes}
(table
) A table containing new filetype maps (see example).{pattern}
(vim.filetype.mapping
){extension}
(vim.filetype.mapping
){filename}
(vim.filetype.mapping
){filetype}
,{option}
) Get the default option value for a{filetype}
.vim.filetype.get_option('vim', 'commentstring')
{filetype}
(string
) Filetype{option}
(string
) Option namestring|boolean|integer
) Option value-- Using a buffer numbervim.filetype.match({ buf = 42 })-- Override the filename of the given buffervim.filetype.match({ buf = 42, filename = 'foo.c' })-- Using a filename without a buffervim.filetype.match({ filename = 'main.lua' })-- Using file contentsvim.filetype.match({ contents = {'#!/usr/bin/env bash'} })
{args}
(table
) Table specifying which matching strategy to use. Accepted keys are:{buf}
(integer
) Buffer number to use for matching. Mutually exclusive with{contents}
{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.{contents}
(string[]
) An array of lines representing file contents to use for matching. Can be used with{filename}
. Mutually exclusive with{buf}
.string?
) If a match was found, the matched filetype. (function?
) A function that modifies buffer state when called (for example, to set some filetype specific buffer variables). The function accepts a buffer number as its only argument.{modes}
,{lhs}
,{opts}
)vim.keymap.del()vim.keymap.del('n', 'lhs')vim.keymap.del({'n', 'i', 'v'}, '<leader>w', { buffer = 5 })
{modes}
(string|string[]
){lhs}
(string
){opts}
(table?
) A table with the following fields:{buffer}
(integer|boolean
) Remove a mapping from the given buffer. When0
ortrue
, use the current buffer.{mode}
,{lhs}
,{rhs}
,{opts}
)vim.keymap.set()-- 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, { buffer = true })-- 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)')
{replace_keycodes}
defaults totrue
if "expr" istrue
.{buffer}
(integer|boolean
) Creates buffer-local mapping,0
ortrue
for current buffer.{remap}
(boolean
, default:false
) Make the mapping recursive. Inverse of{noremap}
.if vim.uv.fs_stat(file) then vim.print('file exists')end
{path}
)vim.fs.abspath().
and..
), or expand environment variables. If the path is already absolute, it is returned unchanged. Also converts\
path separators to/
.{path}
(string
) Pathstring
) Absolute path{file}
(string?
) Pathstring?
) Basename of{file}
{path}
(string
) An absolute or relative path to the directory to iterate over. The path is first normalizedvim.fs.normalize().{opts}
(table?
) Optional keyword arguments:Iterator
) over items in{path}
. Each iteration yields two values: "name" and "type". "name" is the basename of the item relative to{path}
. "type" is one of the following: "file", "directory", "link", "fifo", "socket", "char", "block", "unknown".{file}
)vim.fs.dirname(){file}
(string?
) Pathstring?
) Parent directory of{file}
{names}
,{opts}
)vim.fs.find()opts.type
) in the given path.{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.-- 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' })
{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:true
if the given item is considered a match.{opts}
(table
) Optional keyword arguments:{upward}
(boolean
, default:false
) Search upward through parent directories. Otherwise, search through child directories (recursively).{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.{limit}
(number
, default:1
) Stop the search after finding this many matches. Usemath.huge
to place no limit on the number of matches.{follow}
(boolean
, default:false
) Follow symbolic links.{...}
)vim.fs.joinpath(){...}
(string
)string
){path}
,{opts}
)vim.fs.normalize()[[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"
{path}
(string
) Path to normalize{opts}
(table?
) A table with the following fields:{expand_env}
(boolean
, default:true
) Expand environment variables.{win}
(boolean
, default:true
in Windows,false
otherwise) Path is a Windows path.string
) Normalized path{start}
)vim.fs.parents()local root_dirfor 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 endendif root_dir then print('Found git repository at', root_dir)end
{start}
(string
) Initial path.fun(_, dir: string): string?
) Iterator (nil
) (string?
){base}
,{target}
,{opts}
)vim.fs.relpath()target
path relative tobase
, ornil
ifbase
is not an ancestor.vim.fs.relpath('/var', '/var/lib') -- 'lib'vim.fs.relpath('/var', '/usr/bin') -- nil
{base}
(string
){target}
(string
){opts}
(table?
) Reserved for future usestring?
){path}
(string
) Path to remove{opts}
(table?
) A table with the following fields:{recursive}
(boolean
) Remove directories and their contents recursively{force}
(boolean
) Ignore nonexistent files and arguments{source}
,{marker}
)vim.fs.root()-- 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 repositoryvim.fs.root(0, '.git')-- Find the parent directory containing any file with a .csproj extensionvim.fs.root(0, function(name, path) return name:match('%.csproj$') ~= nilend)
{source}
(integer|string
) Buffer number (0 for current buffer) or file path (absolute or relative to thecurrent-directory) to begin the search from.{marker}
(string|string[]|fun(name: string, path: string): boolean
) A marker, or list of markers, to search for. If a function, the function is called for each evaluated item and should return true if{name}
and{path}
are a match.string?
) Directory path containing one of the given markers, or nil if no directory was found.*
to match one 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 onexample.0
,example.1
, …)[!...]
to negate a range of characters to match in a path segment (e.g.,example.[!0-9]
to match onexample.a
,example.b
, but notexample.0
){pattern}
(string
) The raw glob patternvim.lpeg
(https://www.inf.puc-rio.br/~roberto/lpeg/).{subject}
,{init}
,{...}
)Pattern:match()pattern
against thesubject
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 argumentinit
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 positioninit
), 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.local pattern = lpeg.R('az') ^ 1 * -1assert(pattern:match('hello') == 6)assert(lpeg.match(pattern, 'hello') == 6)assert(pattern:match('1 hello') == nil)
{subject}
(string
){init}
(integer?
){...}
(any
)any
) ...{pattern}
)vim.lpeg.B()patt
. Patternpatt
must match only strings with some fixed length, and it cannot contain captures. Like theand
predicate, this pattern never consumes any input, independently of success or failure.{pattern}
(vim.lpeg.Pattern|string|integer|boolean|table
)vim.lpeg.Pattern
){patt}
)vim.lpeg.C()patt
. The captured value is a string. Ifpatt
has other captures, their values are returned after this one.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)endlocal a, b, c = split('a,b,c', ',')assert(a == 'a')assert(b == 'b')assert(c == 'c')
{patt}
(vim.lpeg.Pattern|string|integer|boolean|table|function
)vim.lpeg.Capture
){n}
)vim.lpeg.Carg()lpeg.match
.{n}
(integer
)vim.lpeg.Capture
){name}
)vim.lpeg.Cb()name
(wherename
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.{name}
(any
)vim.lpeg.Capture
){...}
)vim.lpeg.Cc(){...}
(any
)vim.lpeg.Capture
){patt}
,{func}
)vim.lpeg.Cf()patt
produces a list of captures C1 C2 ... Cn, this capture will produce the valuefunc(...func(func(C1, C2), C3)...,Cn)
, that is, it will fold (or accumulate, or reduce) the captures frompatt
using functionfunc
. This capture assumes thatpatt
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 topatt
.) For each subsequent capture, LPeg callsfunc
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.local number = lpeg.R('09') ^ 1 / tonumberlocal list = number * (',' * number) ^ 0local function add(acc, newvalue) return acc + newvalue endlocal sum = lpeg.Cf(list, add)assert(sum:match('10,30,43') == 83)
{patt}
(vim.lpeg.Pattern|string|integer|boolean|table|function
){func}
(fun(acc, newvalue)
)vim.lpeg.Capture
){patt}
,{name}
)vim.lpeg.Cg()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).{patt}
(vim.lpeg.Pattern|string|integer|boolean|table|function
){name}
(string?
)vim.lpeg.Capture
){patt}
,{fn}
)vim.lpeg.Cmt()function
. The given function gets as arguments the entire subject, the current position (after the match ofpatt
), plus any capture values produced bypatt
. The first value returned byfunction
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 positioni
, the returned number must be in the range[i, len(s) + 1]
.) If the call returnstrue
, the match succeeds without consuming any input (so, to return true is equivalent to returni
). If the call returnsfalse
,nil
, or no value, the match fails. Any extra values returned by the function become the values produced by the capture.{patt}
(vim.lpeg.Pattern|string|integer|boolean|table|function
){fn}
(fun(s: string, i: integer, ...: any)
) (position: boolean|integer, ...: any)vim.lpeg.Capture
)local I = lpeg.Cp()local function anywhere(p) return lpeg.P({I * p * I + 1 * lpeg.V(1)}) endlocal match_start, match_end = anywhere('world'):match('hello world!')assert(match_start == 7)assert(match_end == 12)
vim.lpeg.Capture
){patt}
)vim.lpeg.Cs()patt
, with substitutions. For any capture insidepatt
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.local function gsub (s, patt, repl) patt = lpeg.P(patt) patt = lpeg.Cs((patt / repl + 1) ^ 0) return lpeg.match(patt, s)endassert(gsub('Hello, xxx!', 'xxx', 'World') == 'Hello, World!')
{patt}
(vim.lpeg.Pattern|string|integer|boolean|table|function
)vim.lpeg.Capture
){patt}
)vim.lpeg.Ct()patt
inside this table in successive integer keys, starting at 1. Moreover, for each named capture group created bypatt
, 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.{patt}
(vim.lpeg.Pattern|string|integer|boolean|table|function
)vim.lpeg.Capture
){tab}
)vim.lpeg.locale()alnum
,alpha
,cntrl
,digit
,graph
,lower
,print
,punct
,space
,upper
, andxdigit
, each one containing a correspondent pattern. Each pattern matches any single character that belongs to its class. If called with an argumenttable
, then it creates those fields inside the given table and returns that table.lpeg.locale(lpeg)local space = lpeg.space ^ 0local name = lpeg.C(lpeg.alpha ^ 1) * spacelocal sep = lpeg.S(',;') * spacelocal pair = lpeg.Cg(name * '=' * space * name) * sep ^ -1local 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')
{tab}
(table?
)vim.lpeg.Locale
){pattern}
,{subject}
,{init}
,{...}
)vim.lpeg.match()pattern
against thesubject
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 argumentinit
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 positioninit
), 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.local pattern = lpeg.R('az') ^ 1 * -1assert(pattern:match('hello') == 6)assert(lpeg.match(pattern, 'hello') == 6)assert(pattern:match('1 hello') == nil)
{pattern}
(vim.lpeg.Pattern|string|integer|boolean|table|function
){subject}
(string
){init}
(integer?
){...}
(any
)any
) ...{value}
)vim.lpeg.P()n
, the result is a pattern that matches exactlyn
characters.-n
, the result is a pattern that succeeds only if the input string has less thann
characters left:lpeg.P(-n)
is equivalent to-lpeg.P(n)
(see the unary minus operation).{value}
(vim.lpeg.Pattern|string|integer|boolean|table|function
)vim.lpeg.Pattern
){...}
)vim.lpeg.R()range
is a stringxy
of length 2, representing all characters with code between the codes ofx
andy
(both inclusive). As an example, the patternlpeg.R('09')
matches any digit, andlpeg.R('az', 'AZ')
matches any ASCII letter.local pattern = lpeg.R('az') ^ 1 * -1assert(pattern:match('hello') == 6)
{...}
(string
)vim.lpeg.Pattern
){string}
)vim.lpeg.S()S
stands for Set). As an example, the patternlpeg.S('+-*/')
matches any arithmetic operator. Note that, ifs
is a character (that is, a string of length 1), thenlpeg.P(s)
is equivalent tolpeg.S(s)
which is equivalent tolpeg.R(s..s)
. Note also that bothlpeg.S('')
andlpeg.R()
are patterns that always fail.{string}
(string
)vim.lpeg.Pattern
){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.{max}
(integer
){value}
)vim.lpeg.type()"pattern"
if the given value is a pattern, otherwisenil
.{value}
(vim.lpeg.Pattern|string|integer|boolean|table|function
)"pattern"?
){v}
)vim.lpeg.V()v
in the enclosing grammar.local b = lpeg.P({'(' * ((1 - lpeg.S '()') + lpeg.V(1)) ^ 0 * ')'})assert(b:match('((string))') == 11)assert(b:match('(') == nil)
{v}
(boolean|string|number|function|table|thread|userdata|lightuserdata
)vim.lpeg.Pattern
)string
)vim.re
module provides a conventional regex-like syntax for patternusage within LPegvim.lpeg. (Unrelated tovim.regex which provides Vimregexp from Lua.){string}
,{defs}
)vim.re.compile(){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.{string}
(string
){defs}
(table?
)vim.lpeg.Pattern
){subject}
,{pattern}
,{init}
)vim.re.find(){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.{init}
makes the search starts at that position in the subject string. As usual in Lua libraries, a negative value counts from the end.{subject}
(string
){pattern}
(vim.lpeg.Pattern|string
){init}
(integer?
)integer?
) the index where the occurrence starts, nil if no match (integer?
) the index where the occurrence ends, nil if no match{subject}
,{pattern}
,{replacement}
)vim.re.gsub(){pattern}
in the given{subject}
by{replacement}
.{subject}
(string
){pattern}
(vim.lpeg.Pattern|string
){replacement}
(string
)string
){subject}
,{pattern}
,{init}
)vim.re.match(){pattern}
against the given{subject}
, returning all captures.{subject}
(string
){pattern}
(vim.lpeg.Pattern|string
){init}
(integer?
)integer|vim.lpeg.Capture?
){bufnr}
,{line_idx}
,{start}
,{end_}
) Matches line atline_idx
(zero-based) in bufferbufnr
. Match is restricted to byte index rangestart
andend_
if given, otherwise seeregex:match_str(). Returned byte indices are relative tostart
if given.{bufnr}
(integer
){line_idx}
(integer
){start}
(integer?
){end_}
(integer?
)integer?
) match start (byte index) relative tostart
, ornil
if no match (integer?
) match end (byte index) relative tostart
, ornil
if no match{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, ornil
if there is no match. Because any integer is "truthy",regex:match_str()
can be directly used as a condition in an if-statement.{str}
(string
)integer?
) match start (byte index), ornil
if no match (integer?
) match end (byte index), ornil
if no match{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.{re}
(string
)vim.regex
){path}
)vim.secure.read(){path}
is a file: attempt to read the file, prompting the user if the file should be trusted.{path}
is a directory: return true if the directory is trusted (non-recursive), prompting the user as necessary.{path}
(string
) Path to a file or directory to read.boolean|string?
) If{path}
is not trusted or does not exist, returnsnil
. Otherwise, returns the contents of{path}
if it is a file, or true if{path}
is a directory.{opts}
(table
) A table with the following fields:{action}
('allow'|'deny'|'remove'
) -'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{path}
(string
) Path to a file to update. Mutually exclusive with{bufnr}
. Cannot be used when{action}
is "allow".{bufnr}
(integer
) Buffer number to update. Mutually exclusive with{path}
.boolean
) success true if operation was successful (string
) msg full path if operation was successful, else error messagevim.version
module provides functions for comparing versions and rangesconforming to thehttps://semver.org spec. Plugins, and plugin managers, canuse this to check available tools and dependencies on the current system.local v = vim.version.parse(vim.fn.system({'tmux', '-V'}), {strict=false})if vim.version.gt(v, {3, 2, 0}) then -- ...end
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 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 same1.* same1 same* any versionx same1.2.3 - 2.3.4 is >=1.2.3 <=2.3.4Partial right: missing pieces treated as x (2.3 => 2.3.x).1.2.3 - 2.3 is >=1.2.3 <2.4.01.2.3 - 2 is >=1.2.3 <3.0.0Partial left: missing pieces treated as 0 (1.2 => 1.2.0).1.2 - 2.3.0 is 1.2.0 - 2.3.0
{v1}
,{v2}
)vim.version.cmp(){major, minor, patch}
tuple, e.g.{1, 0, 3}
).if vim.version.cmp({1,0,3}, {0,2,1}) == 0 then -- ...endlocal 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
{v1}
(vim.Version|number[]|string
) Version object.{v2}
(vim.Version|number[]|string
) Version to compare withv1
.integer
) -1 ifv1 < v2
, 0 ifv1 == v2
, 1 ifv1 > v2
.{v1}
,{v2}
)vim.version.eq()true
if the given versions are equal. Seevim.version.cmp() for usage.{v1}
(vim.Version|number[]|string
){v2}
(vim.Version|number[]|string
)boolean
){v1}
(vim.Version|number[]|string
){v2}
(vim.Version|number[]|string
)boolean
){v1}
(vim.Version|number[]|string
){v2}
(vim.Version|number[]|string
)boolean
){versions}
(vim.Version[]
)vim.Version?
){v1}
(vim.Version|number[]|string
){v2}
(vim.Version|number[]|string
)boolean
){v1}
(vim.Version|number[]|string
){v2}
(vim.Version|number[]|string
)boolean
){version}
,{opts}
)vim.version.parse()vim.version
functions. For example "1.0.1-rc1+build.2" returns:{ major = 1, minor = 0, patch = 1, prerelease = "rc1", build = "build.2" }
{version}
(string
) Version string to parse.{opts}
(table?
) Optional keyword arguments:true
, no coercion is attempted on input not conforming to semver v2.0.0. Iffalse
,parse()
attempts to coerce input such as "1.0", "0-x", "tmux 3.2a" into valid versions.vim.Version?
) parsed_version Version object ornil
if input is invalid.{spec}
)vim.version.range(){ from: Version to: Version has(v: string|Version)}
:has()
checks if a version is in the range (inclusivefrom
, exclusiveto
).local r = vim.version.range('1.0.0 - 2.0.0')print(r:has('1.9.9')) -- trueprint(r:has('2.0.0')) -- falseprint(r:has(vim.version())) -- check against current Nvim version
.to
and.from
directly:local r = vim.version.range('1.0.0 - 2.0.0') -- >=1.0, <2.0print(vim.version.ge({1,0,3}, r.from) and vim.version.lt({1,0,3}, r.to))
{spec}
(string
) Version range "spec"table?
) A table with the following fields:{from}
(vim.Version
){to}
(vim.Version
){has}
(fun(self: vim.VersionRange, version: string|vim.Version)
)vim.iter()
:vim.iter(pairs(…))
.vim.iter(ipairs(…))
.vim.iter()
scans table input to decide if it is a list or a dict; toavoid this cost you can wrap the table with an iterator e.g.vim.iter(ipairs({…}))
, but that precludes the use oflist-iteratoroperations such asIter:rev()).local it = vim.iter({ 1, 2, 3, 4, 5 })it:map(function(v) return v * 3end)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 endend):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 5vim.iter({ a = 1, b = 2, c = 3, z = 26 }):any(function(k, v) return k == 'z'end)-- truelocal rb = vim.ringbuf(3)rb:push("a")rb:push("b")vim.iter(rb):totable()-- { "a", "b" }
{pred}
(fun(...):boolean
) Predicate function. Takes all values returned from the previous stage in the pipeline as arguments and returns true if the predicate matches.{pred}
)Iter:any(){pred}
(fun(...):boolean
) Predicate function. Takes all values returned from the previous stage in the pipeline as arguments and returns true if the predicate matches.{f}
)Iter:each(){f}
(fun(...)
) Function to execute for each item in the pipeline. Takes all of the values returned by the previous stage in the pipeline as arguments.vim.iter(ipairs(t))
vim.iter(t):enumerate()
local it = vim.iter(vim.gsplit('abc', '')):enumerate()it:next()-- 1'a'it:next()-- 2'b'it:next()-- 3'c'
Iter
)local bufs = vim.iter(vim.api.nvim_list_bufs()):filter(vim.api.nvim_buf_is_loaded)
{f}
(fun(...):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.Iter
)local it = vim.iter({ 3, 6, 9, 12 })it:find(12)-- 12local it = vim.iter({ 3, 6, 9, 12 })it:find(20)-- nillocal it = vim.iter({ 3, 6, 9, 12 })it:find(function(v) return v % 4 == 0 end)-- 12
{f}
(any
)any
){depth}
)Iter:flatten(){depth}
. Errors if it attempts to flatten a dict-like value.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
Iter
)-- Create a new table with only even valuesvim.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 }
{init}
(any
) Initial value of the accumulator.{f}
(fun(acc:A, ...):A
) Accumulation function.any
){delim}
.{delim}
(string
) Delimiterstring
)local it = vim.iter(vim.gsplit('abcdefg', ''))it:last()-- 'g'local it = vim.iter({ 3, 6, 9, 12, 15 })it:last()-- 15
any
)local it = vim.iter({ 1, 2, 3, 4 }):map(function(v) if v % 2 == 0 then return v * 3 endend)it:totable()-- { 6, 12 }
{f}
(fun(...):...:any
) 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.Iter
)local it = vim.iter(string.gmatch('1 2 3', '%d+')):map(tonumber)it:next()-- 1it:next()-- 2it:next()-- 3
any
)n
is negative, offsets from the end of alist-iterator.local it = vim.iter({ 3, 6, 9, 12 })it:nth(2)-- 6it:nth(2)-- 12local it2 = vim.iter({ 3, 6, 9, 12 })it2:nth(-2)-- 9it2:nth(-2)-- 3
any
)local it = vim.iter({ 3, 6, 9, 12 })it:peek()-- 3it:peek()-- 3it:next()-- 3
any
)local it = vim.iter({1, 2, 3, 4})it:pop()-- 4it:pop()-- 3
any
)local it = vim.iter({ 3, 6, 9, 12 }):rev()it:totable()-- { 12, 9, 6, 3 }
Iter
){f}
)Iter:rfind()local it = vim.iter({ 1, 2, 3, 2, 1 }):enumerate()it:rfind(1)-- 51it:rfind(1)-- 11
{f}
(any
)any
)local it = vim.iter({1, 2, 3, 4})it:rpeek()-- 4it:rpeek()-- 4it:pop()-- 4
any
)local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)it:next()-- 1it:pop()-- 3
{n}
(number
) Number of values to skip.Iter
)local it = vim.iter({ 3, 6, 9, 12 }):skip(2)it:next()-- 9
{n}
(number
) Number of values to skip.Iter
):skip(first - 1):rskip(len - last + 1)
.{first}
(number
){last}
(number
)Iter
)local it = vim.iter({ 1, 2, 3, 4 }):take(2)it:next()-- 1it:next()-- 2it:next()-- nil
{n}
(integer
)Iter
)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 } }
table
){direction}
(vim.snippet.Direction
) Navigation direction. -1 for previous, 1 for next.{filter}
)vim.snippet.active()true
if there's an active snippet in the current buffer, applying the given filter if provided.{filter}
(vim.snippet.ActiveFilter?
) Filter to constrain the search with:direction
(vim.snippet.Direction): Navigation direction. Will returntrue
if the snippet can be jumped in the given direction. Seevim.snippet.ActiveFilter.boolean
){input}
)vim.snippet.expand(){input}
(string
){direction}
)vim.snippet.jump()<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, { descr = '...', expr = true, silent = true })
{direction}
(vim.snippet.Direction
) Navigation direction. -1 for previous, 1 for next.{enc}
(string
) String to decodestring?
) Decoded string (string?
) Error message, if any{str}
(string
) String to encodestring
) Hex encoded string{size}
,{text}
,{opts}
)vim.text.indent()text
tosize
spaces/tabs.SPC SPC TAB …
= two-space indent.TAB SPC …
= one-tab indent.opts.expandtab
to treat tabs as spaces.size=0
:vim.print(vim.text.indent(0, ' a\n b\n'))
local indented, old_indent = vim.text.indent(0, ' a\n b\n')indented = vim.text.indent(old_indent + 2, indented)vim.print(indented)
local text = ' a\n b\n 'vim.print(vim.text.indent(0, (text:gsub('\n[\t ]+\n?$', '\n'))))
{size}
(integer
) Number of spaces.{text}
(string
) Text to indent.{opts}
({ expandtab?: number }?
)string
) Indented text. (integer
) Indent size before modification.{file}
:TOhtml{file}
. If{file}
is notgiven, a temporary file (created bytempname()) is used.{winid}
,{opt}
)tohtml.tohtml.tohtml(){winid}
to HTML and returns the output as a list of string.{winid}
(integer?
) Window to convert (defaults to current window){opt}
(table?
) Optional parameters.{title}
(string|false
, default: buffer name) Title tag to set in the generated HTML code.{number_lines}
(boolean
, default:false
) Show line numbers.{font}
(string[]|string
, default:guifont
) Fonts to use.{width}
(integer
, default:'textwidth' if non-zero or window width otherwise) Width used for items which are either right aligned or repeat a character infinitely.{range}
(integer[]
, default: entire buffer) Range of rows to use.string[]
)