Commit Graph

11145 Commits

Author SHA1 Message Date
zeertzjq
2cd4229d01 fix(window): crash when closing new curwin during CTRL-W_x (#41378)
Problem:  Crash when closing the new current window during CTRL-W_x.
Solution: Remove a duplicate redraw of a window that should normally be
          already mark for redraw in the previous call.
2026-08-19 20:13:08 +08:00
zeertzjq
53211ade2b vim-patch:9.2.0969: runtime(shaderslang): matchit % breaks on braces (#41371)
Problem:  b:match_words groups "{" with the if/for/while/switch keywords
          and "}" with "break" which breaks % matching on braces
Solution: Drop the brace and bracket groups, matchit appends
          'matchpairs' by itself (Matthias Bruns).

matchit counts every alternative in a group instead of pairing the
alternatives with each other.  Listing `{` alongside the if, for,
while, switch, struct and class keywords therefore makes a line such
as `for (...) {` count as two openers, and listing `break` alongside
`}` lets a brace pair with a break statement.  As a result % on the
opening brace of a function does not move at all, and % on
`switch (x) {` jumps to `break;` instead of the closing brace.

Braces and brackets do not need to be listed: matchit appends
'matchpairs' to b:match_words by itself.  Drop them and leave the
preprocessor group unchanged.

closes: vim/vim#21064

08c74ce09a

Co-authored-by: Matthias Bruns <matthiasbruns35@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-19 07:47:24 +08:00
Justin M. Keyes
0c091cedc2 test(tui): unreliable "TUI exits immediately when stdin is closed" #41367
Problem:
Unreliable test on slow CI (ASAN/TSAN):

    FAILED  .../tui_spec.lua @ 3054: TUI exits immediately when stdin is closed
    retry() attempts: 1
    Expected: vim.NIL
    Actual: { name = "nvim", pid = 33201, ppid = -1 }

The test asserts "immediate" exit of the Nvim process, but this may be
subject to OS delays outside of our control.

Solution:
Make the "timed out waiting for DA1" log conditional on the actual
timeout, and assert the logs in the test.
2026-08-18 09:22:05 -04:00
Goldpigg
ab82c2c6b0 feat(extmark): virt_lines can highlight until EOL #41289 2026-08-18 08:35:22 -04:00
Justin M. Keyes
f6bf814378 fixfix(cmdatom): repeat Visual <Cmd>; CmdFrame + stage #41355
Problem:
- Dot-repeat of a Visual selection prepared by a `<Cmd>` mapping,
  results in E1255 and leaves Visual mode active.
- Visual-mode capture is implemented as a second, parallel "capture
  engine": it re-composes a CmdSpec from cmdarg_T per key and decides
  replayability from its own table of "void" key classes.

Solution:
- Model nested `normal_execute()` as a `CmdFrame` stack,
  instead of a single module-scoped `stage`.
  - Capture `<Cmd>` ":norm …" commands as subatoms from its nested frames.
- Produce every command exactly once; atom_push_raw() routes the atom to
  the Visual composite while a selection is open, like it already does
  for mapping composites.
  - `v/pat<CR>d` is now repeatable and cascades.
2026-08-18 07:50:27 -04:00
Justin M. Keyes
c5ea9ca2ad fix(zip): missed "password:" prompt if output trails it #41364
Problem:
Flaky test:

    RUN      T1158 nvim.zip reports an incorrect archive password: 11092.84 ms FAIL

The prompt is detected only if the pty output *ends* with "password: ",
but a read may return the prompt plus following bytes.

Solution:
- Match anywhere in the output since the last password was sent. The
  buffer is cleared before each send, so won't match stale text.
- Assert on the reported message, so a failure shows what was reported.
2026-08-18 06:23:59 -04:00
Marcus Caisey
d9b4fb1273 feat(lsp): fallback to textDocument/formatting from vim.lsp.formatexpr #40079
Problem:
With the addition of the `:help al` text object, you can now easily
format the whole buffer with `gqal`. However, `vim.lsp.formatexpr` only
uses `textDocument/rangeFormatting` which some language servers (like
gopls) don't support.

Solution:
- Fall back to `textDocument/formatting` if the whole buffer is being formatted
  and the server doesn't support `textDocument/rangeFormatting`.
  - In theory, these two methods should return the same response if the whole
    buffer is being formatted, but I preserved the existing behaviour of
    prioritising `textDocument/rangeFormatting` in case that does not hold (i.e.
    LS bug).
- Also: `vim.lsp.formatexpr` had no tests at all, so actually add tests for it.
2026-08-18 05:16:16 -04:00
zeertzjq
82c751db4e vim-patch:9.2.0967: hit-enter prompt eats keys from a running mapping (#41359)
Problem:  The hit-enter prompt fires whenever a message scrolls the screen.
          When this happens while a mapping is being processed, it consumes
          the mapping's next key, causing unexpected behavior for users.
Solution: Similar to what 9.1.1969 did for stuffed characters, skip the
          hit-enter prompt when there are still keys pending from a mapping
          in the typeahead buffer.

related: neovim/neovim#38298
related: neovim/neovim#20635
related: neovim/neovim#30890
closes:  vim/vim#20753

AI assisted.

6025ea9e02

Co-authored-by: XiaowenHu96 <me@xiaowenhu.com>
2026-08-18 09:23:34 +08:00
zeertzjq
bce3bf06a3 vim-patch:9.2.0963: crash when sound-folding a crafted spell file (#41358)
Problem:  A SAL rule longer than MAXWLEN is silently truncated to an
          empty lead.  set_sal_first() then reorders the sl_sal entries
          by their index byte and can move the terminating sentinel out
          of the last slot, so spell_soundfold_wsal() reads past the end
          of the array, e.g. when soundfold() or spellsuggest() is used
          (Erick Alex).
Solution: Bound the sound-folding loops against sl_sal.ga_len.

closes: vim/vim#21076

6ac008db96

Co-authored-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-18 09:03:37 +08:00
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
Rob Pilling
a4aa0417cf feat(ui2): drop default enter-pager-via-CR mapping #40993 2026-08-17 08:03:29 -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
Willaaaaaaa
e0e2f978a0 feat(vim.fs): slug() supports URI #41241
Problem:
`vim.fs.slug()` does not handle URIs like `term://foo//123:bash`,
so callers (e.g. terminal persistence) must strip the scheme before
calling `slug()`.

Solution:
Detect `scheme://` from the raw input before `normalize()` and
replace it with a `=uri-<scheme>-` prefix.
2026-08-16 13:29:34 -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
zeertzjq
2edb1c0009 fix(lua): don't limit indexed vim.cmd positional argument count (#41317) 2026-08-16 07:25:04 +08: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
Barrett Ruth
b169d9376c test(dir_spec): fix failures with PUC Lua 2026-08-15 13:07:21 +08:00
Barrett Ruth
0af3b9827b feat(dir): user can sort/filter listings, DirReadPost event #41138
Problem:
Directory listing entries cannot be customized (filtered, reordered).
Listings are read by a BufReadCmd, which suppresses BufReadPost, so they
are the only buffers with no post-read event to hook.

Solution:
Introduce a post-render User autocmd `DirReadPost`, marking the dir
buffer writable for the duration and before the cursor is placed, so
handlers can sort or filter it with ordinary commands. Document common
recipes
2026-08-14 12:25:31 -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
zeertzjq
1a9467ab44 vim-patch:9.2.0957: filetype: ArgoCD config file is not recognized (#41301)
Problem:  filetype: ArgoCD configuration file is not recognized
Solution: Detect */argocd/config as yaml filetype (Fionn Fitzmaurice).

Reference:
https://argo-cd.readthedocs.io/en/latest/user-guide/commands/argocd_configure/#options-inherited-from-parent-commands

closes: vim/vim#21031

7807dd2279

Co-authored-by: Fionn Fitzmaurice <git@fionn.computer>
2026-08-14 08:47:14 +08: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
Nathan B.
faf8345eef fix(diagnostic): don't accumulate BufRead autocmds for unloaded buffers #40869
Problem:
vim.diagnostic.set() defers extmark position computation for an
unloaded buffer via a once=true BufRead autocmd, registering a new one
on every call without replacing the previous one. Each pending autocmd
also retains that call's diagnostics.

Solution:
Instead of registering an autocmd per set() call, register a single
static BufRead autocmd that computes positions from the diagnostic
cache for any buffer with cached diagnostics when it is read. This
removes the per-call registration entirely (nothing left to
accumulate) and means diagnostics cleared while the buffer was
unloaded no longer produce stale extmarks.
2026-08-13 09:17:16 -04:00
Justin M. Keyes
a1ea2f35be Merge #41075 from echasnovski/pack-packspec-part1 2026-08-13 08:53:49 -04: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
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
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
Nathan Zeng
4a3197f2ad refactor(defaults): edit global cwd on "1-" #41254
Problem:
`1-` does nothing from a directory buffer, because we are already in the
buffer-local CWD. It's also unintuitive that this mapping behaves
differently based on the resolved CWD.

Solution:
Have `1-` open the global CWD.
2026-08-11 04:08:33 -04: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
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
Kyle
8d406ed2ac fix(defaults): emit events on automatic background change #41242
Problem:
After #40270, events are no longer emitted from the automatic background
detection. This applies not just during startup, but also if the user
manually changes the background of their terminal.

Solution:
Set the background as normal, assuming that a normal terminal will
respond within 100 ms. Change test to match expected behavior:
- BG set during startup won't trigger user autocmds since it runs before
  any user config
- If the terminal takes longer than 100 ms to respond to initial OSC 11,
  it does trigger the OptionSet, but it is triggered through the normal
  path to ensure values like v:option_new are set #38551
- BG change after startup still triggers autocmds #41146
2026-08-10 04:17:51 -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
Torben Leth
f538a4f16f vim-patch:9.2.0926: filetype: Business Central files are not recognized (#41230)
Problem:  filetype: Business Central files are not recognized
Solution: Add filetype detection logic for *.al files to detect perl or
          use either perl or al filetype (Torben Leth).

Reference:
https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-dev-overview

closes: vim/vim#20975

Supported by AI.

9b41cf6386
2026-08-09 00:49:20 +00:00
Justin M. Keyes
e16d577f16 Merge #41224 from justinmk/fixbuild 2026-08-08 03:59:15 -04:00
zeertzjq
390e90bba4 vim-patch:9.2.0925: crash when getcompletiontype() gets a NULL string (#41231)
Problem:  Crash when getcompletiontype()/getcompletion() gets a NULL string
          (dvaave2025).
Solution: Do not write the NUL terminator in set_cmd_context() when the
          cursor column is at or past the end of the string, since the
          string may be a read-only literal.

fixes:  vim/vim#20963
closes: vim/vim#20964

Supported by AI.

e2dcefa0d8

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-08-08 09:44:54 +08:00
zeertzjq
5d5b8e3e7d vim-patch:9.2.0923: tabpage: closing a tab page loses the alternate tab page (#41229)
Problem:  Closing the current tab page resets the alternate tab page, even
          when that is another tab page which still exists, so that
          CTRL-Tab stops working (igorlfs).
Solution: Restore the last used tab page after entering another one to
          close the current one (Hirohito Higashi).

related: vim/vim#20965
closes:  vim/vim#20973

a05bd64c1d

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 09:30:03 +08:00
Justin M. Keyes
9e283f273b test(terminal): unreliable "spawns in CWD effective at time of invocation"
FAILED  …/terminal/ex_terminal_spec.lua @ 270: :terminal (fake shell) spawns in CWD effective at time of invocation
    Expected values to differ.
    Value:
    "~/work/neovim/neovim/build/Xtest_xdg_terminal"
    stack traceback:
   …/terminal/ex_terminal_spec.lua:276: in function <…/terminal/ex_terminal_spec.lua:270>
2026-08-08 02:23:55 +02:00
tao
f0a0182285 refactor(path): pathcmp() #41035
Problem:
Redudant code

Solution:
Add `path_fold_char()` to normalize path sep.
Refactor `pathcmp()` and `path_fnamencmp()` into `path_cmp`.

| feature                  | pathcmp        | path_fnamencmp | path_cmp(now) |
| ------------------------ | -------------- | -------------- | ------------- |
| case folding             | `mb_toupper()` | `utf_fold()`   | `utf_fold()`  |
| consults fileignorecase  |              |              | `ic` param    |
| `maxlen`                 |              |              |             |
| `/` == `\`               |              |              |             |
| MSWIN drive letter       |              |              |             |
| sep affects sorting      |              |              |             |
| ignores a trailing slash |              |              |             |

Refactor `path_fnamecmp` and `path_full_compare` into `path_equal`,
with flags controlling "no filesystem" comparison (i.e. `path_cmp`), env
variables expansion, absolute path resolution and filesystem access.
2026-08-07 19:54:29 -04:00
Justin M. Keyes
b53c00b425 fix(progress): ins-compl progress-msg during pum #41226
Problem:
The insert-mode completion progress-message is in "running" state while
the user is selecting an item. That is noisy and unwanted UX; it was
only intended for the "Scanning..." task.

Solution:
End the progress-msg just after `ins_compl_show_statusmsg`.
2026-08-07 22:49:44 +00:00
Justin M. Keyes
33a688f9fe fix(messages): dangling progress-messages #41222
Problem:
Some builtin features emit progress-messages which never "complete".
- On failure, `:write` does not complete the progress-msg it started.
- ins-completion never ends its "Scanning..." message.

Solution:
- `buf_write()` emits "failed" status on failure.
- `ins_compl_stop()` ends the completion one.
2026-08-07 16:10:02 -04:00
Justin M. Keyes
0a2676e54a fix(messages): :read starts a "bufwrite" progress #41219
Problem:
filemess() treats an empty suffix as "a buffer write is starting", but
readfile() calls it that way too. So ":read" (and ":edit", …) opens a
`nvim.bufwrite "<file>"` progress that is never completed.

Users of e.g. ghostty will see a stuck "progress" spinner.

Solution:
Only `buf_write()` starts the progress, via `filemess_progress()`.
2026-08-07 13:21:17 -04:00
Erdiansyah
59597316a6 fix(cwd): :bcd lost by nvim_win_set_buf, nvim_open_win #41218
Problem:
:bcd (buffer-local directory) is not preserved after
`nvim_open_win` or `nvim_win_set_buf`

Analysis:
set_curbuf() ends with update_cwd(), which falls back to
os_chdir(globaldir) when the target buffer has no b_localdir.

Solution:
Pass kCtxKeepCwd to ctx_switch().
2026-08-07 12:09:22 -04:00
Jan Edmund Lazo
cd02662ba3 vim-patch:8.2.1525: messages from tests were not always displayed #41203
Problem:    Messages from tests were not always displayed.
Solution:   Always show messages, the timing is always useful. (Ken Takata,
            closes vim/vim#6792)

6e3aeec846

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-08-07 11:18:50 -04:00
Justin M. Keyes
7e53d3ba4d fix(cwd): keep buffer-local dir when re-editing #41215
Problem:
Re-editing a buffer (`:edit!`, re-reading a dir.lua buffer, etc.) drops
its `:bcd` directory, so the CWD falls back to the global one. Whereas
other buffer-local state (`b:` vars, local options) survives a reload.

Solution:
Don't clear buf dir in `buf_freeall()`; `do_ecmd()` calls that when
reloading/re-editing. `free_buffer_stuff()` still clears them when
a buffer is freed or reused for another file.
2026-08-07 14:10:21 +00:00
Justin M. Keyes
2e0a5a596a fix(terminal): spawn in effective CWD #41211
Problem:
`:terminal` does not respect the invocation-time CWD.
This wasn't noticeable with `:lcd` because the window-local CWD gets
applied to the new terminal buffer. But it is noticeable with `:bcd`.

Solution:
Specify `cwd` in the job spec.
2026-08-07 07:44:19 -04:00