aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/lua/executor.c
Commit message (Collapse)AuthorAge
* [extregs] implement tab completion for ~ menu.extregsJosh Rahm15 hours
|
* [extregs] implemented aliases.Josh Rahm33 hours
|
* [extregs] switch to a hash map for an arbitrary number of extregs.Josh Rahm33 hours
|
* [feat] extregistersJosh Rahm33 hours
| | | | | | | | | | | | | | | | | | | | | Implements "extended registers" Extended registers provide access to a separate namespace of registers backed by custom lua callback functions. A new special register ("~) is introduced, which prompts the user for the name of an extregistr to yank or paste from. This enables file-backed or cloud-synced or other arbitrary register behavior. One can now use: `"~file_extreg<cr>yy` to yank into the "file_extreg" register. AI-assisted: Qwen3-Coder
* fix(lua): regression with `print()` in headless modebfredl13 days
| | | | | | | | | This is a bunch of hacks so we can override msg_puts_printf specifically while still allowing redirecting and "normal" message flow to happen, as this still has observable side-effects (even with no screen attached, screenstring() is still valid..) fixes #42218
* feat(lua): in script mode -l, use raw output for print()bfredl2026-10-02
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | consider the following test_script.lua : print 'hello\n' -- TWO new lines print 'this is \027[31mRED FOR AN AMAZING REASON\027[0m' print 'foo' print '' -- newline despite empty! print 'bar' -- a bit later: os.execute 'sleep 2' -- CPU goes BRR, cursor in column zero print 'more bar' before this PR, `nvim -l test_script.lua` had some weird behaviors compared to `lua test_script.lua` or the now removed `nvim -ll test_script.lua`. - one extra '\n' at the end of a print is ignored, one would need TWO '\n' for a single extra '\n' - an empty print'' is supposed to print an empty line - print'\027[31mRED' is being escaped so it does not work - the cursor gets stuck at the end of a message, instead of after emitting the new line, this looks like the CPU lag has something to do with the _last_ printed message which is likely not the case. I consider these behaviors to be unintentional (a consequence of stragglig through the message.c meta-machine, which is optimized for message handling in _an interative text editor_) and getting closer to plain lua behavior would be better. An alternative would be to restore the builtin print(), but our implemenation still has some benefits, like try `print(setmetatable({}, {__tostring=error})` in plain lua..
* fix(api): correct Lua command and completion typesLewis Russell2026-09-28
| | | | | | | | | | | Problem: Command inputs and parsed modifiers have different optional fields, and completion window IDs are annotated as floating-point values. Solution: Separate modifier input and return types, correct integer IDs, and update the metadata generators and their output. AI-assisted
* fix(strings): non fatal errors for [NULL] safety in vim_snprintfbfredl2026-09-08
| | | | | | | | | | | | | | | | | | | | | | | | | | | | context: vim_snprintf provides a "portable" replacement for a system vsnprintf(). However we rely on system vsnprintf() in places. This is quite arbitrary. I want to use system vsnprintf() only, and reduce the machinery in string.c for typval printf only, which will delet a lot of duplicated code. The biggest hurdle here is not "portably" (we only support sane c runtimes) but the following discrepancy: standard libc printf() considers NULL args to %s to be undefined behavior strictly while vim_snprintf() _defacto_ allows this by replacement to "[NULL]" IMO, this should be seen as "graceful" error handling (nicer than crashing on the user), not a valid means to have the string "[NULL]" intentionally be shoved in the users face. more robust code should explicitly check for NULL and replace it with a _appropriate_ fallback for the situation, depending on what a NULL string actually means in the context (unnamed buffer? anonymous namespace? global augroup?) soo, this PR provides the most _gently_ incremental nudge towards considering this case again as an error one could possible imagine. If sanitizers are complied in, this minor incursion gets printed into the sanitizers' log as a "report-and-continue" error with a traceback. This doesn't annoy the end user or "stop the world" in the test suite, but the CI will see the reported error and fail the build, just like other non-fatal CI errors.
* fix(lua): blast radius of broken `_G.debug` #41507Justin M. Keyes2026-08-27
| | | | | | | | | | | | | | | | | | | | | | | | Problem: `nlua_pcall()` references `_G.debug.traceback`. If user code deletes it or breaks it some other way, various Lua features are broken. _G.debug = nil vim.schedule(function() end) vim.wait(100) E5113: Lua chunk: attempt to index a nil value stack traceback: [C]: in function 'loop_poll' [string "vim/_core/editor"]:176: in function 'wait' crash.lua:3: in main chunk PANIC: unprotected error in call to Lua API (attempt to index a nil value) Solution: Check `_G.debug.traceback` before using it as errfunc. If it's broken, omit the traceback and say so in the error message. Note: We could cache `_G.debug` in LUA_REGISTRYINDEX on startup, but that would prevent plugins from providing custom functionality there (and we happen to do so in `tui_spec.lua` for example).
* fix(lifecycle): Lua state not freed if free_all_mem() is re-entered #41366Justin M. Keyes2026-08-18
| | | | | | | | | | | | | | | | | | | | | | Problem: Leak reported by ASAN CI, always at Lua state init. ERROR: LeakSanitizer: detected memory leaks strbuf_init src/cjson/strbuf.c:62:22 json_create_config src/cjson/lua_cjson.c:635:5 lua_cjson_new src/cjson/lua_cjson.c:2060:5 nlua_state_add_stdlib src/nvim/lua/stdlib.c:840:3 nlua_state_init src/nvim/lua/executor.c:973:3 ... SUMMARY: AddressSanitizer: 1055 byte(s) leaked in 2 allocation(s). Analysis: `getout()` may run during `free_all_mem()` (that's why it checks `!entered_free_all_mem`). If that happens, the second `os_exit()` returns early from `free_all_mem()` then `exit()` is called and Lua state is never closed. Solution: Always call `nlua_free_all_mem()` in the early-return case.
* fix(options): ":set foo?" for Lua callbacks #41100Justin M. Keyes2026-08-01
| | | | | | | | | | | | | | | | | Problem: `:set foo=<tab>` and `:set foo?` for func/expr options set to a Lua function, always displays "v:lua". The existing "<Lua N: file:line>" form was avoided because the ref id N changes on every read of the same option. Solution: - Don't attempt to tab-complete Lua functions. - Show "<Lua file:line>" (or "<Lua>" if source file is unknown). Example: :set operatorfunc? operatorfunc=<Lua ~/.config/nvim/init.lua:42>
* refactor(exmode): Ex-mode as cmdwin + Lua #40991Justin M. Keyes2026-07-27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: POSIX-compatible Ex-mode requires special-cases all over the codebase to match various quirks that don't actually matter to users. - The main utility of *interactive* Ex-mode is its REPL behavior, and that can be achieved with `cmdwin`, which also gains extra UX benefits. - The main utility of *non-interactive* `nvim -es` is for shell scripting, where Ex-mode quirks are mostly unhelpful (e.g. the "Entering Ex mode" message). Solution: - Reimplement *interactive* Ex-mode as a "persistent, insert-mode cmdwin" in Lua. - "nvim -e/-E" is simply an alias to "gQ". - Reframe *non-interactive* Ex-mode (`nvim -es`) as "script mode". - Drop POSIX Ex-mode quirks. Improvements: - "nvim -V1 -es" output ends with a final newline! - "nvim -V1 -es" no longer shows the "Entering Ex mode" msg. (This was pointless noise, unwanted for scripting purposes.) - stdin is no longer typeahead. Scripts (":lua io.read()") can read stdin as data. - Empty line is a no-op: a stray blank line no longer moves the cursor (deviates from POSIX ex "+1"), no longer exits 1 at EOF (E501). Preserved behavior: - cursor starts at "$" - mode()=="cv" (for non-interactive) - multiline commands (:append/:function/heredoc pull continuation lines) - bare-range print - :print=>stdout - -V1=>stderr - CRLF input - continue-after-error and exit codes Dropped (regressed) POSIX behavior (non-interactive): - Event loop only ticks while/between commands, not while blocked waiting for a stdin line. - ":g/pat/visual...Q" - input()/getchar()/":s/x/y/c" no longer consume stdin lines as answers: Nvim stops at end-of-input, skipping the rest of the script, exit 0. Use ":lua io.read()" instead. - If users care about this they should use interactive Ex-mode (`gQ`). - ":@r" stops at end of the register instead of continuing to read cmdline input from stdin.
* feat(eval): declare more "fast" functions #40834Justin M. Keyes2026-07-19
|
* refactor(input): rename getchar.c => input.c #40698Justin M. Keyes2026-07-12
| | | | | | | | | | | | Problem: `getchar.c` is a quirky name and doesn't align with our existing `os/input.c` and `tui/input.c` modules, which encompass the same topic at different layers. Solution: Rename `getchar.c` => `input.c` for discoverability. Introduce `dialog.c` for functionality related to showing confirm prompts, dialogs, etc.
* refactor(lua): rename nlua_call_typvalJustin M. Keyes2026-07-06
|
* fix(lua): bufwrite message overridden by :redrawstatusJustin M. Keyes2026-07-06
| | | | | | | | | | | Problem: bufwrite message overridden by :redrawstatus command within Progress callback. Solution: - don't use globally-shared IObuf. - use vim_snprintf to deduplicate `nlua_call_luaeval`, `nlua_call_vlua`. fix https://github.com/neovim/neovim/issues/40616
* fix(lua): give nicer error message when trying to index vim.NILbfredl2026-06-29
| | | | | | | | | The added test shows the context, one expected a JSON field to be a Object but it was a null value pros: shows `vim.NIL` instead of `a userdata` cons: the context `field 'foo'` is lost. I think this is generated with internal magic which is hard to replicate.
* fix(lua): reject process exit in fast callbacks #39937Barrett Ruth2026-06-27
| | | | | | | | | | | | Problem: `os.exit()` in `nvim -l` exits through normal teardown. But, as #39783 shows, when it is called from a libuv callback, teardown polling the main loop when inside `uv_run()` can trip the recursive poll guard and cause a crash. Fast callbacks are not safe to teardown, so it's better to schedule an exit out of a callback rather than convolutedly handle this as I tried before. Solution: Reject `os.exit()` from fast callbacks with `E5560` error.
* feat(startup)!: "standalone" mode -ll is killbfredl2026-06-04
| | | | | | | | | | | | | | This was originally used because we needed a lua interpreter to run the standalone _busted_ lua application (except we used fuckery behind the scenes to fake its binary dependencies with our own binary dependencies). Now we longer do that, we instead run `test.harness` as a standard nvim -l script. as this mode is no longer used in tests it risks going to bitrot anyway. NB: -ll mode still had some theoretical benefits like quicker initialization and more "native" printing behavior, etc. But we can incrementally work on "nvim -l" mode instead of maintaining a separate special thing.
* Merge pull request #39920 from bfredl/luastringbfredl2026-05-25
|\ | | | | fix(lua): use even safer and even better error() message conversion
| * fix(lua): use even safer and even better error() message conversionbfredl2026-05-25
| | | | | | | | | | | | | | | | | | | | | | | | problem: this crashes neovim: ondska = setmetatable({}, {__tostring = error}) error(ondska) solution: make it not crash neovim
* | fix(api): fail fast if `has_lua_imp` retval looks wrong #39866Justin M. Keyes2026-05-20
|/
* fix(api): regressions with lua return values #39837bfredl2026-05-18
| | | | | fixes #39834 fixes #39833 fixes #39851
* vim-patch:9.2.0494: User commands cannot handle single args with spaces (#39854)zeertzjq2026-05-18
| | | | | | | | | | | | | | | | | | | | | | | | | | Problem: User commands cannot handle single args with spaces Solution: Add the -nargs=_ attribute (Maxim Kim) -nargs=_ allow user commands to have a single argument with spaces. For example given the following Test command and TestComplete function: ``` vim9script def TestComplete(A: string, _: string, _: number): list<string> var all = ["qqqq", "aaaa", "qq aa"] return all->matchfuzzy(A) enddef command! -nargs=_ -complete=customlist,TestComplete Test echo <q-args> ``` `:Test q a<tab>` should successfully complete `qq aa` fixes: vim/vim#20102 closes: vim/vim#20189 https://github.com/vim/vim/commit/f0e874a129a702457a383017b576eef1553f95d8 Co-authored-by: Maxim Kim <habamax@gmail.com>
* feat(api): nvim_buf_call, win_call can has multiple return values #39801bfredl2026-05-17
| | | | | | from the "because we can and it is not much code" department. (diffcount excluding tests is actually negative) fixes https://github.com/neovim/neovim/issues/39636#issuecomment-4397141270
* test: run Lua harness with nvim -lLewis Russell2026-05-13
| | | | | | | | | | | | | | | | | | Problem: The Lua test harness still ran through standalone -ll mode, so tests depended on the low-level Lua path instead of the regular Nvim Lua environment. That also meant os.exit() coverage had to carry an ASAN workaround because Lua's raw process exit skipped Nvim teardown and let LeakSanitizer interfere with the observed exit code. Solution: Run the harness and related fixtures with nvim -l. Patch os.exit() in the main Lua state to exit through getout(), so scripts observe normal Nvim shutdown while standalone -ll remains available for generator-style scripts. As a consequence, the startup test can assert os.exit() without disabling leak detection. AI-assisted: Codex
* fix(messages): fast context for for nvim_echo({kind}) callback #39755luukvbaal2026-05-12
| | | | | | | | Problem: vim.ui_attach() callback for nvim_echo() call that spoofs an internal message kind is executed in fast context. Solution: Set msg_show callback |api-fast| context dynamically at external message callsites, and for internal list_cmd", "progress" and "shell*" messages.
* refactor(excmd): pass fargs to Lua for builtin cmds #39528Justin M. Keyes2026-05-02
| | | | | | | | | | | | | | Problem: The fallback that tokenizes `eap->arg` by unescaped whitespace (when the parser doesn't pre-split via `EX_EXPAND` etc.) lives in `nlua_do_ucmd`, so only user-command callbacks got `eap.fargs`. Builtin commands routed through `nlua_call_excmd` have to re-parse the args themselves (e.g. `M.ex_lsp`). Solution: - Move the tokenization into `nlua_push_eap` so every Lua handler sees `eap.fargs`. Keep only the `EX_NOSPC` override in `nlua_do_ucmd` (the `nargs=1`/`?` case which is genuinely user-command-specific). - Drop the re-parse in `M.ex_lsp`.
* fix(ui): z=, tselect with async vim.ui.selectJustin M. Keyes2026-04-30
| | | | | | | | | | | Problem: After 55ceb31, z= and tselect don't work if `vim.ui.select` is an async provider (especially terminal buffers). Solution: Drop the `vim.wait()` approach, use an async approach. fix #39506
* feat(ui): use vim.ui.select for :oldfiles, :recoverJustin M. Keyes2026-04-30
| | | | | | | | | | | | Problem: followup to 55ceb314ca96 #39478 `:oldfiles` and swapfile `:recover` do not delegate to `vim.ui.select`. Solution: - Delegate to `vim.ui.select`. - Fix a long-standing `recover_names` bug where `concat_fnames(dir_name, files[i], true)` produced malformed `<dir>//<dir>/<file>` paths (also fixes `swapfilelist()`).
* refactor(lua): move vim.wait into runtime LuaLewis Russell2026-04-27
| | | | | | | | | | | | | | Move vim.wait into runtime/lua/vim/_core/editor.lua and replace the C entrypoint with narrow vim._core helpers for polling, UI flushing, and interrupt checks. Keep the existing interval semantics by retaining the dummy timer that wakes the loop while it is otherwise idle. Update the docs to describe the success return values correctly, and adjust the test expectation for the new vim.validate() callback error. AI-assisted: Codex
* fix(lua): don't strip debuginfo in precompile module #39191phanium2026-04-23
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: debug.getinfo on bytecode module/func don't give you detail source info. Solution: - Use `loadstring`+`string.dump` to replace LUAC_PRG(`luac`/`luajit -b`) - `string.dump(…,false)` to generate non-strip version bytecode - `loadstring(…,fname)` to specify the full source name BEFORE: $ nvim --clean +'=debug.getinfo(vim.fn.maparg("]<Space>", "n", 0, 1).callback, "Sl")' --headless +q { currentline = -1, lastlinedefined = 456, linedefined = 452, short_src = "?", source = "=?", what = "Lua" } AFTER: $ nvim --clean +'=debug.getinfo(vim.fn.maparg("]<Space>", "n", 0, 1).callback, "Sl")' --headless +q { currentline = -1, lastlinedefined = 456, linedefined = 452, short_src = "/home/xx/b/neovim/runtime/lua/vim/_core/defaults.lua", source = "@/home/xx/b/neovim/runtime/lua/vim/_core/defaults.lua", what = "Lua" }
* feat(eval): treat Lua string as "blob" in writefile() #39098Barrett Ruth2026-04-22
| | | | | | | Problem: vim.fn.writefile() treats Lua strings as Vimscript strings instead of a "binary clean" string. Solution: Treat Lua-originated strings as blob data.
* fix(excmd): nlua_call_excmd require() failure is a "lua_error"Justin M. Keyes2026-04-20
| | | | | | | | Although `nlua_call_excmd` is semantically for implementing Ex-commands, the `require()` should never fail, so that's a "Lua error". But if the call itself fails (the later `semsg` call), that's an "Ex cmd" error.
* refactor(excmd): migrate ex_terminal to LuaJustin M. Keyes2026-04-20
|
* refactor(excmd): migrate ex_checkhealth to LuaJustin M. Keyes2026-04-20
|
* feat(vimfn): use Lua for more excmds/vimfnsJustin M. Keyes2026-04-18
| | | | | | | | | | | Problem: Too much boilerplate needed to use Lua to impl an excmd or f_xx function. Solution: - Add `nlua_call_vimfn` which takes the args typval, executes Lua, and returns a typval. - refactor(excmd): lua impl for :log, :lsp
* perf(vim.fn): call Lua-implemented vim.fn.xx() directly #39166Justin M. Keyes2026-04-17
| | | | | | | | | | | | | | | | | | | | | | | | Problem: - Builtin "Vimscript" functions (f_xx) are mostly implemented in C. Partly that's because there is some boilerplate required to call out to Lua. - Calls to `vim.fn.foo()` always marshall over the Lua <=> Vimscript ("typval") bridge, even if `fn.foo()` is implemented entirely in Lua: ``` Lua => typval => Object => Lua => Object => typval => Lua. ``` Solution: Functions declared in eval.lua with `func_lua` are implemented in entirely in Lua (`_core/vimfn.lua`). - `gen_eval.lua` wires `func_lua` entries to `lua_wrapper`, which handles the typval conversion for Vimscript callers (slow path). - `nlua_call()` detects `func_lua` functions and calls the Lua implementation directly. This eliminates all conversion overhead for Lua callers (fast path). - Validate at build-time that `func`, `func_float`, and `func_lua` are mutually exclusive. - Migrate `hostname()` as a toy example, to show the idea.
* docs: news #38464Justin M. Keyes2026-03-28
|
* fix(messages): disallow user-defined integer message-id #38359Justin M. Keyes2026-03-18
| | | | | | | | | | | | | | | Problem: `nvim_echo(…, {id=…})` accepts user-defined id as a string or integer. Generated ids are always higher than last highest msg-id used. Thus plugins may accidentally advance the integer id "address space", which, at minimum, could lead to confusion when troubleshooting, or in the worst case, could overflow or "exhaust" the id address space. There's no use-case for it, and it could be the mildly confusing, so we should just disallow it. Solution: Disallow *integer* user-defined message-id. Only allow *string* user-defined message-id.
* docs: api, messages, lsp, trustJustin M. Keyes2026-03-11
| | | | | gen_vimdoc.lua: In prepare for the upcoming release, comment-out the "Experimental" warning for prerelease features.
* fix(cmdline): cmdline_block events for :lua debug.debug() #38171luukvbaal2026-03-06
| | | | | Problem: :lua debug.debug() is missing cmdline_block events. Solution: Emit cmdline_block_show/append/hide events for :lua debug.debug().
* fix: wait() checks condition twice on each interval (#37837)zeertzjq2026-02-13
| | | | | | | | Problem: wait() checks condition twice on each interval. Solution: Don't schedule the due callback. Also fix memory leak when Nvim exits while waiting. No test that the condition isn't checked twice, as testing for that can be flaky when there are libuv events from other sources.
* fix(lua): close vim.defer_fn() timer if vim.schedule() failed (#37647)zeertzjq2026-02-01
| | | | | | | | Problem: Using vim.defer_fn() just before Nvim exit leaks luv handles. Solution: Make vim.schedule() return an error message if scheduling failed. Make vim.defer_fn() close timer if vim.schedule() failed.
* fix(ui): textlock still causes issues for UI callbacks #37513luukvbaal2026-01-27
| | | | | | | Problem: There are still ways to run into textlock errors with vim.ui_attach callbacks trying to display a UI event. Solution: Disregard textlock again during vim.ui_attach() callbacks (also when scheduled). Partially revert 3277dc3b; avoiding to flush while textlock is set is still helpful.
* fix(lua): correct line number reporting for options set in coroutines (#37463)Tommy Guo2026-01-21
|
* build: ship "_core/*" as bytecode (built-into Nvim binary)Justin M. Keyes2025-12-30
| | | | | | | | | | | | | | | | | | | | | | | | | | Problem: We want to encourage implementing core features in Lua instead of C, but it's clumsy because: - Core Lua code (built into `nvim` so it is available even if VIMRUNTIME is missing/invalid) requires manually updating CMakeLists.txt, or stuffing it into `_editor.lua`. - Core Lua modules are not organized similar to C modules, `_editor.lua` is getting too big. Solution: - Introduce `_core/` where core Lua code can live. All Lua modules added there will automatically be included as bytecode in the `nvim` binary. - Move these core modules into `_core/*`: ``` _defaults.lua _editor.lua _options.lua _system.lua shared.lua ``` TODO: - Move `_extui/ => _core/ui2/`
* fix(lua): relax `vim.wait()` timeout validation #36900skewb1k2025-12-10
| | | | | | | | | Problem: After bc0635a9fc9c15a2423d4eb35f627d127d00fa46 `vim.wait()` rejects floats and NaN values. Solution: Restore the prior behavior, while still supporting `math.huge`. Update tests to cover float case.
* fix(lua): vim.wait(math.huge) fails #36885skewb1k2025-12-09
| | | | | | | | | | Problem: `nlua_wait()` uses `luaL_checkinteger()` which doesn't support `math.huge` since it's double type. On PUC Lua this fails with 'number has no integer representation' error and on LuaJIT this overflows int. Solution: Use `luaL_checknumber()` and handle `math.huge`.
* feat(vimscript): log function name in "fast" message #32616Matthieu Coudron2025-10-21
|