| Commit message (Collapse) | Author | Age |
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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 mode when redirecting
|
| | |
| |
| |
| |
| |
| |
| |
| |
| | |
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
|
| |/
|
|
|
|
|
|
|
| |
Problem:
`vim._with({ buf = 0, win = 0 }, f)` fails an assert in ctx_switch().
vim._with() allows `buf` with `win` when `win` shows `buf`, but
nlua_with() passes both, and ctx_switch() takes only one target.
Solution:
Ignore `buf` if `win` is given; the window implies its buffer.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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..
|
| |
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
| |
CI is currently using clang-tidy 21 but prepare for the future
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem: Option validators and setters repeatedly pass error buffers and
their sizes separately. Some setters return messages in static storage.
Solution:
- Add CharBuf for borrowed writable storage, with its length including
space for a terminating NUL.
- Move option error buffers to the callers that report errors. Preserve
existing buffer sizes, truncation, and calls that do not need a
message.
- Consolidate option error formatting and the duplicated code that lists
valid option values.
- Return error messages directly from do_one_set_option().
- Remove unused arguments from get_option_newval() and
set_option_value_for().
- Handle legacy TTY assignments in the existing callers and remove the
redundant compatibility wrapper.
- Reuse CharBuf for Tree-sitter query errors.
- Pass CharBuf through the statusline and statuscolumn builders,
retaining the buffer sizes provided by their callers, including title
formatting.
AI-assisted
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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).
|
| |
|
|
|
| |
Co-authored-by: darkdi <rantovov5@gmail.com>
Co-authored-by: Qiaoxi Guo <28090444+breadtitor@users.noreply.github.com>
Co-authored-by: zaveshaa <zaveshaa@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
- buf-local CWD scope is lower priority than :lcd, which is weird.
```
win > buf > tab > global
```
- No way to clear current CWD at a given scope.
Solution:
- Rerrange scope precedence to:
```
buf > win > tab > global
```
- Introduce "bang" variants (`:bcd!`/`:lcd!`/`:tcd!`) which clears the
local CWD for the given scope.
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
- Explicit `:bcd` (etc.) persists from `nvim_buf_call()` but not from an
autocmd handler targeting a hidden buf (`LspAttach`, `TermRequest`, …),
which needs a `vim.schedule()` workaround.
- `vim._with()` is supposed to work as a "sandbox", discarding
side-effects, but it leaks CWD changes: `:lcd` from a `win` context,
any chdir from a visible-buffer context.
Solution:
- Explicit :cd/:tcd/:bcd during a temp context persists by default.
- "Ambient" directory changes ('autochdir', existing win-local CWD,
etc.) are still undone, as before.
- Add `kCtxKeepDirs`: snapshot/restore the target's full CWD state
(w/b/tp-local, global, cwd). Used by `vim._with()` and `'inccommand'`,
which must not leak state.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
The object subsystem has an intermediate representation for no real
reason. Besides the code cost, this also adds an extra (api <=> OptVal)
conversion step, which is a (small) perf cost.
Solution:
We already have `Object`, so use it instead.
- drop `OptVal`, `OptValData`, `OptValType`, and related boilerplate.
- add `kObjectTypeUnset`.
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problems:
1. Can't get individual parts of a key-chord separately: modifiers, key.
2. Can't separate a key-combo into individual key-chords.
Solution:
Enhance `vim.keycode()` to optionally return a structured parse result
as a list of key-chords:
- `key_raw` the key-chord (problem 2)
- `mod` the modifiers of `key_raw` (problem 1)
- `key_orig` the key part of the key-chord, only here if differing from `key`
(this doesn't solve any of the above mentioned problems, but it may provide
useful and it's (in terms of code) free)
- `key` a normalized version of `key_orig` (solving problem 1), example(the
first is `key_orig` and second is `key`): `lt` and `<`, `Bar` and `|` (in
`<C-Bar>`)
|
| |\
| |
| | |
build(wasm): bundle runtime files into MEMFS
|
| | | |
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
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.
|
| | | |
|
| | | |
|
| |/
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
All wasm parsers shared a single global TSWasmStore via
ts_parser_set_wasm_store(). A TSWasmStore is owned by exactly one parser:
ts_parser_delete() frees it through ts_wasm_store_delete(). So the first
wasm parser collected freed the shared store, leaving the global pointer
dangling, and creating the next wasm parser dereferenced freed memory in
ts_wasm_store_reset() -> wasmtime_store_context(), crashing with SIGSEGV.
Give each parser its own store via ts_wasm_store_new() instead. This is
the 1:1 store-per-parser model intended by tree-sitter (see
tree-sitter/tree-sitter#3454): the global store remains only as the
language loader, ts_parser_delete() cleanly frees each parser's own
store, and the wasm engine is shared safely because ts_wasm_store_new()
clones its engine reference internally.
AI-assisted: Claude Code
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |\
| |
| | |
fix(lua): use even safer and even better error() message conversion
|
| | |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
problem:
this crashes neovim:
ondska = setmetatable({}, {__tostring = error})
error(ondska)
solution:
make it not crash neovim
|
| |/ |
|
| |
|
|
|
|
|
|
| |
Problem:
`aucmd_restbuf` must be guarded in case `aucmd_prepbuf` wasn't called.
Solution:
Update `aucmd_restbuf` to be a no-op if `aucmd_prepbuf` wasn't called.
This requires `aco` to be zero-initialized.
|
| |
|
|
|
| |
fixes #39834
fixes #39833
fixes #39851
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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>
|
| |
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
CI currently uses clang-tidy 20, but this affects local builds
and CI is going to be upgraded sooner or later.
Some remaining systematic issues:
- clang-tidy warns agains any atoi() or atol() usage (because of no
error handling)
- functions which takes (char *fmt, char *only_string_arg) and expect
fmt to contain exactly one "%s" usage.
- error: initializing non-local variable with non-const expression depending on
uninitialized non-local variable (cppcoreguidelines-interfaces-global-init)
This is a much worse problem in C++ (hence C++ core guidelines) where
initialization is intermingled with arbitrary code execution. I
"think" in plain C, the linker will either resolve all these
deterministically or barf an error. But with some restructuring
we could make all static initialization actually static..
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
parser_gc() calls ts_parser_delete() but leaves the userdata pointer
pointing to freed memory. If the GC finalizer runs at an unexpected time
(e.g. inside nvim_buf_get_lines #39411), a stale pointer could cause a crash.
Solution:
- NULL out `*ud` after ts_parser_delete() in parser_gc()
- Update parser_check() to handle NULL with a clear error message,
guarding all parser methods against UAF
Co-authored-by: Lewis Russell <lewis6991@gmail.com>
Signed-off-by: Szymon Wilczek <swilczek.lx@gmail.com>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
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`.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Problem:
vim._with may silence all cmdline-errors if emsg_silent=true, silent=false.
Steps to reproduce:
`nvim --clean -u repro.lua`, then `:echoerr 123`, nothing is shown.
local api, fn = vim.api, vim.fn
-- api.nvim_create_autocmd("CursorMovedC", {
api.nvim_create_autocmd("CmdlineChanged", {
callback = function(args)
if args.match ~= ":" then
return
end
-- vim.cmd([[silent! ]])
vim._with({ emsg_silent = true }, function()
-- return api.nvim_parse_cmd(fn.getcmdline(), {})
end)
end,
})
Solution:
Force CMOD_SILENT if CMOD_ERRSILENT.
|
| |
|
|
|
|
|
|
|
|
|
| |
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
|