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.1endbit 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)endThe first way to call this function is:foo(1, 2)-- ==== Result ====-- A: 1-- B: 2This 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 = &runtimepathdebug.getinfo(1, 'S').source:sub(2)
{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))EOFendfunctionlocal 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')" foonil 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'] " Errorvim 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.inspectvim.text.diffvim.* that work with pure Lua values, likevim.split,vim.tbl_*,vim.list_*, etc.vim.is_thread() returns true from a non-main thread.{...})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, ...): 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.{ns})vim.ui_detach(){ns}.{ns} (integer) Namespace ID{time},{callback},{interval},{fast_only})vim.wait()time milliseconds, untilcallback returnstrue (success). Executescallback immediately, then at intervals of approximatelyinterval milliseconds (default 200). Returns allcallback results on success.-- 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 up to 100 ms or until `vim.g.foo` is true, and get the callback results.local ok, rv1, rv2, rv3 = vim.wait(100, 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{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?)true before timeout:true, nil, ...false, -1false, -2vim.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 2vim.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 = trueset 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 wildignorevim.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: *.ovim.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)endtrue 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!")endstring|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 keynil.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.echo(…) instead ofvim.cmd{cmd='echo',…}.-- 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.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 :vertical resize +2vim.cmd.resize({ '+2', mods = { vertical = true } }){command} (string|table) Command(s) to execute.{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 callingfntable) 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.fun(x: any, opts?: vim.inspect.Opts): stringstring)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){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)endfor 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} (any?)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} (any?)boolean)true if list-like table, elsefalse.{t},{val},{opts})vim.list.bisect(){t} where{val} can be inserted while keeping the list sorted.{bound} to determine whether to return the first or the last position, defaults to "lower", i.e., the first position.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]) -- 3local 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{t} (any[]) A comparable list.{val} (any) The value to search.{opts} (table?) A table with the following fields:{lo}? (integer, default:1) Start index of the list.{hi}? (integer, default:#t + 1) End index of the list, exclusive.{key}? (fun(val: any): any) Optional, compare the return value instead of the{val} itself if provided.{bound}? ('lower'|'upper', default:'lower') Specifies the search variant.{val} keeps the list sorted.{val} keeps the list sorted..integer) index serves as either the lower bound or the upper bound position.{t},{key})vim.list.unique()key argument that if provided is called for each value in the list to compute a hash key for uniqueness comparison. This is useful for deduplicating table values or complex objects.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, function(x) return x.id end)-- t is now { {id=1}, {id=2} }{t} (any[]){key} (fun(x: T): any?) Optional hash function to determine uniqueness of valuesany[]) The deduplicated list{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#srctable) 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{fn} (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{fn},{t})vim.tbl_map()fn to all values of tablet, inpairs() iteration order (which is not guaranteed to be stable, even when the data doesn't change).{fn} (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') -- ...endvim.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'}, } -- ...endvim.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 failsfun(name: string, val: any, validator: vim.validate.Validator, message: string)fun(spec: table<string,[any, vim.validate.Validator, boolean|string]>){str} (string) Base64 encoded stringstring) Decoded string{str} (string) String to encodestring) Encoded stringvim.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. (boolean?) Return true if a match was found by falling back to a generic configuration file (i.e., ".conf"). If true, the filetype should be set with:setf FALLBACK conf, which enables a later:setf command to override the filetype. See:help setf for more information.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:{depth}? (integer, default:1) How deep the traverse.{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}{follow}? (boolean, default:false) Follow symbolic links.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)-- 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' }){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)[]|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 ifname andpath are a match. Each item (which may itself be a nested list) is evaluated in-order against all ancestors, until a match is found.string?) Directory path containing one of the given markers, or nil if no directory was found.* 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 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)/), or between the start/end of the path and the nearest separator.** (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.[] 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.{pattern} (string) The raw glob patterninit.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{start} ([integer,integer]|string) Start of region as a (line, column) tuple or string accepted bygetpos(){finish} ([integer,integer]|string) End of region as a (line, column) tuple or string accepted bygetpos(){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 specifiedvim.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 tableIter)-- 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()-- 15any)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()-- 3any)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)-- 3any)local it = vim.iter({ 3, 6, 9, 12 })it:peek()-- 3it:peek()-- 3it:next()-- 3any)local it = vim.iter({1, 2, 3, 4})it:pop()-- 4it:pop()-- 3any)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()-- 4any)local it = vim.iter({ 1, 2, 3, 4, 5 }):rskip(2)it:next()-- 1it:pop()-- 3{n} (number) Number of values to skip.Iter){n})Iter:skip()n values of an iterator pipeline, or all values satisfying a predicate of alist-iterator.local it = vim.iter({ 3, 6, 9, 12 }):skip(2)it:next()-- 9local function pred(x) return x < 10 endlocal it2 = vim.iter({ 3, 6, 9, 12 }):skip(pred)it2:next()-- 12{n} (integer|fun(...):boolean) Number of values to skip or a predicate.Iter):skip(first - 1):rskip(len - last + 1).{first} (number){last} (number)Iter){n})Iter:take()local it = vim.iter({ 1, 2, 3, 4 }):take(2)it:next()-- 1it:next()-- 2it:next()-- nillocal function pred(x) return x < 2 endlocal it2 = vim.iter({ 1, 2, 3, 4 }):take(pred)it2:next()-- 1it2:next()-- nil{n} (integer|fun(...):boolean) Number of values to take or a predicate.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){str},{opts})vim.json.decode(){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?) A table with the following fields:{luanil}? ({ object?: boolean, array?: boolean }, default:nil) Convertnull in JSON objects and/or arrays to Luanil instead ofvim.NIL.any){obj},{opts})vim.json.encode()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)endvim.o.formatexpr = 'v:lua.fmt_json()'{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, the returned JSON is formatted with newlines and whitespace, whereindent defines the whitespace at each nesting level.{sort_keys}? (boolean, default:false) Sort object keys in alphabetical order.string){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}.enable=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 resetvim.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){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){url},{opts},{on_response})vim.net.request()on_response handler on completion.{url} (string) The URL for the request.{opts} (table?) Optional parameters:verbose (boolean|nil): Enables verbose output.retry (integer|nil): Number of retries on transient failures (default: 3).outpath (string|nil): File path to save the response body to. If set, thebody value in the Response Object will betrue instead of the response body.{on_response} (fun(err?: string, response?: { body: string|boolean })) Callback invoked on request completion. Thebody field in the response object contains the raw response data (text or binary). Called with (err, nil) on failure, or (nil, { body = string|boolean }) on success.{row} and{col} coordinates of a position. To create a newvim.Pos object, callvim.pos().local pos1 = vim.pos(3, 5)local pos2 = vim.pos(4, 0)-- Operators are overloaded for comparing two `vim.Pos` objects.if pos1 < pos2 then print("pos1 comes before pos2")endif pos1 ~= pos2 then print("pos1 and pos2 are different positions")end{row} (integer) 0-based byte index.{col} (integer) 0-based byte index.{buf}? (integer) Optional buffer handle.{lsp} (fun(buf: integer, pos: lsp.Position, position_encoding: lsp.PositionEncodingKind)) SeePos:lsp().{pos} ([integer, integer]){pos} ([integer, integer])local buf = vim.api.nvim_get_current_buf()local lsp_pos = { line = 3, character = 5}-- `buf` is mandatory, as LSP positions are always associated with a buffer.local pos = vim.pos.lsp(buf, lsp_pos, 'utf-16'){buf} (integer){pos} (lsp.Position){position_encoding} (lsp.PositionEncodingKind)[integer, integer])[integer, integer])-- `buf` is required for conversion to LSP position.local buf = vim.api.nvim_get_current_buf()local pos = vim.pos(3, 5, { buf = buf })-- Convert to LSP position, you can call it in a method style.local lsp_pos = pos:lsp('utf-16'){start} and a{end_} position(seevim.Pos). Note that the{end_} position is exclusive. To create a newvim.Range object, callvim.range().local pos1 = vim.pos(3, 5)local pos2 = vim.pos(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(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.-- Operators are overloaded for comparing two `vim.Pos` objects.if range1 == range2 then print("range1 and range2 are the same range")end{start} and{end_} positions need to have the same optional fields.{start} (vim.Pos) Start position.{end_} (vim.Pos) End position, exclusive.{lsp} (fun(buf: integer, range: lsp.Range, position_encoding: lsp.PositionEncodingKind)) SeeRange:lsp().boolean)true if{outer} range fully contains{inner} range.vim.Range?) range that is present inside bothr1 andr2.nil if such range does not exist. Seevim.Range.local buf = vim.api.nvim_get_current_buf()local lsp_range = { ['start'] = { line = 3, character = 5 }, ['end'] = { line = 4, character = 0 }}-- `buf` is mandatory, as LSP ranges are always associated with a buffer.local range = vim.range.lsp(buf, lsp_range, 'utf-16'){buf} (integer){range} (lsp.Range){position_encoding} (lsp.PositionEncodingKind)-- `buf` is required for conversion to LSP range.local buf = vim.api.nvim_get_current_buf()local range = vim.range(3, 5, 4, 0, { buf = buf })-- Convert to LSP range, you can call it in a method style.local lsp_range = range:to_lsp('utf-16')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 message{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, { desc = '...', expr = true, silent = true }){direction} (vim.snippet.Direction) Navigation direction. -1 for previous, 1 for next.{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.{code} (integer){signal} (integer){stdout}? (string)nil if stdout is disabled or has a custom handler.{stderr}? (string)nil if stderr is disabled or has a custom handler.{cmd} (string[]) Command name and args{pid} (integer) Process IDtrue if the underlying process handle is eithernil or is in the process of closing. It is useful for determining whether it is safe to perform operations on the process handle.boolean)local obj = vim.system({'sleep', '10'})obj:kill('sigterm') -- sends SIGTERM to the process{timeout})SystemObj:wait()timeout (in milliseconds) has been reached. If the process does not exit before the timeout, it is forcefully terminated with SIGKILL (signal 9), and the exit code is set to 124.timeout is provided, the method will wait indefinitely (or use the timeout specified in the options when the process was started).local obj = vim.system({'echo', 'hello'}, { text = true })local result = obj:wait(1000) -- waits up to 1000msprint(result.code, result.signal, result.stdout, result.stderr){timeout} (integer?)data is a list of strings, each string is written followed by a newline.data is a string, it is written as-is.data isnil, the write side of the stream is shut down and the pipe is closed.local obj = vim.system({'cat'}, { stdin = true })obj:write({'hello', 'world'}) -- writes 'hello\nworld\n' to stdinobj:write(nil) -- closes stdin{data} (string[]|string?){cmd},{opts},{on_exit})vim.system(){cmd} cannot be run.vim.system({'bash', '-c', 'help'}).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} (table?) A table with the following fields:{cwd}? (string) Set the current working directory for the sub-process.{env}? (table<string,string|number>) Set environment variables for the new process. Inherits the current environment withNVIM set tov:servername.{clear_env}? (boolean)env defines the job environment exactly, instead of merging current environment. Note: ifenv isnil, the current environment is used but withoutNVIM set.{stdin}? (string|string[]|true) Iftrue, then a pipe to stdin is opened and can be written to via thewrite() method to SystemObj. Ifstring orstring[] then will be written to stdin and closed.{stdout}? (fun(err:string?, data: string?)|boolean, default:true) Handle output from stdout.{stderr}? (fun(err:string?, data: string?)|boolean, default:true) Handle output from stderr.{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 in ms. Upon timeout the process is sent the TERM signal (15) and the exit code is set to 124.{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 callsuv.unref() on the child's process handle.{on_exit} (fun(out: vim.SystemCompleted)?) Called when subprocess exits. When provided, the command runs asynchronously. See return of SystemObj:wait().fun(cmd: string[], on_exit: fun(out: vim.SystemCompleted)): vim.SystemObj{a},{b},{opts})vim.text.diff(){a} and{b}. Any indices returned by this function, either directly or via callback arguments, are 1-based.vim.text.diff('a\n', 'b\nc\n')-- =>-- @@ -1 +1,2 @@-- -a-- +b-- +cvim.text.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.{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?: integer }?)string) Indented text. (integer) Indent size before modification.{opts},{on_confirm})vim.ui.input()on_confirm.vim.ui.input({ prompt = 'Enter value for shiftwidth: ' }, function(input) vim.o.shiftwidth = tonumber(input)end){prompt}? (string) Text of the prompt{default}? (string) Default reply to the input{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{highlight}? (function) Function that will be used for highlighting user inputs.{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), 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} (table?) Options{cmd}? (string[]) Command used to open the path or URL.vim.SystemObj?) Command object, or nil if not found. Seevim.SystemObj. (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 options{prompt}? (string) Text of the prompt. Defaults toSelect one of:{format_item}? (fun(item: any):string) Function to format an individual item fromitems. Defaults totostring.{kind}? (string) Arbitrary hint string indicating the item shape. Plugins reimplementingvim.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.{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 URIsvim.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.system({'tmux', '-V'}):wait().stdout, {strict=false})if vim.version.gt(v, {3, 2, 0}) then -- ...end1.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 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
{from} (vim.Version){to}? (vim.Version){version})VersionRange:has()from, 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)){version} (string|vim.Version)boolean){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){r1},{r2})vim.version.intersect()vim.VersionRange?) Maximal range that is present inside bothr1 andr2.nil if such range does not exist. Seevim.VersionRange.{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?) Options for parsing.{strict}? (boolean, default:false) Iftrue, 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?)Version object ornil if input is invalid.{spec})vim.version.range(){spec} (string) Version range "spec"require('vim._extui').enable({ enable = true, -- Whether to enable or disable the UI. msg = { -- Options related to the message module. ---@type 'cmd'|'msg' Where to place regular messages, either in the ---cmdline or in a separate ephemeral message window. target = 'cmd', timeout = 4000, -- Time a message is visible in the message window. },})[+x] "spill" indicator, wherex indicates thespilled lines. To see the full message, theg< command can be used.