Commit Graph

8376 Commits

Author SHA1 Message Date
Justin M. Keyes
31ad7d4527 Merge #40621 fix(ui2)!: legacy 'ruler' inconsistencies 2026-07-15 08:13:37 -04:00
phanium
6f370f34f2 fix(window): remove float grid from compositor layers before free #40731
Problem: Closing a floating window from a non-current tab frees its grid
without removing it from the compositor's `layers` table, so the next
`ui_comp_put_grid()` walks a dangling pointer (UAF).

Solution: Call `ui_comp_remove_grid()` (and `ui_call_win_close()` for
multigrid UIs) before `win_free_mem()`, matching `win_close()` since
PR #21551.
2026-07-15 07:48:34 -04:00
Barrett Ruth
b2570e6852 fix(showcmd): avoid stale %S contents #40747
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
2026-07-15 06:10:09 -04:00
Justin M. Keyes
671e9d4913 feat(marks): :marks completion, list extmarks #40743
Problem:
- No UI for listing extmarks.
- `:marks` doesn't support cmdline-completion.

Solution:
- Add completion and extmarks support to `:marks`.
- Update `get_buf_local_marks` to include the ":" (prompt-buffer) mark.
2026-07-15 05:55:51 -04:00
zeertzjq
f17dfc9ab3 test: fix typo (#40750) 2026-07-15 07:55:01 +00:00
zeertzjq
39bc59a8f1 fix(floatwin): don't use same window as altwin (#40748)
Fixes a regression from #34486
Fix #40745
2026-07-15 05:59:45 +00:00
Barrett Ruth
4b69d3fd2d test: adjust exit waits for slow CI (#40739) 2026-07-15 05:37:28 +08:00
Barrett Ruth
0bb2f5cc08 fix(ftplugin): source inherited Lua ftplugins
Problem:
Vimscript ftplugins that inherit a base ftplugin often use explicit
`runtime! ftplugin/foo.vim` patterns. This skips corresponding Lua
ftplugins, unlike top-level ftplugin loading.

Solution:
Use the existing `{vim,lua}` patterns for bang runtime imports while
preserving each call's current lookup breadth.
2026-07-14 00:18:50 +02:00
Justin M. Keyes
eb94149a29 refactor(vimscript)!: drop ctxget(), ctxpush(), etc #40724
Problem:
This functions are most likely never used in the wild.
- They are redundant with `nvim_get_context` + `nvim_load_context`.
- The "context" concept was never fully developed and hasn't gained
  traction.

Solution:
Drop these vimscript aliases, they are just extra cruft.
2026-07-13 17:57:13 -04:00
Barrett Ruth
73bb6a8a5e fix(dir): let 3P dir-browser plugin rename the dir buffer #40529
Problem:
`FileType directory` fires *before* the `BufEnter` path where `dir.lua`
populates the buffer, in order to allow a 3P dir-browser plugin to handle the
event and (optionally) rename the buffer to e.g. `example:///tmp/foo/`.

But currently, `open_buffer()` continues after `filetypedetect BufRead` as if
the original directory buffer is *still* current and valid, which may fall
through to the built-in `nvim.dir` path after a 3P plugin ALREADY handled the
directory.

Solution:
Keep a buf ref around the early `filetypedetect BufRead` call for directory
buffers.

If the `FileType directory` handler switches away from/deletes the original
directory buffer, stop the open path instead of continuing into the built-in
`nvim.dir` flow.
2026-07-13 15:10:19 -04:00
Justin M. Keyes
dc8934482e feat(api): optional params after opts #40720
Problem:
After 25439dad7e, `opts` is optional, but not params that follow it.

Solution:
- Update `gen_api_dispatch.lua`, docs, tests.
- Enhance the `nvim_get_api_info()` api-metadata to include a boolean
  flag indicating whether a parameter is optional:
  ```
  [type, name, optional]
  ```

Note: Currently, optional params are assumed to be Dict/Array. Since we
don't yet have any use-cases of optional params following `opts`, the
build just checks this assumption and we can deal with it later if we
ever care to:

    nvim_get_hl: optional param "foo" has type "Integer" but (currently)
    we assume Dict/Array
2026-07-13 13:43:49 -04:00
Justin M. Keyes
f50f421694 test(pack): unreliable "vim.pack" tests on Windows #40717
FAILED   …/plugin/pack_spec.lua:92: …/plugin/pack_spec.lua @ 70: vim.pack update() can use lockfile revision as a target
    …/plugin/pack_spec.lua:92: …/plugin/pack_spec.lua:70: process still exists
    stack traceback:
    D:/a/neovim/neovim/test/functional/testnvim/exec_lua.lua:124: in function 'system_sync'
    …/plugin/pack_spec.lua:92: in function 'git_cmd'
    …/plugin/pack_spec.lua:113: in function 'git_add_commit'
    …/plugin/pack_spec.lua:1209: in function <…/plugin/pack_spec.lua:1173>

fix #40167
2026-07-13 10:49:48 -04:00
Barrett Ruth
25439dad7e feat(api): relax contract, opts + rest params are optional #40581
Problem:
|api-contract| allows adding an optional trailing `opts` parameter, but
the dispatch generator still requires every parameter, so `opts` cannot
be omitted.

Solution:
Treat a trailing `Dict(...) *opts` parameter as optional in the generated
RPC and Lua dispatch wrappers.

Co-authored-by: Judit Novak <judit.novak@gmail.com>
2026-07-13 10:28:24 -04:00
Barrett Ruth
1665b992b7 fix(filetype): trigger FileType after BufReadCmd #40679
Problem:
A successful `BufReadCmd` can leave an existing `filetype` without
rerunning its `FileType` setup, so state cleared during reload may not
be restored.

This also causes `:edit`/reload syntax `directoryDirectory` groups to
not be reapplied.

Solution:
After `BufReadCmd` handles a read, trigger `FileType` for the existing
`filetype` if no `FileType` event fired during the read.
2026-07-13 09:08:09 -04:00
Justin M. Keyes
e1c1bd3722 fix(coverity): RESOURCE_LEAK, USE_AFTER_FREE
/src/nvim/ex_docmd.c: 5033             in ex_restart()
    5027         // The address after --listen may be in use by the current server.
    5028         if (i > 0 && strequal(arg, "--listen")) {
    5029           const listitem_T *next_li = li->li_next;
    5030           if (next_li != NULL) {
    5031             const char *addr = tv_get_string(TV_LIST_ITEM_TV(next_li));
    5032             if (strstr(addr, ":") || strstr(addr, "/") || strstr(addr, "\\")) {
    >>>     CID 649201:         Resource leaks  (RESOURCE_LEAK)
    >>>     Overwriting "listen_arg" in "listen_arg = xstrdup(addr)" leaks the storage that "listen_arg" points to.
    5033               listen_arg = TO_SLASH_SAVE(addr);
    5034     #ifdef MSWIN
    5035               // On Windows, don't pass --listen to new server (named pipe can't be reused immediately).
    5036               // Instead pass the address via RPC; new server rebinds after startup.
    5037               li = next_li;
    5038               continue;

    *** CID 649200:         Memory - illegal accesses  (USE_AFTER_FREE)
    /src/nvim/eval/fs.c: 228             in modify_fname()
    222
    223       // ":h" - head, remove "/file_name", can be repeated
    224       // Don't remove the logical root, see `FileInfo`.
    225       while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') {
    226         valid |= VALID_HEAD;
    227         *usedlen += 2;
    >>>     CID 649200:         Memory - illegal accesses  (USE_AFTER_FREE)
    >>>     Using freed pointer "s".
    228         while (tail > s && after_pathsep(s, tail)) {
    229           MB_PTR_BACK(*fnamep, tail);
    230         }
    231         *fnamelen = tail <= s ? (size_t)(s - *fnamep) : (size_t)(tail - *fnamep);
    232         if (*fnamelen == 0) {
    233           // Result is empty.  Turn it into "." to make ":cd %:h" work.
2026-07-13 05:48:05 +02:00
tao
4a08596314 fix(path): normalize separators (slashes) #39155
Problem:
Continue separators normalization, and try to keep it at the
nvim <-> external boundary, e.g., `fn.xxx`, `api.xxx`, `:xxx`

Solution:
some key changes
- normalize `$HOME-windows`
- normalize entry points of changing directory
  - `nvim_set_current_dir()`, `chdir()`
- normalize the named pipe
  - `--listen` arg, `--server` arg, `:restart`
  - `serverstart()`, `sockconnect()`, `serverstop()`
- make `expand()` respect 'shellslash' again
- clean up `did_set_shellslash`
- replace `forward_slash` with `TO_SLASH`
- remove obsolete `TMP_PATHSEPSTR`
- remove `slash_adjust` in `do_autocmd_dirchanged`?
- make `fnamemodify()` always return `/` (except when substituting
  separators via `:s`, `:gs` ?)

Note:
- these funcs still apply `slash_adjust` on return, as before:
  `:pwd`, `chdir()`, `exepath()`, `getcwd()`
- these funcs alwarys return `/`, unlike before the normalization PRs
  - `getcompletion()`, `finddir()`, `findfile()`

Also
- clean up code, comments, formatting and tests
- move `TO_SLASH` from `f_chdir` to `changedir_func`
- move `TO_SLASH` from `f_bufadd` to `buflist_new`

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2026-07-12 13:23:44 -04:00
Kim A. Brandt
543a96e491 fix(lsp): unclear error on malformed server responses #40422
Problem:
Malformed server responses with `null` (vim.NIL) values, do not show
clear error messages.


Solution:
Assert two known, specific cases, to avoid user confusion.
2026-07-12 12:52:10 -04:00
glepnir
58b6310adc fix(startup): respect enter for windows created in startup scripts #37287
Problem: When a split window is created from the init script using nvim_open_win()
with enter=false, the current window focus is not preserved. The cursor
incorrectly moves into the newly created split during startup.

Solution: Save curwin before the iteration loop in create_windows(), and
restore it after the loop. also update edit_buffers() to use curwin instead
of firstwin.
2026-07-12 12:30:40 -04:00
Justin M. Keyes
81c4c295ac refactor(insert): rename edit.c => insert.c #40705
Problem:
- `edit.c` is an unnecessarily misleading and less-discoverable name
  than `insert.c`.
- Numerous insert-mode related things are named with a `ins_` prefix.
- There is already a `insexpand.c` module...

Solution:
Rename `edit.c` => `insert.c`.
2026-07-12 11:57:17 -04:00
Justin M. Keyes
88b627d72d test(autoread): unreliable "coalesces rapid changes via debouncing"
previous: #40272

    FAILED   …/autoread_spec.lua @ 142: autoread file watcher coalesces rapid changes via debouncing
    Expected values to be equal.
    Expected:
    1
    Actual:
    2
    stack traceback:
    …/autoread_spec.lua:169: in function <…/autoread_spec.lua:142>
2026-07-12 15:15:46 +02:00
Justin M. Keyes
d25ae8b8c2 refactor(input): rename getchar.c => input.c #40698
Problem:
`getchar.c` is a quirky name and doesn't align with our existing
`os/input.c` and `tui/input.c` modules, which encompass the same topic
at different layers.

Solution:
Rename `getchar.c` => `input.c` for discoverability.

Introduce `dialog.c` for functionality related to showing confirm
prompts, dialogs, etc.
2026-07-12 08:34:13 -04:00
Barrett Ruth
67af4141c8 fix(filetype): false positive when matching directory buffer #40695
Problem:
URI buffer names can end with a slash, but slash-ended directory
matching should not preempt URI filetype patterns.

Solution:
Do not use the slash shortcut for names with URI schemes, so those
continue through normal filetype matching.

Co-authored-by: Adam Karafyllidis <akisarou90@gmail.com>
2026-07-11 18:19:44 -04:00
Sébastien Hoffmann
0ffd74ae85 fix(ui2): fix ruler on repeated messages
Problem: a long message is cropped to keep the ruler visible. But when
the message is repeated, it can be written over the ruler, while the
repetition indicator "(1)" is still placed just before the ruler, which
ends up somewhere inside the message.

Solution: currently, long messages are only cropped when setting the
'last' virttext. Make sure this happens after a repeated long message.
2026-07-11 18:44:42 +02:00
Sébastien Hoffmann
2473cb62b7 fix(ui2): correctly crop message at multibyte/multicell character 2026-07-11 18:31:54 +02:00
Sébastien Hoffmann
fcc391d89a fix(ui2): clear showcmd virt_text together with search count
Problem: when the search count is displayed, the showcmd virt_text is
set to 11 empty spaces to ensure a consistent distance between search
count and ruler, or screen edge in case of noruler. But when the search
count is removed to make place for a message, the empty dummy showcmd
remains and unnecessarily erases part of the message.

Solution: properly remove showcmd together with search count.
2026-07-11 18:31:54 +02:00
Sébastien Hoffmann
60687ccb6a fix(ui2)!: consistent ruler width inside/outside statusline
Problem: before ui2, the ruler in the last line had a one cell safety
margin on the right because writing in the last column of the last line
"scrolls the screen up on some terminals," according to code comments.
When the ruler is included in the statusline, it aligns on the left with
the normal ruler, but goes all the way to the screen edge on the right,
and is therefore one cell longer.

Since ui2 doesn't have that padding cell, they don't align anymore.

Also, in the future, when the C implementation of the ruler will be
replaced with a default expression that will be included in the default
statusline (currently `%-14.(%l,%c%V%) %P`), the width will naturally be
the same in both places, and the unit tests will need adapting anyway.

Solution: when ui2 is active, increase the ruler width by 1.

BREAKING CHANGE: the default ruler in ui2 is now 1 cell wider.

ref https://github.com/neovim/neovim/issues/40247
2026-07-11 18:31:54 +02:00
Justin M. Keyes
0f1e0a7900 refactor(ctx): drop aucmd_prepbuf/aucmd_restbuf #40692 2026-07-11 12:04:31 -04:00
Justin M. Keyes
f2d15fc0b0 refactor(input): ungetchars() usage #40685
Repurpose `ins_char_typebuf` to make its usage more obvious.
Rename it and update docs.
2026-07-11 10:53:30 -04:00
Justin M. Keyes
d1b7a39fc3 test: unreliable "TUI split sequences within 'ttimeoutlen'"
FAILED   ...Xtest_xdg_terminal/test/functional/terminal/tui_spec.lua @ 1200: TUI split sequences work within 'ttimeoutlen' time
    .../runner/work/neovim/neovim/test/functional/ui/screen.lua:774: Row 1 did not match.
    Expected:
      |*^                                                  |
      |{100:~                                                 }|
      |{100:~                                                 }|
      |{100:~                                                 }|
      |*{3:[No Name]                                         }|
      |{5:-- INSERT --}                                      |
      |{5:-- TERMINAL --}                                    |
    Actual:
      |*�^                                                 |
      |{100:~                                                 }|
      |{100:~                                                 }|
      |{100:~                                                 }|
      |*{3:[No Name] [+]                                     }|
      |{5:-- INSERT --}                                      |
      |{5:-- TERMINAL --}                                    |
2026-07-11 14:46:48 +02:00
Justin M. Keyes
f2927bd919 test: unreliable "vim.system (async) supports timeout"
FAILED   2 tests, listed below:
    FAILED   …/lua/system_spec.lua:124: …/lua/system_spec.lua @ 44: vim.system (async) supports timeout
    …/lua/system_spec.lua:124: …/lua/system_spec.lua:44: process still exists
    stack traceback:
    D:/a/neovim/neovim/test/functional/testnvim/exec_lua.lua:124: in function 'system'
    …/lua/system_spec.lua:124: in function <…/lua/system_spec.lua:118>
    FAILED   …/lua/system_spec.lua:111: …/lua/system_spec.lua @ 22: vim.system (sync) can set environment with clear_env = true and env = nil
    …/lua/system_spec.lua:111: …/lua/system_spec.lua:22: process still exists
    stack traceback:
    D:/a/neovim/neovim/test/functional/testnvim/exec_lua.lua:124: in function 'system'
    …/lua/system_spec.lua:111: in function <…/lua/system_spec.lua:97>
2026-07-11 14:46:48 +02:00
Justin M. Keyes
141a498cca test: unreliable "API nvim_list_chans, nvim_get_chan_info stream=job :terminal channel"
FAILED   ...vim/build/Xtest_xdg_api/test/functional/api/vim_spec.lua @ 3256: API nvim_list_chans, nvim_get_chan_info stream=job :terminal channel
    Expected values to be equal.
    Expected:
    {
      argv = { "/home/runner/work/neovim/neovim/build/bin/nvim", "-u", "NONE", "-i", "NONE" },
      buf = 2,
      buffer = 2,
      exitcode = 1,
      id = 4,
      mode = "terminal",
      pty = "",
      stream = "job"
    }
    Actual:
    {
      argv = { "/home/runner/work/neovim/neovim/build/bin/nvim", "-u", "NONE", "-i", "NONE" },
      buf = 2,
      buffer = 2,
      exitcode = 129,
      id = 4,
      mode = "terminal",
      pty = "",
      stream = "job",
      <metatable> = {
        __tostring = <function 1>
      }
    }
    stack traceback:
    ...vim/build/Xtest_xdg_api/test/functional/api/vim_spec.lua:3300: in function <...vim/build/Xtest_xdg_api/test/functional/api/vim_spec.lua:3256>
2026-07-11 14:46:48 +02:00
Justin M. Keyes
f1904f2a6c test(dir): "replace - mapping" hangs the Windows CI 2026-07-11 14:09:05 +02:00
Justin M. Keyes
8d51e07fa1 feat(eval): writefile() treats RPC string as "blob"
related: fb6aeaba2d
2026-07-11 13:49:52 +02:00
Justin M. Keyes
eb2e695e40 test: "Failed to start server: address already in use" #40683
Problem:
unreliable test:

    FAILED   …/tui_spec.lua @ 895: TUI mouse events work with right-click menu (escape sequences sent to child)
    D:/a/…/testnvim.lua:144: Vim:Failed to start server: address already in use
    stack traceback:
    D:/a/…/testnvim.lua:144: in function 'eval'
    D:/a/…/testnvim.lua:1015: in function 'new_pipename'
    …/tui_spec.lua:897: in function <…/tui_spec.lua:895>

Solution:
Workaround potential PID reuse.
2026-07-11 06:52:04 -04:00
Barrett Ruth
784765cb73 fix(winbar): update hidden tabpages on global 'winbar' change #40608
Problem:
Changing global 'winbar' only updates window layout state in the current
tabpage. This means existing hidden tabs can keep stale winbar height.

Solution:
Recompute winbar state for all tabpages on global `'winbar'` changes.
2026-07-10 12:49:52 -04:00
Barrett Ruth
3b88a8a65d fix(filetype): ensure directory bufname ends w/ slash sep #40552
Problem:
`vim.filetype.match()` needs a cheap way to recognize directory buffers
without doing filesystem stat work.

Solution:
Ensure full buffer names for directories end in a trailing slash. Now
directory buffers can proceed through the normal 'filetype' path.

Note side-effects: session and ShaDa buffer-list restore behavior must
be compatible, so those + corresponding tests must be updated.
2026-07-10 12:40:13 -04:00
Barrett Ruth
20a4b1bc5e fix(dir): user/plugin can override default "-" mapping #40676 2026-07-10 11:52:24 -04:00
Justin M. Keyes
d79c787f27 refactor(ctx): ctx_restore_curwin #40667
unify context-switching logic.

1. `prevwin` is now restored for all targets (was buf-only).
   - add a `nvim_win_call` test.
2. The buf-found "restore the shown buffer" dance no longer depends on
   the origin window: it runs even if the callback closed the origin.
2026-07-10 07:58:02 -04:00
Justin M. Keyes
6bb1aa74e6 refactor: unify context-switching concepts 2026-07-10 03:27:37 +02:00
Justin M. Keyes
982d2f2531 fix(test): screen:expect({none=…}) with no any/grid
Problem:
`screen:expect({none=…})` with no any/grid crashed (concat on nil)
because actual_rows was only rendered when any or grid was present.

Solution:
Update the condition.
2026-07-10 00:06:59 +02:00
Barrett Ruth
7dccbfed10 fix(dir): select origin on parent navigation #40658 2026-07-09 17:47:56 -04:00
MAAZIZ Adel Ayoub
de141b4679 fix(socket): --listen silently truncates long paths #40625
Problem:
A `--listen` path longer than the system socket path limit (~104 bytes on
macOS, 108 on Linux) is silently truncated by `uv_pipe_bind()`. Nvim either
serves a socket at a different path than `v:servername` reports, or fails with
an error that blames the full untruncated path (confusing):

    nvim: Failed to --listen: address already in use: "<full path>"

Steps to reproduce:

    $ nvim --listen /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide --embed -p
    nvim: Failed to --listen: address already in use: "/var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide"

    $ ls /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide
    "/var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide": No such file or directory (os error 2)

    $ ls -l /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/
    srwxr-xr-x@ - rpatterson 31 Mar 10:24 -Users-rpatterson-Projects-src-github.com-neovid

Solution:
Bind with `uv_pipe_bind2()` and `UV_PIPE_NO_TRUNCATE` (libuv 1.46+), so
a too-long path fails up front with the actual reason:

    nvim: Failed to --listen: invalid argument: "<full path>"
2026-07-09 16:07:17 -04:00
Barrett Ruth
a54a7f6a78 fix(dir): preserve alternate buffer #40659 2026-07-09 15:41:09 -04:00
Nathan Zeng
c0a16a5977 feat(restart)!: ZR restores session #40498 2026-07-09 07:09:12 -04:00
Evgeni Chasnovski
fce6d9a549 feat(lua): add cwd context to vim._with() #40653
Problem: No concise way to execute a callback with temporarily set
  working directory. This might be useful when sourcing nested files to
  allow them to assume that current working directory is their root
  directory.

Solution: Add `cwd` context to `vim._with().`
2026-07-09 07:07:14 -04:00
zeertzjq
7c9222f45e fix(mouse): reset click count on next click if mouse moved (#40637)
Also, drop drag event if the mouse hasn't moved, like in gVim.
2026-07-09 08:40:00 +08:00
Justin M. Keyes
d55252a3ec refactor(logging)!: rename current_level #40642 2026-07-08 20:15:42 +00:00
Evgeni Chasnovski
0653e7a338 feat(pack): 'packlockfile' option #40562
Problem: No way to configure the lockfile location.

Solution: Add 'packlockfile' option.
2026-07-08 12:23:28 -04:00
Oleh Volynets
ef130902cf fix(lsp): clear push diagnostics on detach #40634
Problem: when an LS client detaches from the buffer, only pull diagnostics
are cleared via capability framework. Push diagnostics remain stuck even
when client stops/restarts.

Solution: clear push diagnostics on client detach.

ref #33864
2026-07-08 12:00:21 -04:00
Caleb White
653f2092ce fix(lsp): refresh document-pull buffers on workspace/diagnostic/refresh #40623
When a server supports both document and workspace pull diagnostics,
`on_refresh` only dispatched a `workspace/diagnostic` request.  The
workspace response handler skips buffers with `pull_kind == "document"`
(i.e. all buffers opened by the user), so their diagnostics went stale
until the next `didChange` or `didOpen` event.

Change `on_refresh` to always refresh document-pull buffers via
`textDocument/diagnostic`, regardless of whether the server also
supports workspace diagnostics.  This ensures that opened buffers
see updated diagnostics (e.g. after a save triggers an external
tool like PHPStan) without requiring the user to re-enter insert
mode.
2026-07-08 07:26:22 -04:00