Commit Graph

21023 Commits

Author SHA1 Message Date
zeertzjq
cc25b2f13c vim-patch:9.2.0960: double-free in string_reduce() (#41357)
Problem:  string_reduce() copies *rettv into argv[0] before calling
          eval_expr_typval().  When the evaluator fails early, rettv is
          never reset and still aliases argv[0] v_string.
          clear_tv(&argv[0]) frees it, leaving rettv dangling and when
          in vim9script get_func_tv() frees it again (Ave Dva).
Solution: Set rettv->v_type = VAR_UNKNOWN like what is done in
          list_reduce() and tuple_reduce(), use tv_get_string_strict()
          in f_reduce()

closes: vim/vim#21048

Supported by AI.

cd59994c45

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-08-18 09:03:27 +08:00
Justin M. Keyes
b107154ba2 docs: misc, cwd, vimscript.txt #41356
Extract vimscript.txt from repeat.txt
2026-08-17 13:37:08 -04:00
Justin M. Keyes
98053bfecf perf(input): drop buffheader_T #41353
Problem:
`buffheader_T` is a linked list (Vim's favorite data structure) with
complex bookkeeping, optimized for ancient hardware:

1. Memory topology: On old platforms (Amiga 512KB without MMU, MS-DOS
   64KB segments), large contiguous allocations were hazardous (no VM).
2. Never-move appends: `add_buff()` fills spare space or links a new
   block.
3. OOM "recovery": a failed block allocation only loses one append.

To avoid OOM, it prefers to allocate small, linked chunks, instead of
resizing one continguous slice. Each stuff/drain cycle costs
a malloc+free.

Solution:
Replace Vim's favorite data structure with Nvim's favorite data structure.

Nvim doesn't have granular handling of OOM (`xmalloc`), and hardware has
changed: caches favor contiguous memory, allocators handle
fragmentation. And these buffers are ~kb scale, so OOM is irrelevant on
any system that can run Nvim.

- Use a flat `StringBuilder` + `read`/`insert` offsets.
- Keeps capacity (does not shrink) until `free_buff`.
- "Steady state" allocates nothing: 1 fewer malloc+free per dot-repeat.
2026-08-17 07:55:47 -04:00
Justin M. Keyes
5f07fc91c2 refactor(cmdatom): drop RedoBuf #41351
Problem:
`RedoBuf` is mostly indirection. It has a mild benefit as an "ownership"
signal but it counteracts the general goal of unifying how "redo state"
is passed throughout the system, tends to sprout redundant interfaces,
and reduces clarity.

Solution:
Add `CmdSpec.body` to hold the "prefixless" key sequence.
Reuse `CmdSpec` to represent a "redo" buf.
2026-08-17 05:37:06 -04:00
Justin M. Keyes
ea6abf15fe refactor(cmdatom): do "redo prep" in one place #41348
Problem:
Redo prep is scattered/duplicated.
- `do_pending_operator()` has 3 prep blocks whose conditions must be in
  sync with `atom_capture_op()`.
- insert.c, spell_suggest() hand-roll `redo_new()` + `redo_append_xx()`
  sequences.
- prep_redo() has 2 roles, decided by `keys != NULL`.

Solution:
- `atom_capture_op()` is the "operator" entry point: capture, then
  prep.
- Extract `prep_redo_visual()`, `atom_capturable()`.
2026-08-17 01:55:14 -04:00
not_compiled
8c0bf18374 fix(spell): avoid invalid window state after async spell select (#41346)
Problem:
When `z=` delegates to `vim.ui.select()`, the picker may change the
current window before returning. `spell_suggest()` then continues to the
cursor restoration branch with the new window and assigns `prev_cursor`,
which belongs to the original window. This can leave Normal mode with an
invalid cursor position and produce E315.

Solution:
Clean up the spell suggestion state and return immediately after handing
control to `vim.ui.select()`.
2026-08-17 11:16:11 +08:00
Justin M. Keyes
581ce0b3da fix(cmdatom): <Cmd> mappings #41347
Problem:
`<cmd>` mappings do not emit `CmdAtom.text`.
`<cmd>` and Lua-callback mappings that edit the buffer apply only at the
primary cursor, not cascaded (multicursor).

Solution:
Capture the `<cmd>` command in getcmdkeycmd().
Add kKeyOpaque ("no capturable keys"); narrow kKeySynthetic ("not
a keystroke") to K_EVENT/K_IGNORE, so an opaque mapping's edit still
sets `map_edit` and cascades via LHS-replay.
2026-08-16 18:00:55 -04:00
Justin M. Keyes
0e436350a5 refactor(cmdatom): atom_redo_keys #41345
Some names/comments are misleading.
Also add some asserts.
2026-08-16 16:14:33 -04:00
Justin M. Keyes
aaf57a053d fix(coverity): false positives in kvec usages #41341
Coverity can't follow kv_ensure_space()'s `kv_roundup32()` bit math, so
every kv_concat_len() looks like an overrun; and it doesn't know
`kv_push()` allocates when `size == capacity`.

    _____________________________________________________________________________________________
    CID 653191:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input.c: 3536             in paste_store()
    3530
    3531         if (s > start) {
    3532           if (need_redo) {
    3533             kv_concat_len(redobuff.cur.keys, start, (size_t)(s - start));
    3534           }
    3535           if (need_record) {
    >>>     CID 653191:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "recordbuff.items" at offset corresponding to index variable "recordbuff.size" through dereference in call to "memcpy".
    3536             kv_concat_len(recordbuff, start, (size_t)(s - start));
    3537           }
    3538         }
    3539
    3540         if (s < str_end) {
    3541           int c = (uint8_t)(*s++);

    _____________________________________________________________________________________________
    CID 653190:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input.c: 730             in redo_append_spec()
    724         return;
    725       }
    726
    727       while (*s != NUL) {
    728         if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
    729           // Insert special key literally.
    >>>     CID 653190:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "redobuff.cur.keys.items" at offset corresponding to index variable "redobuff.cur.keys.size" through dereference in call to "memcpy".
    730           kv_concat_len(redobuff.cur.keys, s, 3);
    731           s += 3;
    732         } else {
    733           sb_add_char(&redobuff.cur.keys, mb_cptr2char_adv(&s));
    734         }
    735       }

    CID 653189:         (OVERRUN)
    /src/nvim/input.c: 3533           in paste_store()
    /src/nvim/input.c: 3536           in paste_store()

    _____________________________________________________________________________________________
    CID 653189:           (OVERRUN)
    /src/nvim/input.c: 3533             in paste_store()
    3527                && *s != NL && !(crlf && *s == CAR)) {
    3528           s++;
    3529         }
    3530
    3531         if (s > start) {
    3532           if (need_redo) {
    >>>     CID 653189:           (OVERRUN)
    >>>     Overrunning dynamic array "redobuff.cur.keys.items" at offset corresponding to index variable "redobuff.cur.keys.size" through dereference in call to "memcpy".
    3533             kv_concat_len(redobuff.cur.keys, start, (size_t)(s - start));
    3534           }
    3535           if (need_record) {
    3536             kv_concat_len(recordbuff, start, (size_t)(s - start));
    3537           }
    3538         }
    /src/nvim/input.c: 3536             in paste_store()
    3530
    3531         if (s > start) {
    3532           if (need_redo) {
    3533             kv_concat_len(redobuff.cur.keys, start, (size_t)(s - start));
    3534           }
    3535           if (need_record) {
    >>>     CID 653189:           (OVERRUN)
    >>>     Overrunning dynamic array "recordbuff.items" at offset corresponding to index variable "recordbuff.size" through dereference in call to "memcpy".
    3536             kv_concat_len(recordbuff, start, (size_t)(s - start));
    3537           }
    3538         }
    3539
    3540         if (s < str_end) {
    3541           int c = (uint8_t)(*s++);

    _____________________________________________________________________________________________
    CID 653188:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input_cmdatom.c: 216             in atoms_concat_keys()
    210
    211     /// Concatenates the keys of multiple atoms into one (allocated) string.
    212     static String atoms_concat_keys(CmdAtomVec atoms)
    213     {
    214       StringBuilder keys = KV_INITIAL_VALUE;
    215       for (size_t i = 0; i < kv_size(atoms); i++) {
    >>>     CID 653188:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "keys.items" at offset corresponding to index variable "keys.size" through dereference in call to "memcpy".
    216         kv_concat(keys, kv_A(atoms, i).keys);
    217       }
    218       size_t len = kv_size(keys);
    219       kv_push(keys, NUL);
    220       return (String){ .data = keys.items, .size = len };
    221     }

    CID 653187:       Null pointer dereferences  (FORWARD_NULL)

    _____________________________________________________________________________________________
    CID 653186:         Null pointer dereferences  (FORWARD_NULL)
    /src/nvim/input_cmdatom.c: 173             in atom_compose_keys()
    167       StringBuilder sb = KV_INITIAL_VALUE;
    168       redo_prefix(&spec, &sb, false);
    169       redo_chars(&spec, &sb, false);
    170       if (sb.size == 0) {
    171         return NULL;
    172       }
    >>>     CID 653186:         Null pointer dereferences  (FORWARD_NULL)
    >>>     Dereferencing null pointer "((sb.size == sb.capacity) ? (sb.capacity = (sb.capacity ? sb.capacity << 1 : 8UL)) , (sb.items = xrealloc(sb.items, 1UL * sb.capacity)) , 0 : 0) , (sb.items + sb.size++)".
    173       kv_push(sb, NUL);
    174       return sb.items;
    175     }
    176
    177     /// The pending change as a CmdAtom: the composed keysequence plus the structured fields.
    178     /// Caller owns `keys`.

    _____________________________________________________________________________________________
    CID 653185:         Null pointer dereferences  (FORWARD_NULL)
    /src/nvim/input.c: 296             in redo_compose()
    290       StringBuilder buf = KV_INITIAL_VALUE;
    291       redo_prefix(&r->spec, &buf, false);
    292       kv_splice(buf, r->keys);
    293       if (buf.size == 0) {
    294         return (String)STRING_INIT;
    295       }
    >>>     CID 653185:         Null pointer dereferences  (FORWARD_NULL)
    >>>     Dereferencing null pointer "((buf.size == buf.capacity) ? (buf.capacity = (buf.capacity ? buf.capacity << 1 : 8UL)) , (buf.items = xrealloc(buf.items, 1UL * buf.capacity)) , 0 : 0) , (buf.items + buf.size++)".
    296       kv_push(buf, NUL);
    297       return cbuf_as_string(buf.items, buf.size - 1);
    298     }
    299
    301     String redo_keys(void)

    _____________________________________________________________________________________________
    CID 653184:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input.c: 3533             in paste_store()
    3527                && *s != NL && !(crlf && *s == CAR)) {
    3528           s++;
    3529         }
    3530
    3531         if (s > start) {
    3532           if (need_redo) {
    >>>     CID 653184:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "redobuff.cur.keys.items" at offset corresponding to index variable "redobuff.cur.keys.size" through dereference in call to "memcpy".
    3533             kv_concat_len(redobuff.cur.keys, start, (size_t)(s - start));
    3534           }
    3535           if (need_record) {
    3536             kv_concat_len(recordbuff, start, (size_t)(s - start));
    3537           }
    3538         }

    _____________________________________________________________________________________________
    CID 653183:         Memory - illegal accesses  (OVERRUN)
    /src/nvim/input.c: 730             in redo_append_spec()
    724         return;
    725       }
    726
    727       while (*s != NUL) {
    728         if ((uint8_t)(*s) == K_SPECIAL && s[1] != NUL && s[2] != NUL) {
    729           // Insert special key literally.
    >>>     CID 653183:         Memory - illegal accesses  (OVERRUN)
    >>>     Overrunning dynamic array "redobuff.cur.keys.items" at offset corresponding to index variable "redobuff.cur.keys.size" through dereference in call to "memcpy".
    730           kv_concat_len(redobuff.cur.keys, s, 3);
    731           s += 3;
    732         } else {
    733           sb_add_char(&redobuff.cur.keys, mb_cptr2char_adv(&s));
    734         }
2026-08-16 11:37:51 -04:00
Nathan Zeng
7b6f344627 fix(restart): preserve global cwd on :restart #41304
Problem:
On :restart, the new Nvim may "inherit" a local dir as its global CWD.

Solution:
Inherit the global CWD explicitly.
2026-08-16 10:34:17 -04:00
Justin M. Keyes
214bcf24cc fix(undo): crash on corrupted undo file #41339
Problem:
`:rundo` on a corrupted undo file crashes or hangs, instead of failing
with E825. Patching one 4-byte field is enough:

    ue_size = 0xFFFFFFFF  " walks a NULL ue_array
    ue_size = 0x7FFFFFF0  " 17 GB xmalloc + memset, then preserve_exit()
    ue_top  = 0xFFFFFFFB  " negative lnum reaches ml_delete()

Analysis:
Every count in the file is read with `undo_read_4c()` and then checked,
differently at each site. None bounds the value by what the file can
hold, so a 2 GB count reaches `xmalloc()`.

Note:
- Vim doesn't have `bi_fsize` because it checks `U_ALLOC_LINE` result
  everywhere (thus doesn't crash, but may thrash...); those checks were
  dropped when Nvim moved to `xmalloc()`, and the `ue_size` loop counter
  became unsigned.
- Vim *does* have the negative line numbers bug: `u_undoredo()` checks
  `top > ml_line_count || top >= bot || bot > ml_line_count + 1`, which
  rejects none of them.

Solution:
- Introduce `undo_read_len()` and use it to fail early instead of
  continuing with nonsense.
- Validate `ue_top`/`ue_bot`/ `ue_lcount`.
- Use `xcalloc()`, so no site can proceed with a NULL array.
- Report a truncated "U" line, distinguish EOF from a 0xFFFFFFFF field,
  and free the header on the extmark error path.
2026-08-16 10:24:24 -04:00
Justin M. Keyes
83730db647 perf(marktree): binary search the node intersect array #41331
Problem:
Undo of a change spanning many paired marks is quadratic. A node's
"intersect" array holds every pair crossing that node, and both
intersect_node() and unintersect_node() walked it linearly. Undoing an
edit over 1M paired marks spends 68% of its time in unintersect_node()'s
scan alone.

Solution:
The array is sorted, so binary search it.

    marks    undo before    after
    200k          831ms     385ms
      1M        14006ms    3820ms

Redo is unaffected: it is dominated by marktree_move() actually
repositioning the marks.
2026-08-16 08:29:58 -04:00
Justin M. Keyes
37c670e682 fix(marks): undo reverts a mark set after the change #41330
Problem:
A named mark updated after a change is moved back (treated as the
original mark) by undo:

    :1mark d
    :$
    dw
    :2mark d   " 'd is on line 2
    :undo      " 'd is back on line 1

The undo header snapshots `b_namedm` when the change is recorded, and
`u_undoredo()` restores that snapshot indiscriminately.

Solution:
Update the pending header's snapshot when a mark is set explicitly.
Marks that the change itself moved go through mark_adjust(), not
setmark_pos(), so those are still reverted.

Similar to 2546741d1b (for extmarks): an explicit set inside an undo
block is confused with an edit-driven adjustment. But the extmarks case
is dealing with mid-edit moves, whereas named/regular marks only need
the stale snapshot dropped.
2026-08-15 13:34:51 -04:00
Justin M. Keyes
fb180287d0 fix(cwd): nvim_win_set_buf of :bcd buf, changes caller CWD #41329
Problem:
Setting a :bcd buffer into another window, modifies the caller's CWD.

    local b = vim.api.nvim_create_buf(true, true)
    vim.api.nvim_buf_call(b, function() vim.cmd.bcd('..') end)
    vim.cmd('vsplit')
    vim.api.nvim_win_set_buf(vim.fn.win_getid(2), b)

    :echo haslocaldir(0) haslocaldir(-1,0) haslocaldir(-1,-1,0)
    0 0 0
    :echo getcwd() ==# getcwd(-1,-1)
    0

Analysis:
`ctx_dirs_save` only saves CWD if it predicts the switch can change it.
But win_set_buf() replaces the target window's buffer *after* the
switch, which cannot be "predicted" from `ctx_dirs_save`.

Solution:
Always snapshot whenever the switch enters another window.
Skipping `os_dirname` was a micro-optimization.
2026-08-15 13:15:37 -04:00
Justin M. Keyes
cd2db7913a fix(cwd): nvim_win_set_buf changes global CWD #41328
Problem:
nvim_win_set_buf() on a non-current win, while the current win has
a win-local dir, changes the global CWD:

    :vsplit | lcd ..
    :call nvim_win_set_buf(other_win, buf)
    :wincmd l
    :verbose pwd
    [global] /parent        " expected: the initial cwd

Analysis:
`globaldir` is where to return when no local dir applies; NULL means the
process CWD is already there. Switching to a window with no local dir
makes update_cwd() chdir back to `globaldir` and clear it. kCtxKeepCwd
restores the process CWD but not that bookkeeping, so the restored
window-local dir is mistaken for the global one.

Solution:
Save/restore `globaldir` with the CWD.
2026-08-15 11:45:44 -04:00
Justin M. Keyes
9cca923ab4 fix(extmarks): redo of a mark created during an edit #41324
Problem:
A mark created by `nvim_buf_set_extmark()` while an undo block is open
never comes back on redo.

Analysis:
Undo deletes the text it covers and collapses the range; redo replays
the splices, which re-insert the text but cannot re-expand the mark.
`extmark_set()` records a position only for a mark it moves, not for one
it creates.

Solution:
Record the created position for redo; undo leaves the mark to the splice
replay, since it did not exist before the edit. Each side of a paired
mark gets its own entry. Redo also revives a mark that undo invalidated,
else its position returns but its highlight does not.
2026-08-15 10:13:32 -04:00
Justin M. Keyes
64a301184e feat(input)!: CmdAtom event #41297
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.
2026-08-14 09:30:31 -04:00
github-actions[bot]
485ae7e31a docs: update version.c #41288
vim-patch:9.2.0946: GTK2/3: mouse move starts Visual selection after a dialog
vim-patch:9.2.0947: GTK4: screen is cleared when moving the mouse after startup
vim-patch:9.2.0948: GTK4: mouse move starts Visual selection after a dialog
vim-patch:9.2.0949: GDK_KEY_VoidSymbol might be undefined
vim-patch:9.2.0951: GTK3: cursor does no longer blink
vim-patch:9.2.0955: tests: terminal tests are flaky
vim-patch:9.2.0956: GTK4: crash when the window is resized while redrawing

vim-patch:8.1.0768: updating completions may cause the popup menu to flicker
vim-patch:8.1.0863: cannot see what signal caused a job to end
vim-patch:8.1.0876: completion match not displayed when popup menu is not shown
vim-patch:8.1.0894: MS-Windows: resolve() does not return a reparse point
vim-patch:8.1.1218: cannot set a directory for a tab page
vim-patch:8.1.1224: MS-Windows: cannot specify font weight
vim-patch:8.1.1417: MS-Windows: resolve() does not resolve all components of path
vim-patch:8.1.1473: new resolve() implementation causes problem for plugins
vim-patch:8.1.1525: cannot move a popup window with the mouse
vim-patch:8.1.1558: popup_menu() and popup_filter_menu() are not implemented yet
vim-patch:8.1.1561: popup_setoptions() is not implemented yet
vim-patch:8.1.1577: command line redrawn for +arabic without Arabic characters
vim-patch:8.1.1580: cannot make part of a popup transparent
vim-patch:8.1.1589: popup window does not indicate scroll position
vim-patch:8.1.1597: cannot scroll a popup window with the mouse
vim-patch:8.1.1609: the user cannot easily close a popup window
vim-patch:8.1.1612: cannot show an existing buffer in a popup window
vim-patch:8.1.1626: no test for closing a popup window with a modified buffer
vim-patch:8.1.1628: popup window functions not in list of functions
vim-patch:8.1.1713: highlighting cursor line only works with popup_menu()
vim-patch:8.1.1714: cannot preview a file in a popup window
vim-patch:8.1.1718: popup menu highlighting does not look good
vim-patch:8.1.1770: cannot get the window ID of the popup preview window
vim-patch:8.1.1784: MS-Windows: resolve() does not work if serial nr duplicated
vim-patch:8.1.1787: cannot resize a popup window
vim-patch:8.1.1799: cannot avoid mapping for a popup window
vim-patch:8.1.1813: ATTENTION prompt for a preview popup window
vim-patch:8.1.1819: :pedit does not work with a popup preview window
vim-patch:8.1.1880: cannot show extra info for completion in a popup window
vim-patch:8.1.1882: cannot specify properties of the info popup window
vim-patch:8.1.1884: cannot use mouse scroll wheel in popup in Insert mode
vim-patch:8.1.1892: missing index entry and option menu for 'completepopup'
vim-patch:8.1.1904: cannot have an info popup align with the popup menu
vim-patch:8.1.1905: cannot set all properties of the info popup
vim-patch:8.1.1906: info popup size is sometimes incorrect
vim-patch:8.1.1908: every popup window consumes a buffer number
vim-patch:8.1.1928: popup windows don't move with the text when making changes
vim-patch:8.1.1969: popup window filter is used in all modes
vim-patch:8.1.2039: character from 'showbreak' does not use 'wincolor'
vim-patch:8.1.2092: MS-Windows: redirect in system() does not work
vim-patch:8.1.2093: MS-Windows: system() test fails
vim-patch:8.1.2139: the modifyOtherKeys codes are not tested
vim-patch:8.1.2142: some key mappings do not work with modifyOtherKeys
vim-patch:8.1.2153: combining text property and syntax highlight is wrong
vim-patch:8.1.2155: in a terminal window 'cursorlineopt' does not work properly
vim-patch:8.1.2158: terminal attributes missing in Terminal-normal mode
vim-patch:8.1.2192: cannot easily fill the info popup asynchronously
vim-patch:8.1.2208: Unix: Tabs in output might be expanded to spaces
vim-patch:8.1.2273: wrong default when "pos" is changed with popup_atcursor()
vim-patch:8.1.2279: computation of highlight attributes is too complicated
vim-patch:8.1.2324: with of scrollbar in popup menu not taken into account
vim-patch:8.1.2351: 'wincolor' not used for > for not fitting double width char
vim-patch:8.1.2362: cannot place signs in a popup window
vim-patch:8.1.2386: 'wincolor' is not used for 'listchars'
vim-patch:8.1.2399: info popup on top of cursor if it doesn't fit
vim-patch:8.1.2415: popup menu flickers if an info popup is used
vim-patch:8.1.2418: bufnr('$') is wrong after recycling popup buffer
2026-08-14 07:35:15 -04:00
bfredl
69e61d52e2 Merge pull request #41186 from Rawan10101/fix-wasm-browser
feat(wasm): track and fix ongoing issues + add WASM build workflow
2026-08-14 12:59:12 +02:00
Barrett Ruth
fc3f71fb7d fix(messages): inputlist() offers the mouse when it cannot be used (#41280)
Problem:
`inputlist()` advertises "click with the mouse" purely because it
implements click selection, so under the default `'mouse'` of "nvi" it
offers a click that command-line mode never receives.

Solution:
Only offer the mouse when `'mouse'` covers command-line mode, the same
condition `:help inputlist()` already documents.
2026-08-14 07:38:39 +08:00
rawan10101
b78adb98ba fix(wasm): remove custom log path and disable autoread 2026-08-13 15:52:30 +03:00
zeertzjq
2dec97464c vim-patch:9.2.0954: u_read_undo() can be improved (after 9.2.0935)
Problem:  u_read_undo() has comments that do not add anything to what
          the code says (afte rv9.2.0935).
Solution: Drop the redundant comments (Hirohito Higashi).

related: vim/vim#20942
closes:  vim/vim#21028

ecfea491aa

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 07:52:57 +08:00
zeertzjq
7525e87f10 vim-patch:9.2.0953: insert completion code can be improved
Problem:  The duplicate-check hashtab in insexpand.c has comments that
          do not add anything to what the code says (after v9.2.0909).
Solution: Drop the redundant comments.

related: vim/vim#20926
closes:  vim/vim#21027

4dde4afa1d

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 07:52:57 +08:00
zeertzjq
39dc19bab4 vim-patch:9.2.0950: transstr() can be improved (after 9.2.0906)
Problem:  transstr() has comments that do not add anything to what the
          code says, and it casts a length to int only to cast it back to
          size_t.
Solution: Drop the comments and keep the length in a size_t
          (Hirohito Higashi).

related: vim/vim#20925
closes:  vim/vim#21026

fe65307d49

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 07:52:57 +08:00
zeertzjq
5e0d4ba389 vim-patch:9.2.0945: sort() with a numeric option can be improved
Problem:  The comments on the precomputed sort keys explain the code by
          contrasting it with the previous implementation, and one of
          them exceeds 80 columns (after v9.2.0937).
Solution: Drop the redundant comments and shorten the union member ones
          (Hirohito Higashi).

related: vim/vim#21003
closes:  vim/vim#21030

722f4292e5

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 07:52:57 +08:00
github-actions[bot]
a63393396c docs: update version.c #41258
vim-patch:8.1.1523: cannot show range of buffer lines in popup window
vim-patch:8.1.1537: using "tab" for popup window can be confusing
vim-patch:8.1.1538: cannot specify highlighting for notifications
vim-patch:8.1.1548: popup_dialog() is not implemented
vim-patch:8.1.1553: not easy to change the text in a popup window
vim-patch:8.1.1559: popup window title property not implemented yet
vim-patch:8.1.1574: tabpage option not yet implemented for popup window
vim-patch:8.1.1659: popup window "mousemoved" values not correct
vim-patch:8.1.1673: cannot easily find the popup window at a certain position
vim-patch:8.1.1690: default padding for popup window menu is too much
vim-patch:8.1.1944: leaking memory when using sound callback
vim-patch:8.1.1999: calling both PlaySoundW() and PlaySoundA()
vim-patch:8.1.2193: popup_setoptions(popup_getoptions()) does not work
vim-patch:8.1.2250: CTRL-U and CTRL-D don't work in popup window
vim-patch:8.1.2292: v:mouse_winid not set on click in popup window
vim-patch:8.2.0238: MS-Windows: job_stop() results in exit value zero
vim-patch:8.2.0286: cannot use popup_close() for a terminal popup
vim-patch:8.2.2105: sound test is a bit flaky
vim-patch:8.2.2296: cannot use CTRL-N and CTRL-P in a popup menu
vim-patch:8.2.2950: sound code not fully tested
vim-patch:8.2.2959: sound_playfile() is not tested on MS-Windows
vim-patch:9.0.0800: compiler complains about repeated typedef
vim-patch:9.0.0999: memory may leak
vim-patch:9.0.2089: sound_playfile() fails when using powershell
vim-patch:9.1.0271: CI sound test aborts with undefined variable
vim-patch:9.1.0949: popups inconsistently shifted to the left
vim-patch:1f045f324 runtime(doc): clarify buffer deletion on popup_close()
vim-patch:9.1.1985: tests: test_sound.vim fails on Windows
vim-patch:3d863d6aa runtime(doc): Update popup width rule
vim-patch:9.2.0928: MinGW: tests hang when Vim is built with coverage enabled
vim-patch:9.2.0940: GTK4: columns are lost when a scrollbar appears
vim-patch:9.2.0943: test: test_hardcopy fails on GTK4 UI
vim-patch:c6b041c63 CI: Keep the GTK4 job from affecting the other jobs
2026-08-12 09:12:57 -04:00
zeertzjq
f33c92348a vim-patch:9.2.0937: sort() with a numeric option converts each item on every comparison (#41286)
Problem:  sort() with "n", "N" or "f" converts an item to its number on
          every comparison.  For "n" that is a tv2string() plus strtod()
          per comparison, so sorting a list of numbers turns each number
          into a string and back O(n log n) times, dwarfing the sort.
Solution: Compute the numeric key of each item once, before the sort,
          and compare the stored key (Samuel Schlesinger).  Only the
          builtin numeric compare modes are affected; uniq(), which
          passes a bare list item to the compare function, and the
          string and user-function paths are unchanged.

Sorting a list of 100000 numbers (min of 3, macOS arm64):
- sort(l, 'n'):  0.205s -> 0.017s
- sort(l, 'N'):  0.017s -> 0.010s
- sort(l, 'f'):  0.014s -> 0.010s
The result is identical, including that a string is still treated as 0
in "n" mode and that "N" keeps full 64-bit precision.

Add Test_sort_numeric_precomputed(): a large shuffled list sorted with
"n", mixed integers and floats, int64 values beyond the exact range of
a double for "N", and uniq() over the non-precomputed path.

closes: vim/vim#21003

c8c59db9df

Co-authored-by: Samuel Schlesinger <sgschlesinger@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-08-12 11:45:38 +00:00
zeertzjq
a0dc3f0067 vim-patch:9.2.0935: reading an undo file is slow with many undo headers (#41285)
Problem:  Reading an undo file resolves every stored sequence number
          with a linear scan over all headers, making loading
          quadratic in the number of undo states.
Solution: Sort uhp_table on uh_seq once and resolve each reference
          with a binary search; the duplicate uh_seq check becomes a
          single pass over the sorted table (Samuel Schlesinger).

At the default 'undolevels' of 1000 the quadratic cost is not
measurable; it takes 'undolevels' in the tens of thousands to matter.
Loading an undo file with 20000 states and 50 alternate branches with
:rundo goes from 1.49s to 0.11s (min of 3, macOS arm64), with the
same undotree().

Also make old_idx/new_idx/cur_idx and the loop index "i" long instead
of short/int: they index uhp_table, whose length num_head is a long
read from the file.  A short index truncated above 32767 headers,
making the restored b_u_oldhead/b_u_newhead/b_u_curhead pointers
wrong in exactly the many-headers case this change is about.

Add tests: a round-trip test with alternate branches that compares
the entries of the tree and the text at every sequence number, a
corruption test with a duplicated uh_seq, and a test for reading an
undo file with zero headers, which is written when only the line for
the "U" command is saved.

closes: vim/vim#20942

fccf613c8f

Co-authored-by: Samuel Schlesinger <sgschlesinger@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-08-12 10:00:09 +08:00
zeertzjq
ecaf9e9396 vim-patch:02bf089: runtime(doc): clarify diff_filler() function (#41283)
fixes: vim/vim#20990

02bf0893d5

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-08-12 08:24:48 +08:00
zeertzjq
e9dc4da86e vim-patch:9.2.0938: cursorbind: cursor in the other window is not updated after undo (#41282)
Problem:  In diff mode with 'cursorbind' the cursor in the other window is
          not updated after an undo that changes which lines correspond.
Solution: Also check whether the text changed before skipping the update
          (Hirohito Higashi).

fixes:   vim/vim#20982
related: vim/vim#13219
related: vim/vim#13210
closes:  vim/vim#21004

2045a20d4b

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 00:16:08 +00:00
rawan10101
014b00a642 fix(wasm): fix browser input and runtime exit handling
Use ev.key directly to preserve Caps Lock casing, implement clipboard
paste, and prevent :q/:qa from leaving the runtime in a loop.
2026-08-11 14:08:40 +03:00
zeertzjq
2757f6eef9 vim-patch:9.2.0933: u_read_undo() leaks the file name when the undo file owner differs (#41269)
Problem:  When the owner of an undo file differs from the owner of
          the text file and the current user, u_read_undo() returns
          without freeing the file name it allocated with
          u_get_undo_file_name().
Solution: Free the file name before returning (Samuel Schlesinger).

Every other exit of the function frees it under the "theend" label;
this early return sits before the file pointer is initialized, so it
cannot use that label.

closes: vim/vim#20987

d03735e8d2

Co-authored-by: Samuel Schlesinger <sgschlesinger@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-08-11 10:35:51 +08:00
zeertzjq
7be8a8dda3 vim-patch:9.2.0932: NFA engine fallback can double free the compiled program (#41268)
Problem:  When the automatic regexp engine falls back to the
          backtracking engine in vim_regexec_string(), the compiled
          program is freed before the replacement is compiled; when
          saving the pattern fails from being out of memory the
          caller's "regprog" is left pointing to freed memory and
          is freed again.
Solution: Free the previous program only after compiling the
          replacement succeeded, like vim_regexec_multi() already
          does (Samuel Schlesinger).

closes: vim/vim#20986

cab0901f12

Co-authored-by: Samuel Schlesinger <sgschlesinger@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-08-11 10:19:52 +08:00
bfredl
344ea602f6 refactor(ex_cmds): use function arguments for magic behavior
Now this was a cargo cult anti-pattern to write home about.
Doing painful save-and-restore bookkeeping around a separate
`magic_overruled` decoy global is just as messy as doing painful
save-and-restore logic around `p_magic` itself. only that now you need
to wrap every access to the effective value in a function call.

This replaces this with a marvellous new Clean Code technique™:
passing in the intended behavior as a function parameter to functions
where either the option or an explicit value might be used.
2026-08-10 13:26:51 +02:00
Justin M. Keyes
5287a04be4 perf(mbyte): annotate pure functions #41251 2026-08-10 04:27:49 -04:00
Justin M. Keyes
2546741d1b fix(extmarks): undo-redo of a mark explicitly moved during an edit #41252
Problem:
A mark moved by nvim_buf_set_extmark() during an edit is misplaced by
undo and redo. Only splices ("edits") are recorded, and replaying them
reproduces the shifts they caused, never the explicit set: the mark ends
up wherever the text pushed it.

Solution:
When an open undo block moves an existing mark, record both positions.
Undo restores the pre-set position, redo re-applies the set.

Partially reverts 18334a4a0c ; ExtmarkSavePos.row/col were unused
because nothing recorded an explicit move, but now `extmark_set()` does.
2026-08-10 04:21:31 -04:00
HX L
4b8c4dfc68 fix(channel): handle socket accept failure #41240 2026-08-10 04:11:27 -04:00
github-actions[bot]
c64fb0767f docs: update version.c #41209
vim-patch:8.2.1300: Vim9: optional argument type not parsed properly
vim-patch:8.2.1341: build failures
vim-patch:8.2.1551: Vim9: error for argument type does not mention the number
vim-patch:8.2.2630: hard to see where a test gets stuck
vim-patch:8.2.4350: FEAT_GUI_ENABLED defined but never used
vim-patch:9.0.2085: Vim9: abstract can be used in interface
vim-patch:9.1.1037: Vim9: confusing error when using abstract method via super
vim-patch:9.1.1586: Vim9: can define an enum/interface in a function
vim-patch:9.1.2076: tests: MinGW test fails midway and stops
vim-patch:9.2.0922: Wayland: modeless selection not redrawn
vim-patch:a6be0d496 CI: Add Github runner for Cygwin
vim-patch:9.2.0924: tests: Test_termwinscroll() fails on FreeBSD
vim-patch:081786261 CI: Bump github/codeql-action

vim-patch:8.1.1851: crash when sound_playfile() callback plays sound

vim-patch:8.2.1527: Vim9: cannot use a function name at script level
vim-patch:8.2.1541: Vim9: cannot find function reference for s:Func
vim-patch:8.2.1581: using line() for global popup window doesn't work
vim-patch:8.2.1582: the channel log does not show typed text
vim-patch:8.2.1592: Vim9: passing "true" to char2nr() fails

vim-patch:9.1.0879: source is not consistently formatted
2026-08-10 03:43:34 -04:00
zeertzjq
2b29905c7f vim-patch:9.2.0927: curswant not set on 8g8 (#41255)
Problem:  curswant not set on 8g8
Solution: Set curswant, adjust tests (Emilien Breton)

closes: vim/vim#20979

7fe5cb35f9

Co-authored-by: Emilien Breton <bricktech2000@gmail.com>
2026-08-10 00:39:14 +00:00
Justin M. Keyes
abc271d8f3 fix(logging): vimscript API calls #41253
Problem:
":call nvim_get_mode()" logs a nonsense channel-id:

    RPC: ch 9223372036854775808: invoke nvim_get_mode

Solution:
Check `is_internal_call`.
Also, skip this logging for RPC calls, because it's redundant with
`log_request`/`log_notify`.

    API: vim -> nvim_get_mode
2026-08-09 17:33:53 -04:00
Jan Edmund Lazo
662f983f76 vim-patch:8.2.1475: Vim9: can't use v:true for option flags (#41249)
Problem:    Vim9: can't use v:true for option flags.
Solution:   Add tv_get_bool_chk(). (closes vim/vim#6725)

----

"tv_get_bool_or_number_chk()" without vim9 params is identical to
"tv_get_number_chk()".
"tv_get_number_chk()" and tv"_get_bool_chk()" are identical
after excluding new vim9 params.
Yes, "want_bool" param is N/A because of "in_vim9script()".
If I port it, then I will refactor these macros or "static inline"
functions within "src/nvim/eval/typval.h".

----

36967b32fd

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-09 06:53:31 +00:00
Jan Edmund Lazo
b3a0cfcd0a vim-patch:8.2.1597: the channel source file is too big
Problem:    The channel source file is too big.
Solution:   Move job related code to a new source file.

----

Move eval-related prompt-buffer API to src/nvim/nvim/eval/buffer.c.

https://github.com/neovim/neovim/pull/37743#issuecomment-3897416840

----

8b5866ded6

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-08 14:52:26 -04:00
Jan Edmund Lazo
9c6ea122a8 vim-patch:8.2.1590: Vim9: bufnr() doesn't take "true" argument
Problem:    Vim9: bufnr() doesn't take "true" argument.
Solution:   use tv_get_bool_chk(). (closes vim/vim#6863)

fe136c9a85

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-08 09:06:53 -04:00
Justin M. Keyes
e16d577f16 Merge #41224 from justinmk/fixbuild 2026-08-08 03:59:15 -04:00
Jan Edmund Lazo
a08607b8d6 vim-patch:8.2.1478: Vim9: cannot use "true" for some popup options (#41236)
Problem:    Vim9: cannot use "true" for some popup options.
Solution:   Add dict_get_bool(). (closes vim/vim#6725)

558813314d

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-08 13:19:59 +08:00
Jan Edmund Lazo
989726f3a6 vim-patch:8.2.1577: Vim9: hasmapto()/mapcheck()/maparg() do nottake "true" arg
Problem:    Vim9: hasmapto(), mapcheck() and maparg() do not take "true" as
            argument.
Solution:   Use tv_get_bool(). (closes vim/vim#6822, closes vim/vim#6824)

04d594b9c1

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-08 00:28:12 -04:00
Jan Edmund Lazo
ecbae9911e vim-patch:8.2.1576: Vim9: index() does not take "true" as argument
Problem:    Vim9: index() does not take "true" as argument.
Solution:   Use tv_get_bool_chk(). (closes vim/vim#6823)

6c553f9c04

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-08 00:25:18 -04:00
Jan Edmund Lazo
b055504d41 vim-patch:8.2.1575: Vim9: globpath() doesnot take "true" as argument
Problem:    Vim9: globpath() doesnot take "true" as argument.
Solution:   Use tv_get_bool_chk(). (closes vim/vim#6821)

f966ce5ea2

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-08 00:23:16 -04:00
Jan Edmund Lazo
f3491ac971 vim-patch:8.2.1574: Vim9: glob() doesnot take "true" as argument
Problem:    Vim9: glob() doesnot take "true" as argument.
Solution:   Use tv_get_bool_chk(). (closes vim/vim#6821)

5892ea1511

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-08 00:22:02 -04:00
Jan Edmund Lazo
c2f0c2b4d1 vim-patch:8.2.1573: Vim9: getreg() does not take "true" as argument
Problem:    Vim9: getreg() does not take "true" as argument.
Solution:   Use tv_get_bool_chk().  (closes vim/vim#6820)

67ff97ded7

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-08 00:19:53 -04:00