aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
Commit message (Collapse)AuthorAge
* fix(options): extend dry-run validationLewis Russell4 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: nvim_set_option_value() dry runs skip checks in did_set_* callbacks. This logic also prepares values needed to apply the option, such as tab widths or a compiled regexp. Moving the checks into validation callbacks needs a way to save that work for did_set_*. Solution: Store prepared values in optset_T so did_set_* can consume them after the option is stored. Dry runs perform the same validation, then free the prepared values without changing live state. This extends dry-run validation for: - 'cedit': reject invalid command-line window keys. - 'completeitemalign': require each completion column exactly once. - 'cursorlineopt': reject empty values and conflicting line modes. - 'encoding': accept only UTF-8 and its aliases. - 'fileencoding': reject lists and local changes with 'nomodifiable'. - 'messagesopt': require mandatory fields and enforce numeric limits. - 'spellcapcheck': return regexp errors, including under :silent!. - 'spellsuggest': reject conflicting suggestion modes. - 'varsofttabstop' and 'vartabstop': reject invalid tab widths. - 'wildmode': reject more than four completion stages. 'makeencoding' also uses the shared encoding preparation. Separating value preparation exposed a bug in 'vartabstop' and 'varsofttabstop': failed assignments could discard local tab widths, and global assignments could overwrite them. Fix this by preparing new widths separately and applying them only after a valid local assignment. AI-assisted
* fix(api): nvim_set_option_value() "remove" ignores non-adjacent items #42351Justin M. Keyes5 days
| | | | | | | | | | | | | Problem: `nvim_set_option_value('fo', {'c','r','o'}, {operation='remove'})` does nothing on "jcqrol": the items are joined into one `:set-=` value, which only matches a contiguous substring. Removing map keys, e.g. {'eol','space'} from 'listchars', never matches. `vim.opt:remove{…}` inherits this. (Regression from f34ee3da80e8; 429338e74bf4 fixed the case where the flags are adjacent and in order.) Solution: Remove each item separately.
* multicursor: v:cascading #42289Evgeni Chasnovski7 days
| | | | | Problem: No way to check if cascade is in action. Solution: Add `v:cascading` variable.
* fix(setreg): use better estimate of register widthbfredl8 days
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | vim-patch:9.2.1175: setreg() block width wrong for unprintable chars When yanking, the width of a <c-v>{motion}y register is determined by the virtual colums of the text. However in setreg() in 'b' mode use an idosyncratic width measurement where C0 control chars (ASCII 0x00 - 0x19) and invalid UTF-8 bytes have width 1 instead of their display width (2 or 4 cells). Consider the following test case: let strings = ['"reference', '"Übel', "\"aa\x07bb", "\"qq\x82", "\"x\nbabbel"] for string in strings call append('$', string) exec "normal G0\<c-v>$\"ay" let one = getregtype('a') if string != strings[-1] call setreg("b", string, 'b') let two = getregtype('b') else let two = "na" endif call setreg("c", [string], 'b') let three = getregtype('c') call append('$', '"yank: '.one.", string: ".two.", list: ".three) endfor AFter this fix, all the three ways of measuring the width gives equal values (or two, in the case of not being able to use setreg() with a plain string in the first case)
* fix(windows): server dies with terminal after :restartJustin M. Keyes10 days
| | | | | | | | | | | | | Problem: On Windows, a server started by :restart attaches to the TUI's console. Closing the host-terminal kills the server, even after :detach or :detach!: the swap to a hidden console only happens when a stdio UI disconnects, but after :restart the TUI is on a socket. Solution: Track whether the console is inherited from the parent. When the last UI disconnects and the server keeps running, swap an inherited console for a hidden one.
* refactor(ui): remove "stop" UI eventJustin M. Keyes10 days
| | | | | | | | | Problem: "stop" has been a no-op since the TUI moved out-of-process. Remote UIs only see EOF, and nothing implements it. Solution: Remove it.
* feat(api): nvim_chan_set()Justin M. Keyes10 days
| | | | | | | | | | | | | | | | | | | Problem: Only the stdio channel can "own" a server (self-exit on close). After :restart the TUI reconnects over a socket, so the restarted server does not have "self-exit" behavior when the channel closes (e.g. by UI disconnect, host-terminal close, etc.), which leaves a dangling server. Solution: - Introduce `nvim_chan_set`. (`nvim_set_client_info` doesn't fit: exposing it to Lua would require a `channel` param, which is not backwards-compatible, plus it's awkward because it doesn't merge info.) - Broadcast per-channel properties in the "restart" UI event as an opaque dict (a potentially useful pattern for other UI-events in the future). - UIs are expected to restore the channel properties on restart. - `nvim_get_chan_info()` reports "detach". - Remove `nvim__chan_set_detach()`.
* Merge pull request #42086 from bfredl/multicharbfredl12 days
|\ | | | | refactor(mbyte): use StrCharInfo/ClusterInfo also for str[len] cases
| * refactor(mbyte): use StrCharInfo/ClusterInfo also for str[len] casesbfredl13 days
| | | | | | | | | | | | | | | | part of a series, next big one is gonna be bring utf_ptr2schar and friends into the New world. after that it might be worth brushing of some benchmarks and re-microoptimize the hottest loops. also some const-y constess but it is fine.
* | Merge pull request #42217 from bfredl/redirectingbfredl13 days
|\ \ | |/ |/| fix(lua): regression with `print()` in headless mode when redirecting
| * 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
* | fix(display): pad virtual text after listchars eol #41292Langning Zhang2026-10-03
|/ | | | | | | | | Problem: End-of-line virtual text is drawn directly after a displayed listchars eol character. Solution: Preserve the normal one-cell separator after the eol character. AI-assisted
* refactor(multicursor)!: drop nvim_mcursor #42156Justin M. Keyes2026-09-30
| | | | | | | | | | | | | | Problem: `nvim_mcursor` is not fully baked, and not strongly motivated, currently. The main programmatic interface for cursors is the "nvim.multicursor" extmarks namespace. Solution: Drop `nvim_mcursor`. Add an internal hook so that multicursor can react when extmarks are added to the "nvim.multicursor" namespace. TODO: If extmarks/namespaces are clumsy to work with, we should _fix that_ rather than adding wrappers.
* 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(api): include all supported window border stylesLewis Russell2026-09-25
| | | | | | | | The border metadata omitted the empty string and bold styles accepted by the API. Include both literals and regenerate the Lua types so valid window configurations pass type checking. AI-assisted
* refactor(options): simplify option callback argumentsLewis Russell2026-09-24
| | | | | | | | | | | | | Problem: Option callbacks carry untyped buffer and window pointers, requiring casts. Helper arguments also pass unused flags and an error value that is always NULL when OptionSet is triggered. Solution: Use typed pointers in optset_T and remove the redundant arguments and checks. Clarify that sandbox assignments also affect option security. AI-assisted
* fix(lint): fix some warnings in clang-tidy 22bfredl2026-09-23
| | | | CI is currently using clang-tidy 21 but prepare for the future
* fix(api): preserve option trust during mergesLewis Russell2026-09-22
| | | | | | | | | | | | | Problem: API append, prepend, and remove operations reach the option setter as full replacements. This can clear an expression's untrusted flag and allow it to write files, unlike equivalent :set operations. Solution: Pass replacement status through the option setters so merges preserve the existing value's trust restrictions. AI-assisted
* refactor(api): reuse parse_cmdline in nvim_cmd #38508glepnir2026-09-22
| | | | | | | | | Problem: nvim_cmd() duplicates Ex parsing: it sets the address type and default range itself and builds the whole command line in build_cmdline_str(). Solution: Build only the range, command name and arguments, and let parse_cmdline() fill in exarg_T.
* refactor(multicursor): view/extmark/region logic #42030Justin M. Keyes2026-09-21
| | | | | | | | | | Problem: Redundant logic. Solution: Deduplicate. Also: `winrestview()` no longer forces a status-line redraw and resending `win_pos` (`win_new_width()` on unchanged width).
* refactor(option): simplify error buffer handlingLewis Russell2026-09-21
| | | | | | | | | | | | | | | | | | | | | | | | | | 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
* fix(options): validate nvim_set_option_value() dry runsLewis Russell2026-09-18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: nvim_set_option_value() with dry_run=true accepts invalid values such as foldmethod='nonsense'. Validation is mixed with side effects in the did_set_* callbacks, so dry runs skip it. Solution: Split value validation out of the did_set_* callbacks into separate validation_cb callbacks. Use these checks for both normal assignments and nvim_set_option_value() dry runs. Keep side effects in did_set_*. Replace direct foldenable/foldlevel assignments in C folding commands with setters. This gives C commands the same OptionSet and synchronization behavior as Lua assignments. Use normal setters for 'tabstop' and 'vartabstop' in :retab so C code indentation and folds based on indentation use the new tab widths. Direct assignments could leave them using the old widths. :retab temporarily turns off 'list' to calculate tab widths. Previously, :retab -1 reported an error and returned without restoring 'list'. Check the argument before turning 'list' off, so an invalid argument leaves the option unchanged. AI-assisted
* feat(api): add ev.win to autocmd callback args #39826glepnir2026-09-09
| | | | | | | | Problem: Autocmd callbacks currently have to rely on curwin, which may already have changed by the time they run. This is especially noticeable for WinNew, WinClosed, WinResized and WinScrolled. Solution: Track the window in the autocmd context and expose it as ev.win. Pass it explicitly for the window events that need it.
* Merge pull request #41751 from bfredl/stringly_nilsbfredl2026-09-08
|\ | | | | test(ci): non fatal errors for [NULL] safety in vim_snprintf
| * fix(api): do not pull a fast one for nvim_del_augroup_by_idbfredl2026-09-08
| | | | | | | | | | | | | | | | This is a bit more boilerplate because of painful impedance mismatch (is augroup names the root source of truth? is ids the source of truth? who knows? what does truth even mean?), but show an error reflecting what the caller actually tried (they passed in an invalid id, not a null string)
* | fix(api): leaked error message in nvim_win_set_buf() #41688Volodymyr Chernetskyi2026-09-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Both handle lookups write into the same `Error` before either one is checked, and `api_set_error()` unconditionally `xmalloc`s `err->msg` without freeing what is already there. When both handles are invalid, the message allocated for the window is silently overwritten by the one for the buffer and leaked. Solution: Check the window before looking up the buffer. As a side effect the reported error no longer names the buffer when the window was wrong too. AI-assisted
* | fix(api): leaked window set in nvim__ns_set() #41689Volodymyr Chernetskyi2026-09-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: The early return for an invalid window handle bypasses the `set_destroy()` at the end of the block, so the set's backing allocation leaks whenever an earlier iteration already called `set_put()`. Triggered by `{ wins = { valid_win, 9999 } }`. Solution: Destroy the set before returning. The new test passes either way, since the leak is only visible to a sanitizer; it is there so the ASAN job covers the path. AI-assisted
* | fix(api): leaked error message in nvim_eval_statusline() #41690Volodymyr Chernetskyi2026-09-04
|/ | | | | | | | | | | | Problem: `find_window_by_handle()` returns NULL only after `VALIDATE_INT` has already set `err`, so the `api_set_error()` that followed allocated a second message over the first pointer and leaked it. Solution: Drop the redundant call and keep the helper's message, which is already set and better worded. AI-assisted
* feat(multicursor): MC HAMMER #41587Justin M. Keyes2026-09-01
| | | | | | | | | | | | | | | | | | | | | Other (squashed) commits: fix(tui): emit ui_send output atomically with the frame Problem: tui_ui_send() writes directly to the TTY, bypassing the output buffer. Sequences sent via nvim_ui_send() (e.g. kitty multiple-cursors, or visual-dot-repeat) always arrive in a separate TTY write from the frame they were computed for. This manifests as "tearing", or e.g. in the case of multicursor the terminal renders text with stale cursor overlays. Solution: - tui_ui_send(): while a frame is being assembled (pending invalid regions or buffered output), buffer instead of writing directly. - Out-of-frame sends (tty queries, clear-on-disable) still write immediately. - mcursor.lua: emit the terminal-cursor update at the end of the redraw cycle (`on_end`, when screen positions are final) instead of vim.schedule().
* fix(cmdwin): allow a user to switch to other buffers #41199Rob Pilling2026-08-28
|
* docs: misc #41452Justin M. Keyes2026-08-23
| | | | | 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>
* feat(extmark): virt_lines can highlight until EOL #41289Goldpigg2026-08-18
|
* docs: misc, cwd, vimscript.txt #41356Justin M. Keyes2026-08-17
| | | Extract vimscript.txt from repeat.txt
* feat(input)!: CmdAtom event #41297Justin M. Keyes2026-08-14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: There is no unified notion of a "user action". Vim processes input by one-char-at-a-time, and mostly throws away any hints it might gather about the user's action, with one exception: it stores the last _edit_ action (the "redo buffer", encoded as unstructured `["x][v][count]body` bytes). Plugins can only observe individual keys (vim.on_key) and high-level effects (TextChanged, CursorMoved). Solution: - Users can subscribe to `CmdAtom` events to handle any user action. - Event is deferred; handlers cannot cancel or interfere with user actions. - Capture `CmdSpec` from the normal/insert/visual subsystems. - typeahead/readahead stay unstructured (`buffheader_T`): they are key streams, not commands. - the redo/record buffers become `StringBuilder`: fewer allocations/copies. - Repurpose the input/redo engine to accept `CmdSpec` objects. "atom": one repeatable unit of user input, as a resolved (post-mapping) keysequence plus structured fields. Only user actions, not `:normal`, API calls, or non-"t" `feedkeys`. BREAKING: dot-repeat of an Insert session, replays the entire session including cursor-moves (:help ins-repeat). BREAKING: dot-repeat of a Visual operation, replays the selection instead of operating on a fixed-size region.
* feat(cwd)!: :lcd! (bang), rearrange :bcd/:lcd/… scope precedence #41194Justin M. Keyes2026-08-07
| | | | | | | | | | | | | | | | 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.
* docs: misc, :bcd, slug()Justin M. Keyes2026-08-06
|
* refactor(options): simplify "unset" logicJustin M. Keyes2026-07-31
|
* refactor(options): memory managementJustin M. Keyes2026-07-31
| | | | | | | | | | | | | | | | Problem: Numerous callers have to manually check optval ownership (i.e. whether, and how, to release) via `is_callback_option`, `option_is_global_local`, etc. This is fragile, hard to use correctly; and if we introduce another optval variant in the future, we'll have to redo all of these careful checks and boilerplate again. Solution: Provide a unified system and use it everywhere: optval_free_owned optval_is_owned optval_own
* feat(options): lua closure/function optionsJustin M. Keyes2026-07-31
| | | | | | | | | | | | | | | Problem: Cannot assign Lua functions/closures to "func" ('completefunc', 'tagfun', …) or "expr" ('foldexpr', 'indentexpr', …) options. Solution: - Store "func"/"expr" options as `Callback` instead of string. - Delete oceans of copy-pasted code. - BREAKING: LuaRef returned via RPC/Vimscript is now represented as `"<Lua N: file:line>"` (like what `:map` shows) instead of `nil`. - Note: `man.vim` still uses `v:lua` string, bc it's a vimscript ftplugin. Helped-by: Lewis Russell <lewis6991@gmail.com>
* refactor(options): naming #41046Justin M. Keyes2026-07-30
| | | | | - "obj" refers to structured (non-scalar `Object`) option values. - "optval" generally refers to the internal scalar (legacy ":set"-style) option value.
* refactor(options): drop OptVal, use ObjectJustin M. Keyes2026-07-29
| | | | | | | | | | | | | 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`.
* fix(api): add `lhs` option for keymap deletionBarrett Ruth2026-07-25
|
* docs: misc #40847Justin M. Keyes2026-07-25
| | | | Co-authored-by: Barrett Ruth <br@barrettruth.com> Co-authored-by: Nathan Zeng <nathan.j.zeng@gmail.com>
* refactor(options): store dict options in :set-string formJustin M. Keyes2026-07-24
| | | | | | | | | | The parent commit made a valiant effort to store "dict options" in their reified form, but this is more trouble than it's worth: - inconsistent model for developers to understand. - string lifetime issues (the "varp" convention is to pass around an aliased, long-lived option value). - lots of extra plumbing to deal with the 2 different option-storage paradigms.
* feat(options): schema, "dict" options, messagesJustin M. Keyes2026-07-24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Options parsing is still painful for dict-style options. Solution: schema-maxxing => better `opt:get()` (will be the basis for `vim.o()`), unified (and more-detailed) err msgs. - Drop bespoke structure-builder in `_core/options.lua`. - Define `schema` for all non-primitive options (except 'guicursor' and statusline-style options); generate reified keysets `OptKeyDict`). - Generate 'fillchars' => `fcs_tab`, 'listchars' => `lcs_tab`. - `nvim_set_option_value`: - Return the improved structures. Also from `vim.opt.x:get()`. - Eliminate api <=> lua roundtrip, centralize option structure handling. - Improve/unify errors. - Bump ERR_BUFLEN 80 → 256 so the "one of" list isn't truncated. - Eliminate old 'diffopt' order-dependence (`iwhiteall` before `iwhite`) Error samples: Typed-key path (opt_strings_check → diffopt/mousescroll/breakindentopt): E474: Unknown item 'foo' E474: 'context' requires a number E474: 'ver' number is out of range E474: 'algorithm' must be one of: myers, minimal, patience, histogram E474: 'filler' does not take a value Related: - #31084 - #34661 - #31820 - #14739 - #20107 - fix #18875 - :get() returns `{ sbr = true, shift = '3' }` (reified-keyset) instead of `{'sbr', 'shift:3'}` - Setting via table now works too. `object_as_optval_for` `is_map` now recognizes struct options. - fix #30296 - instead of `E474: Invalid argument`, errors now look like: ``` E474: Invalid value 'x', expected one of: single, double: ambiwidth=x E474: Unknown item 'foo': diffopt=foo E474: 'context' requires a number: diffopt=context:x ``` simplify `win_float_parse_option` from #26799.
* feat(float): 'previewpopup' option #26799glepnir2026-07-23
| | | | | | | | Problem: The preview-window (:pedit, etc.) always uses a split, but it would be useful as a floatwin (or "popup"). Solution: Support Vim's 'previewpopup' option.
* feat(api): mark nvim_create_autocmd as api-fast #40836Justin M. Keyes2026-07-19
| | | | | | | | | | | | | | | | | | | | | | | | Problem: nvim_create_autocmd() isn't |api-fast|, so modules that create autocmds (e.g. vim.treesitter.query) can't be require()d in a fast event context. Solution: Mark it |api-fast|. Compile autocmd patterns with RE_NOBREAK so aucmd_next() won't os_breakcheck() mid-iteration, where a fast nvim_create_autocmd() could realloc the autocmds vector and dangle the caller's AutoPat/AutoCmd. RE_NOBREAK is low-risk because: - aucmd_next()'s loop checks CTRL-C: `(for (… i < apc->ausize && !got_int; …)`. - `line_breakcheck()` (`autocmd.c:1912`) runs once per matched autocmd. - Each autocmd _execution_ runs through `do_cmdline`, which has its own breakchecks. However this does admit risk of a pathological case: a catastrophic-backtracking glob matched against a very long `User` event-pattern. Co-authored-by: Riley Bruins <ribru17@hotmail.com> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
* feat(eval): declare more "fast" functions #40834Justin M. Keyes2026-07-19
|
* docs: misc, remove some old help tags #40214Justin M. Keyes2026-07-18
| | | | | | | | | | - Remove old help tags: they add noise to cmdline completion. Co-authored-by: acehinnnqru <acehinnnqru@gmail.com> Co-authored-by: KangaZero <samuelyongw@gmail.com> Co-authored-by: Simone Ragusa <hi@interrato.dev> Co-authored-by: Chinmay Dalal <~chinmay/public-inbox@lists.sr.ht> Co-authored-by: c