Commit Graph

10138 Commits

Author SHA1 Message Date
zeertzjq
875958c9a1 fix(terminal): don't refresh for sync flush when exiting (#38363)
Fixes the following error log:

    ERR 2026-03-18T20:17:36.920 T281.9357.0 buf_updates_send_changes:258: Disabling buffer updates for dead channel 1
2026-03-19 02:53:52 +00:00
Justin M. Keyes
1b2b715389 fix(messages): disallow user-defined integer message-id #38359
Problem:
`nvim_echo(…, {id=…})` accepts user-defined id as a string or integer.
Generated ids are always higher than last highest msg-id used. Thus
plugins may accidentally advance the integer id "address space", which,
at minimum, could lead to confusion when troubleshooting, or in the
worst case, could overflow or "exhaust" the id address space.

There's no use-case for it, and it could be the mildly confusing, so we
should just disallow it.

Solution:
Disallow *integer* user-defined message-id.
Only allow *string* user-defined message-id.
2026-03-18 21:07:17 -04:00
Maria Solano
4430c9a424 feat(lsp): migrate document_color to capability framework (#38344)
* feat(lsp): migrate `document_color` to capability framework

* feat(lsp): use `vim.Range` in `document_color` module
2026-03-18 17:18:48 -07:00
Sean Dewar
6f12663de5 fix(api): nvim_get_option_value FileType autocmd handling #37414
Problem:
nvim_get_option_value with "filetype" set silently returns incorrect
defaults if autocommands are blocked, like when they're already running.

Solution:
Allow its FileType autocommands to nest: `do_filetype_autocmd(force=true)`.
Also error if executing them fails, rather than silently return wrong defaults.

Endless nesting from misbehaving scripts should be prevented by the recursion
limit in apply_autocmds_group, which is 10.
2026-03-18 20:11:59 -04:00
tao
19715e6e8a fix(fs): expand drive-relative paths on Windows #37084
Problem:
On windows, if a drive-relative path doesn't contain a slash,
`path_to_absolute` can't split out the relative component, causing
expansion to fails. e.g., `c:` `c:.` `c:..` `c:foo.md`

Solution:
For these cases, we can pass letter and colon to `path_full_dir_name`.
Notably, `..` is included as well.
if that relative path exists, it can be expanded correctly.
2026-03-18 19:54:19 -04:00
Juan Pablo Briones
f4f1149292 fix(options): vim.opt fails for 'fillchars' #37141
Problem:
When `to_vim_value[info.metatype](info, value)` is called, a list value
such as `{'eob:a'}` is treated like a map, which generates `1:eob:a`.

Note: commands like `:lua vim.opt.wildmode={'longest:full'}` are not an
issue because only cases harcoded in `key_value_options` have metatype `map`.

Solution:
Check for array type and use the same logic as in array metatypes.
2026-03-18 19:19:47 -04:00
glepnir
8f9278d7c2 fix(menu): right-click menu fails with E335 when using V after i_ctrl-o #37349
Problem:
Right-click menu fails with E335 when using V in Insert mode (after
i_ctrl-o). The mode detection checks restart_edit before VIsual_active,
incorrectly selecting Insert mode binding even when Visual mode is
active.

Solution:
Check Visual mode before Insert mode, to match get_menu_mode() priority
order.
2026-03-18 18:52:06 -04:00
Yi Ming
addd408b39 fix(lsp): redraw codelens after request completed #38352
Problem:
When code lens is enabled, `on_attach` is executed, but it does not trigger a redraw. Another event, eg, moving the cursor, is required to trigger a redraw and execute the decoration provider's `on_win`.

Solution:
Trigger a `redraw` after each request is completed.
2026-03-18 11:02:46 -04:00
Ayaan
63642ebf80 refactor(terminal): impl "[Process exited]" in Lua #38343
Problem:
"[Process exited]" is implemented in C with anonymous namespace
and users have no way to hide it.

Solution:
- Handle "TermClose" event in Lua.
- User can delete the "nvim.terminal" augroup to avoid "[Process exited]".
2026-03-18 07:54:41 -04:00
zeertzjq
c3308fa5fe test(tui_spec): remove unnecessary :messages (#38349)
The :echomsg commands already trigger a hit-enter prompt. The :messages
will lead to an intermediate state, which causes the test to be flaky.
2026-03-18 01:49:36 +00:00
zeertzjq
1d776d909f test: always show snapshot if screen:expect_unchanged() fails (#38347)
If the final screen state does match but an intermediate screen state
doesn't, show the first intermediate state.
2026-03-18 07:10:01 +08:00
mgleonard425
b38173e493 feat(terminal): synchronized output (mode 2026) #38284
Problem:
Applications running inside :terminal that use DEC private mode 2026
(synchronized output) to batch screen updates get garbled rendering.
Neovim's embedded libvterm does not handle mode 2026, so the
synchronization sequences are ignored and intermediate screen states
leak through as visual corruption.

Solution:
Add mode 2026 support to libvterm's state machine and wire it through
to terminal.c. When an application enables mode 2026, invalidation of
the terminal buffer is deferred until the application disables it,
causing all accumulated screen updates to flush as a single
atomic refresh.

* fix(terminal): harden sync output redraw gating

Problem:
The initial mode 2026 implementation gated invalidate_terminal()
but missed three other redraw paths: term_sb_push/term_sb_pop
bypassed the gate by directly adding to invalidated_terminals,
refresh_timer_cb could fire mid-sync flushing partial state, and
the 10ms timer delay after sync-end left a window for stale
repaints.

Solution:
- Gate term_sb_push/term_sb_pop during synchronized output
- Skip syncing terminals in refresh_timer_cb
- On sync end, schedule a zero-delay full-screen refresh via
  sync_flush_pending flag in terminal_receive()
- Add news.txt entry for mode 2026 support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test(terminal): add vterm unit tests for mode 2026

Add unit-level tests for synchronized output (mode 2026) to
vterm_spec.lua, covering settermprop callbacks and DECRQM
query/response.

Suggested-by: justinmk

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(terminal): address review feedback for mode 2026

- Use multiqueue_put(main_loop.events) instead of restarting the
  global refresh timer on sync end, to avoid affecting other
  invalidated terminals.
- Add screen:expect_unchanged() to verify screen doesn't update
  during sync mode.
- Merge buffer-lines test into existing test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 17:40:49 -04:00
Justin M. Keyes
02ce446510 docs: api, lsp, messages, intro #38327 2026-03-17 17:02:15 -04:00
glepnir
0da9827673 fix(lsp): respect documentation markup kind in completion preview #38338
Problem:
Completion preview always assumes plain text, ignoring LSP documentation "kind".

Solution:
Pass markup kind from completion item to info window, or fallback to PlainText.
2026-03-17 10:24:30 -04:00
zeertzjq
5773f0e994 fix(marks): make jumpoptions=view work with 'smoothscroll' (#38339)
Problem:  'jumpoptions' "view" doesn't remember skipcol and may lead to
          glitched display with 'smoothscroll'.
Solution: Save skipcol in the mark view. Also make sure skipcol doesn't
          exceed line size.
2026-03-17 21:52:25 +08:00
Harsh Kapse
a5b8cf145d feat(diff): merge adjacent blocks using inline:word (#37085)
vim-patch:9.2.0174: diff: inline word-diffs can be fragmented

Problem:  When using 'diffopt=inline:word', lines were excessively
          fragmented with punctuation creating separate highlight
          blocks, making it harder to read the diffs.
Solution: Added 'diff_refine_inline_word_highlight()' to merge
          adjacent diff blocks that are separated by small gaps of
          non-word characters (up to 5 bytes by default) (HarshK97).

When using inline:word diff mode, adjacent changed words separated by
punctuation or whitespace are now merged into a single highlight block
if the gap between them contains fewer than 5 non-word characters.

This creates more readable diffs and closely matches GitHub's own diff
display.

closes: vim/vim#19098

42c6686c78
2026-03-17 12:11:55 +00:00
zeertzjq
9ab6c607cc vim-patch:9.2.0180: possible crash with winminheight=0 (#38335)
Problem:  possible crash with winminheight=0
          (Emilien Breton)
Solution: Use <= instead of < when checking reserved room in
          frame_setheight() to correctly handle the zero-height
          boundary case (Hirohito Higashi).

In frame_setheight(), when shrinking the current window and the only
other window has 'winfixheight' with 'winminheight'=0, room_reserved
was not cleared because the condition used '<' instead of '<='.
The freed rows were discarded, leaving fr_height sum less than
topframe fr_height.  Subsequent resize operations then computed a
wrong room_cmdline that expanded topframe beyond the screen, causing
a crash.

fixes:  vim/vim#19706
closes: vim/vim#19712

a5d9654620

Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
2026-03-17 00:02:32 +00:00
Sean Dewar
33b357d01f vim-patch:9.2.0182: autocmds may leave windows with w_locked set #38332
Problem:  autocmds that switch windows may cause them to remain with
          w_locked set, preventing them from being closed longer than
          intended.
Solution: Unset w_locked in the window where it was set (Sean Dewar).

closes: vim/vim#19716

bae31c35bb

Also move alist_add_list's ga_grow inside the if block, so it's only called when
check_arglist_locked is OK, like Vim.

I also notice a redundant return at the end of the block; could be useful if
more code is added later, so I'm leaving it.
2026-03-16 23:05:39 +00:00
Shadman
7b7e8cc724 feat(progress): disable cmdline progress msg via messagesopt' #36730
Problem:
No way to disable progress messages in cmdline message area. If
a third-party plugin handles Progress events + messages, the user may
not want the "redundant" progress displayed in the cmdline message area.

Solution:
Support "progress:c" entry in 'messageopts' option.
2026-03-16 11:29:47 -04:00
Justin M. Keyes
680d25e5b3 fix(api): use standard error messages 2026-03-16 14:52:04 +01:00
Justin M. Keyes
b8f1426a86 Merge #27223 nvim_open_tabpage 2026-03-16 09:51:27 -04:00
glepnir
88a72efb46 fix(diagnostic): open_float() handles config.float function #31577
Problem:
The `float` field of vim.diagnostic.config can be a function,
but diagnostic.open_float() does not handle it correctly.

Solution:
Add handling for it in open_float().
2026-03-16 09:50:13 -04:00
Sean Dewar
97b064c9ac fix(api): nvim_open_tabpage positional "enter"
Problem: nvim_open_tabpage's "enter" argument is optional, which is inconsistent
with nvim_open_win.

Solution: make it a (non-optional) positional argument, like nvim_open_win.

Also change "enter"'s description to be more like nvim_open_win's doc.
2026-03-16 13:20:45 +00:00
Sean Dewar
0c1ed63c05 fix(api): nvim_open_tabpage "after" like :[count]tab
Problem: "after" in nvim_open_tabpage is inconsistent with how a count works
with :tab, :tabnew, etc. Plus, the name "after" implies it's inserted after that
number.

Solution: internally offset by 1. Allow negative numbers to mean after current.

Hmm, should we even reserve sentinels for after current? Callers can probably
just use nil...
2026-03-16 13:05:47 +00:00
Sean Dewar
cd4c98fded fix: nvim_open_tabpage cleanup, fixes, more tests
- Cleanup, remove redundant comments, add more tests.
- Enhance win_new_tabpage rather than create a new function for !enter, and use
  a different approach that minimizes side-effects. Return the tabpage_T * and
  first win_T * it allocated.
- Disallow during textlock, like other APIs that open windows.
- Remove existing win_alloc_firstwin error handling from win_new_tabpage; it's
  not needed, and looks incorrect. (enter_tabpage is called for curtab, which is
  not the old tabpage! Plus newtp is not freed)
- Fix checks after creating the tabpage:
  - Don't fail if buf wasn't set successfully; the tab page may still be valid
    regardless. Set buffer like nvim_open_win, possibly blocking Enter/Leave
    events. (except BufWinEnter)
  - tp_curwin may not be the initial window opened by win_new_tabpage. Use the
    win_T * it returns instead, which is the real first window it allocated,
    regardless of autocmd shenanigans.
  - Properly check whether tab page was freed; it may have also been freed
    before win_set_buf. Plus, it may not be safe to read its handle!
2026-03-16 13:05:47 +00:00
Will Hopkins
e80d19142b feat(api): add nvim_open_tabpage
Problem: no API function for opening a new tab page and returning its handle, or
to open without entering.

Solution: add nvim_open_tabpage.
2026-03-16 13:05:46 +00:00
Justin M. Keyes
c82f83abb0 fix(ux): drop "Sorry" from messages #38318
Problem:
"Sorry" in a message (1) is noise, and (2) actually reduces the clarity
of the message because the titlecasing of "Sorry" distracts from the
actually important part of the message.

Solution:
Drop "Sorry" from messages.
2026-03-16 07:46:34 -04:00
Yinzuo Jiang
6dd634b025 vim-patch:9.2.0143: termdebug: no support for thread and condition in :Break
Problem:  termdebug :Break does not support `thread` and `if` arguments
Solution: extend :Break and :Tbreak to accept optional location, thread
          {nr}, and if {expr} arguments (Yinzuo Jiang).

closes: vim/vim#19613

5890ea5397

AI-assisted: Codex
2026-03-16 19:05:15 +08:00
zeertzjq
9d025e6a4d test(old): avoid indexing undefined signs
Co-authored-by: Yinzuo Jiang <jiangyinzuo@foxmail.com>
2026-03-16 19:05:15 +08:00
Yinzuo Jiang
42640c62d1 vim-patch:partial:9.1.1004: tests: a few termdebug tests are flaky
Problem:  tests: a few termdebug tests are flaky; test_termdebug_basic()
          and test_termdebug_config_types() may fail if there is too
          much load
Solution: Set g:test_is_flaky

Only include:
- mark Test_termdebug_basic() as flaky in oldtest termdebug plugin tests

The Test_termdebug_config_types() part does not apply here.

ebb08d5913

Co-authored-by: Christian Brabandt <cb@256bit.org>
AI-assisted: Codex
2026-03-16 19:05:15 +08:00
Yinzuo Jiang
dff515205c vim-patch:partial:9.1.0613: tests: termdebug test may fail and leave file around
Problem:  tests: termdebug test may fail and leave temp file around
          (Dominique Pellé)
Solution: only run balloon_show() if the function exists, validate
          termdebug is running using the g: termdebug_is_running var,
          use defer to delete temporary files

Only include:
- guard balloon_show() in the termdebug plugin
- wait for g:termdebug_is_running in Test_termdebug_basic()

The remaining upstream test cleanups do not apply here.

fixes: vim/vim#15334

2979cfc262

Co-authored-by: Christian Brabandt <cb@256bit.org>
AI-assisted: Codex
2026-03-16 19:05:15 +08:00
Sean Dewar
3cd07709ba fix(terminal): don't always leave if enter autocmds delete buffer #38324
Problem: #38316 is a bit aggressive; we need not always leave Terminal mode if
autocmds put us in a different terminal.

Solution: don't skip entering; let terminal_check_focus handle whether we should
immediately leave.
2026-03-16 09:56:36 +00:00
Justin M. Keyes
16f7440cc7 feat(help): super K (":help!") guesses tag at cursor #36205
Problem:
`K` in help files may fail in some noisy text. Example:

      (`fun(config: vim.lsp.ClientConfig): boolean`)
                            ^cursor

Solution:
- `:help!` (bang, no args) activates DWIM behavior: tries `<cWORD>`,
  then trims punctuation until a valid tag is found.
- Set `keywordprg=:help!` by default.
- Does not affect `CTRL-]`, that is still fully "tags" based.
2026-03-15 19:02:49 -04:00
Sean Dewar
1c57e4cb4f fix(terminal): heap UAF from autocmds when entering #38316
Problem: heap-use-after-free possible when entering Terminal mode if
autocommands close the terminal.

Solution: set the refcount. Skip to the end if we must close the terminal.
2026-03-15 17:38:25 -04:00
phanium
0ca9849387 fix(statusline): missing info/hint diagnostics #38307
Problem: default stl treat vim.diagnostics.count() return as array

Solution: next() tell if a dict is empty
2026-03-15 10:35:08 -04:00
zeertzjq
9084483715 test(ui/mode_spec): fix retry not working (#38300) 2026-03-15 08:00:07 +08:00
zeertzjq
0082cd3134 vim-patch:9.2.0165: tests: perleval fails in the sandbox
Problem:  tests: perleval fails in the sandbox
          (after v9.2.0156)
Solution: Update tests and assert that it fails

related: vim/vim#19676

3f89324b3a

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-03-15 06:31:26 +08:00
zeertzjq
1aaa8e8e3a vim-patch:9.2.0162: tests: unnecessary CheckRunVimInTerminal in test_quickfix
Problem:  tests: unnecessary CheckRunVimInTerminal in test_quickfix.vim
          (after v9.2.0159)
Solution: Remove it (zeertzjq).

closes: vim/vim#19671

81d5329ace
2026-03-15 06:28:47 +08:00
zeertzjq
80684a418b vim-patch:9.2.0159: Crash when reading quickfix line
Problem:  Crash when reading quickfix line (Kaiyu Xie)
Solution: Make sure line is terminated by NUL

closes: vim/vim#19667

Supported by AI

8d13b8244a

Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-03-15 06:26:53 +08:00
Sean Dewar
3115e3d0d1 fix(api): improve external window validation
Problem: "win" is allowed in external window configs in some cases. External
window converted to normal float can't move tabpages in one nvim_win_set_config
call. External window can't be turned into a normal split.

Solution: disallow setting "win" for external windows. Allow external window to
move tabpages, which turns it non-external. Allow external window to be turned
into a (non-external) split.

parse_win_config has more validation issues from not considering the window's
existing config enough (not from this PR). For example, zindex can be set for an
existing split if "split"/"vertical" isn't given, despite intending for that to
be an error. Plus the logic is confusing.

It could do with a refactor at some point...
2026-03-14 20:48:32 +00:00
Sean Dewar
853eea859f fix(api): disallow moving window between tabpages in more cases
Problem: more cases where it may not be safe to move a window between tabpages.

Solution: check them.

Rather speculative... I haven't spend much time looking, but I didn't find
existing code that sets these locks to skip checking win_valid. (what I did find
called it anyway, like in win_close) Still, I think it's a good precaution for
what future code might do.

If the fact that nvim_win_set_config *actually* moves windows between tabpages
causes unforeseen issues, "faking" it like ":wincmd T" may be an alternative:
split a new window, close the old one, but instead also block autocmds, copy the
old window's config, and give it its handle?
2026-03-14 20:48:32 +00:00
Sean Dewar
094b297a3b feat(api): nvim_win_set_config can move split to other tp as floatwin
Problem: not possible for nvim_win_set_config to convert a split to a floatwin,
then move it to another tabpage in one call.

Solution: allow it.
2026-03-14 20:48:32 +00:00
Sean Dewar
3325536150 fix(winfloat): last_status when changing split to floatwin
Problem: converting a split to a floatwin may not remove the last statusline
when needed. (e.g: 'ls' is 1)

Solution: call last_status/win_comp_pos in win_new_float, after win_remove.

Also fix float_pos formatting for screen snapshots so it doesn't give a nil
error for external windows.

Not an issue from this PR.
2026-03-14 20:48:32 +00:00
Sean Dewar
7be4ae796f fix(api): relax config validation for "win"
Problem: only possible to move floats between tabpages if relative=win, which
has the restrictive effect of also anchoring it to the target window.

Solution: allow "win" without "relative" or "split"/"vertical". Only assume
missing "win" is 0 if relative=win is given to maintain that behaviour. (or when
configuring a new window)

Also add an error when attempting to change a split into a float that's in
another tabpage, as this isn't actually supported yet. (until the next commit)

Maybe this could do with some bikeshedding. Unclear if "win" should require
"relative" to be given, like with "row"/"col"; this can be annoying though as
specifying "relative" requires other fields to be given too.
2026-03-14 20:48:31 +00:00
Sean Dewar
ef084b5c22 fix(api): don't config split as floatwin relative to itself
Problem: possible to configure a split as a floatwin with relative=win that is
relative to itself.

Solution: fix the check.

Not caused by this PR; just something I noticed when about to fix the validation
logic.
2026-03-14 19:27:20 +00:00
Sean Dewar
c924c2a7b3 fix(api): win_config_float_tp grid removal, redraw
Problem: when nvim_win_set_config moves a floatwin between tabpages, its grid
may remain if temporarily inside another tabpage. Also, things like tablines
aren't redrawn.

Solution: always remove its grid. Set must_redraw so things are redrawn even if
w_redr_type was already set for the old tabpage.

I don't think it's necessary to do anything extra here when removing the grid:

- win_ui_flush calls ui_call_win_hide anyway, and calling it manually ends up
  sending two win_hide events.
- ui_comp_remove_grid safely does nothing if the grid doesn't exist.
- w_pos_changed is set by win_config_float later, if that's needed. I think the
  pending_comp_index_update set by ui_comp_remove_grid is enough anyway, at
  least for making sure win_ui_flush sends win_hide.

Added test fails with the prior approach of checking `parent_tp != curtab`, but
also `win_tp == curtab`. (which is a better, but still flawed alternative)

The added redrawing here also supersedes setting w_hl_needs_update, and also
redraws stuff like the tabline to pass the new test.
2026-03-14 19:27:20 +00:00
Sean Dewar
e5240b35c3 refactor(api): cleanup, more comments, more tests, news
- Factor out logic to keep nvim_win_set_config clean.
- Clean up a few things, remove redundant logic, reflow some lines.
- Add some more comments where appropriate.
- Don't consider negative "win", as that's only relevant for splits.
- Add more test coverage.
- Add news.txt entry.
2026-03-14 19:27:19 +00:00
glepnir
e2a0748cb2 feat(api): nvim_win_set_config can move floatwin to another tabpage
Problem: nvim_win_set_config can't move floating windows to different tab pages.

Solution: allow it.

Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
2026-03-14 18:45:29 +00:00
luukvbaal
83037cf218 fix(messages): allocate message history kind string #38292
Problem:  nvim_echo()->kind memory may be used after it is freed with :messages.
Solution: Copy and free message kind string in message history.
2026-03-14 08:07:55 -04:00
glepnir
5653b25e9b fix(lsp): handle non-string documentation in completion items #38291
Problem: `get_doc` throws error with "attempt to get length of a userdata
value" when `item.documentation` is truthy but not a string (e.g. vim.NIL
from a JSON null).

Solution: Check `type(item.documentation)` before taking its length.
2026-03-14 05:20:34 -04:00