Commit Graph

4489 Commits

Author SHA1 Message Date
Evgeni Chasnovski
e45cdbc7c4 fix(util): add and use forge link computation
Problem: There are many Git forges each with a different way of
  constructing permanent links to like commits and tags.

Solution: Add a private utility function that computes these special
  links on the best effort basis.
2026-04-25 20:29:19 +03:00
Evgeni Chasnovski
d01dc690e1 feat(pack): support textDocument/documentLink in confirmation buffer
Problem: In `vim.pack.update()` confirmation buffer it might be useful
  to be able to use `gx` (open link at cursor) when cursor is on
  something like commit or tag.

Solution: Add `textDocument/documentLink` method support for the
  in-process LSP. This may be used by LSP clients and makes `gx`
  automatically work.

  The shortcoming is that this requires tracking how to construct a URL
  from source and commit/tag. Currently only GitHub hosted repositories
  are supported.
2026-04-25 20:28:43 +03:00
Tristan Knight
f83d0b9653 fix(lsp): handle self-mapped methods in supports_method #39383
Problem:
The LSP client incorrectly checks for server capabilities when determining
support for self-mapped methods (e.g., 'shutdown'), which do not have
corresponding capabilities in the server's response. This leads to false
negatives when checking if such methods are supported.
This was handled correctly for dynamic registrations, but not for static.

Methods such as 'shutdown', do not have a related server capability and should
be assumed to be supported.

Solution:
Update the `supports_method` logic to always return true for self-mapped
methods.
2026-04-24 18:48:23 -04:00
Kyle
66149ca668 feat(tui): restore 'ttyfast' to control tty requests #38699
Problem:
When running nvim on a remote machine over SSH, if there is high ping,
then bg detection may not complete in time. This results in a warning
every time nvim is started. #38648

Solution:
Restore 'ttyfast' option and allow it to control whether or not bg
detection is performed. Because this is during startup and before any
user config or commands, we use the environment variable
`NVIM_NOTTYFAST` to allow disabling `ttyfast` during initialization.
2026-04-24 14:45:20 -04:00
Peter Cardenas
27191e0f4f feat(api): nvim_echo(percent=nil) means "unknown" progress #39029
Problem:
No way to signal "unknown" or "indeterminate" progress percentage.

Solution:
Treat percent=nil as "indeterminate" percent.
2026-04-24 11:57:35 -04:00
Justin M. Keyes
2c7679f4d3 fix(lsp): more info in error msg, deduplicate test #39359 2026-04-24 07:40:33 -04:00
Justin M. Keyes
5c88492a13 fix(trust): always use "/" slashes in filepaths #39355
Problem:
We should not use "\" (backslashes) except where absolutely required.
See references in https://github.com/neovim/neovim/pull/37729

Solution:
There is no reason to use "\" slashes in the trust db, so don't.
2026-04-24 07:37:21 -04:00
zeertzjq
c0e358f7e8 vim-patch:9.2.0390: filetype: some Beancount files are not recognized (#39360)
Problem:  filetype: some Beancount files are not recognized
Solution: Detect *.bean files as beancount filetype
          (Bruno Belanyi)

closes: vim/vim#20037

521eac1877

Co-authored-by: Bruno Belanyi <bruno@belanyi.fr>
2026-04-24 07:50:31 +08:00
Olivia Kinnear
645a588aa6 feat(excmd): add :uptime command #39331
Problem
Nvim marks its v:starttime, but there is no user-friendly way to get Nvim's uptime.

Solution
Add :uptime (based loosely on uptime(1)).
2026-04-23 17:11:59 -04:00
atusy
46b6859a4f fix(lsp): handle null id in JSON-RPC responses #38340
Problem:
LSP spec allows response message to have a null request-id.
This may happen when for example client sends unparseable request.
https://github.com/microsoft/language-server-protocol/issues/196

Solution:
Guard the server response branches against id=vim.NIL (json null),
and handle error responses with null id by logging a warning
and dispatching on error.

Problem:
CI (ubuntu asan, ubuntu tsan, windows) reports `uv_loop_close()
hang?` from the two new null-id response tests. The leaked
handle is the server-side accepted TCP socket created inside
`server:listen` callback. The tests closed only the listener
but not the accepted socket, so libuv could not finish shutting
down the loop and each test session took ~2s extra to exit.

Solution:
Hoist the accepted socket to the outer `exec_lua` scope and
close it at teardown before closing the listener. The close
runs synchronously inside `exec_lua`, so the loop has time to
dispose the handle before the session exits.

* test(lsp): close accepted socket on read-loop exit/error

Match the precedent in the handler test ("handler can return
false as response") and the shared `_create_tcp_server` helper
in `test/functional/plugin/lsp/testutil.lua`: close the
accepted socket from inside the `create_read_loop` exit/error
callbacks. The teardown close added in the previous commit
remains as belt-and-suspenders, so the socket is disposed
whether the server goes away first or the client does.
2026-04-23 16:41:59 -04:00
Barrett Ruth
0a8218a2b4 fix(trust): hash unchanged empty buffers as empty files #39027
Problem:
`vim.secure.trust()` hashes an unchanged empty buffer as
a newline, so trusting an empty file by buffer never works.

Solution:
Hash unchanged empty-buffers `''` so buffer-based
trust matches the on-disk empty file.
2026-04-23 15:01:37 -04:00
geril07
790a8be5f3 fix(lsp): malformed edit if apply_text_edits() is called twice #34954
Problem:
Use vim.lsp.util.apply_text_edits to re-apply the same textedit causes
an incorrect edit, because apply_text_edits silently modifies the
parameter.

Solution:
- Avoid changing `text_edit._index`.
- Document this fun feature.

Helped-by: Riley Bruins <ribru17@hotmail.com>
Helped-by: Yi Ming <ofseed@foxmail.com>
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2026-04-23 16:01:44 +00:00
Evgeni Chasnovski
f8c94bb8cf fix(pack): only use tags that strictly comply with semver spec #39342
Problem: Using `version=vim.version.range(...)` in plugin specification
  is meant to use semver-like tags. Whether a tag is semver-like was
  decided by a plain `vim.version.parse` which is not strict by default.
  This allowed treating tags like `nvim-0.6` (which is usually reserved
  for the latest revision compatible with Nvim<=0.6 version) like semver
  tags and resulted in confusing behavior (preferring `nvim-0.6` tag
  over `v0.2.2`, for example).

Solution: Use `vim.version.range(x, { strict = true })` to decide if the
  tag name is semver-like or not. This allows tags like both `v1.2.3`
  and `1.2.3` while being consistent in what Nvim thinks is a semver
  string.

  This is technically not a breaking change since it was documented that
  only tags like `v<major>.<minor>.<patch>` will be recognized as
  semver.
2026-04-23 11:14:06 -04:00
Ashley Hauck
7e006b06c4 fix(lsp): callHierarchy/outgoingCalls ranges are relative to caller, not callee #39336
Problem:
The fromRanges field of the result of callHierarchy/outgoingCalls is
documented as being relative to the caller. Using
vim.lsp.buf.outgoing_calls() opened the qflist with an entry with the
callee's filename, but the caller's line number.

Solution:
Open the qflist with the callers file (the bufnr from the request),
rather than the callees (the uri from the resulting CallHierarchyItem)
2026-04-23 08:20:58 -04:00
Barrett Ruth
ecb8402197 fix(lsp): filter code_action diagnostics to the cursor #38988
Problem:
Cursor-position `vim.lsp.buf.code_action()` requests include all diagnostics on the current line, so unrelated same-line diagnostics affect the returned actions.

Solution:
Filter same-line diagnostics to the cursor position for cursor-position requests.
2026-04-23 06:46:59 -04:00
altermo
451811b1be feat(treesitter): expand selection to sibling node #38938
Problem:
Can't expand treesitter-incremental-selection to the next and previous
sibling nodes.

Solution:
Pressing `]N` in visual mode will expand the selection to the next
sibling node, and `[N` will do the same with the previous node.
2026-04-22 17:10:24 -04:00
Justin M. Keyes
28ba068372 feat(:restart): v:starttime, v:exitreason #39282
Problem:
- The `ZR` feature makes it more obvious that we need some sort of flag so that
  an `ExitPre` / `QuitPre` / `VimLeave` handler can handle restarts differently
  than a normal exit. For example, it's common that users want `:mksession` on
  restart, but perhaps not on a normal exit.
- Nvim has no way to report its "uptime".

Solution:
- Introduce `v:starttime`
- Introduce `v:exitreason`
2026-04-22 13:40:41 -04:00
Yi Ming
558204d87b perf(lsp): clear table by table.clear() #39222
benchmark: https://gist.github.com/ofseed/6224529d77c016c36f7ab2f977059848

    local rounds = tonumber(arg[1]) or 1000
    local count = tonumber(arg[2]) or 1000

    -- Load the table.clear function.
    local clear = require("table.clear")

    local function fill(t, n)
      for i = 1, n do
        t[i] = i
      end
    end

    local function bench_reassign(n_rounds, n_items)
      local t = {}
      local start = os.clock()

      for _ = 1, n_rounds do
        t = {}
        collectgarbage("collect")
        fill(t, n_items)
      end

      return os.clock() - start
    end

    local function bench_reassign_no_gc(n_rounds, n_items)
      local t = {}
      local start = os.clock()

      for _ = 1, n_rounds do
        t = {}
        fill(t, n_items)
      end

      return os.clock() - start
    end

    local function bench_clear(n_rounds, n_items)
      local t = {}
      local start = os.clock()

      for _ = 1, n_rounds do
        clear(t)
        fill(t, n_items)
      end

      return os.clock() - start
    end

    -- Warm up LuaJIT before the real benchmark.
    do
      local t = {}
      for _ = 1, 2000 do
        clear(t)
        fill(t, count)
      end
    end

    collectgarbage("collect")

    local reassign_time = bench_reassign(rounds, count)
    collectgarbage("collect")

    local reassign_no_gc_time = bench_reassign_no_gc(rounds, count)
    collectgarbage("collect")

    local clear_time = bench_clear(rounds, count)

    print(string.format("rounds=%d count=%d", rounds, count))
    print(string.format("t = {} + GC   : %.6f s", reassign_time))
    print(string.format("t = {}        : %.6f s", reassign_no_gc_time))
    print(string.format("table.clear   : %.6f s", clear_time))
    print(string.format("vs + GC       : %.2fx", reassign_time / clear_time))
    print(string.format("vs no GC      : %.2fx", reassign_no_gc_time / clear_time))

benchmark result:

    rounds=1000 count=1000
    t = {} + GC   : 0.022469 s
    t = {}        : 0.002570 s
    table.clear   : 0.000387 s
    vs + GC       : 58.06x
    vs no GC      : 6.64x

`count` is how many items the table has, and `round` is how many rounds we fill
the table, clear, and then refill it. `table = {}` is clear the table by
resigning a new empty one, because this script does not run persistently like
nvim so GC is not triggered, so I added another extreme control group that
manually triggers GC.
2026-04-22 11:38:58 -04:00
Nick Krichevsky
e68e769352 fix(options): default 'titlestring' shows CWD #39233
Problem:
In the default 'titlestring', if the containing directory is the CWD, it renders as "."

Solution:
Add `:p` to the titlestring.
2026-04-22 05:56:23 -04:00
fleesk
e53e728c92 fix(pack): GIT_DIR/GIT_WORK_TREE env vars may interfere #39279
Problem:
With GIT_DIR/GIT_WORK_TREE set, the LSP on the vim.pack.update()
confirmation buffer does not show the correct git log on hover.

Solution:
Temporarily remove the git vars from the environment.
2026-04-22 04:46:48 -04:00
zeertzjq
8f1e14ffa2 vim-patch:9.2.0356: Cannot apply 'scrolloff' context lines at end of file
Problem:  Cannot apply 'scrolloff' context lines at end of file
Solution: Add the 'scrolloffpad' option to keep 'scrolloff' context even
          when at the end of the file (McAuley Penney).

closes: vim/vim#19040

a414630393

Co-authored-by: McAuley Penney <jacobmpenney@gmail.com>
2026-04-22 10:14:52 +08:00
zeertzjq
208951cbc0 fix(:restart): avoid ERR/WRN logging on Windows with --listen (#39287)
Problem:  :restart leads to ERR/WRN logging on Windows with --listen.
Solution: Add a log_level flag to vim._with() and use it to suppress
          logging from serverstart()/serverstop() during restart.
2026-04-22 08:12:55 +08:00
Sanzhar Kuandyk
5891f2f3dc fix(:restart): reuse --listen addr on Windows #38539
Problem:
On Windows, :restart cannot immediately reuse the canonical --listen
address because named pipe release is asynchronous.

Solution:
Start the new Nvim server on a temporary address; in the new Nvim,
retry serverstart() with the original ("canonical") address until it
succeeds.
2026-04-21 12:49:16 -04:00
Justin M. Keyes
a1c8b81672 feat(normal): normal-mode ZR does :restart
Make it a normal-mode command instead of a default mapping.
2026-04-21 15:54:08 +02:00
Mike J. McGuirk
2551c7a8b1 feat(defaults): map ZR to restart
Problem: No default mapping for :restart.

Solution: Map to ZR in defaults.

Closes: https://github.com/neovim/neovim/issues/38942
2026-04-21 15:54:08 +02:00
zeertzjq
32e249dfa6 vim-patch:9.2.0371: filetype: ghostty config files are not recognized (#39267)
Problem:  filetype: ghostty config files are not recognized
Solution: Detect ghostty configuration files as ghostty filetype,
          include a simple ghostty filetype plugin (Bez Hermoso)

closes: vim/vim#20002

b30803b231

Co-authored-by: Bez Hermoso <bezalelhermoso@gmail.com>
Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-04-21 02:24:07 +00:00
luukvbaal
faa7c15b5a fix(ui2): don't dismiss expanded messages for non-typed key #39247
Problem:  Invalid check for non-typed key to dismiss expanded cmdline.
          Unable to delay the timer that removes a message from the msg
          window.
Solution: Check for empty string instead of nil to determine whether a
          key is typed.
          Restart the timer if it expires while the user is in the msg
          window. Allow entering the msg window with a mouse click.
2026-04-20 11:38:47 -04:00
Luuk van Baal
607fcfb37a fix(ui2): ensure msg window is visible after closing tab
Problem:  After closing a tabpage while the msg window is showing a
          message, it is hidden while the msg window still contains a
          message.
Solution: Unhide the msg window after entering a tabpage and it still
          contains a message.

Co-authored-by: Linykq <yukunlin590@gmail.com>
2026-04-20 14:20:20 +02:00
Justin M. Keyes
2b52acfb8a docs: misc #39207 2026-04-20 07:09:37 -04:00
glepnir
01861c2f95 fix(api): expose fg_indexed/bg_indexed in nvim_get_hl #39210
Problem: fg_indexed/bg_indexed were dropped from nvim_get_hl output due
to a wrong short_keys guard. HL_FG_INDEXED also wasn't cleared in
hl_blend_attrs, and HLATTRS_DICT_SIZE was too small.

Solution: Remove the short_keys guard, clear HL_FG_INDEXED in
hl_blend_attrs, bump HLATTRS_DICT_SIZE to 24, and clarify docs that
these flags mean rgb is an approximation of the cterm palette index.
2026-04-20 05:12:52 -04:00
Justin M. Keyes
c7d4892ce6 Merge #39194 from justinmk/luavimfn 2026-04-20 04:23:54 -04:00
luukvbaal
fe986e5dd0 feat(options): add 'winpinned' to pin a window #39157
Problem:
- Unable to "pin" a window to prevent closing without specifically
  being targeted.
- :fclose closes hidden windows (even before visible windows).

Solution:
- Add 'winpinned' window-local option. When set, window is skipped by
  :fclose and :only. Pin the ui2 cmdline window (which should always be
  visible), so that it is not closed by :only/fclose.
- Skip over hidden (and pinned) windows with :fclose.

Co-authored-by: glepnir <glephunter@gmail.com>
2026-04-19 20:36:55 -04:00
Justin M. Keyes
ea45e6f6ba fix(health): workaround nil vim.system():wait() result
Workaround until https://github.com/neovim/neovim/issues/37922 is fixed.
2026-04-20 02:31:09 +02:00
Justin M. Keyes
919a109951 refactor(excmd): migrate ex_terminal to Lua 2026-04-20 02:31:09 +02:00
Justin M. Keyes
fe7218528d refactor(excmd): migrate ex_checkhealth to Lua 2026-04-20 02:12:05 +02:00
Maria Solano
5f6abd34f5 fix(lsp): notify when maximum created hl groups is reached #39231 2026-04-19 19:05:51 -04:00
Maria Solano
e8b3968774 docs(lsp): description for on_list example #39230 2026-04-19 18:30:45 -04:00
Olivia Kinnear
c6209e5542 feat(excmd): add EXX error codes for :lsp, :log #39135
Also remove the `--add-comments` flag from `xgettext` because
it dumped a bunch of comments from Lua files into the `.pot` files.
2026-04-19 10:40:49 -04:00
Jaehwang Jung
88dd492996 fix(lsp): stale codelens after external file change (#39203)
Problem:
Codelens virtual lines remain on stale rows after an external file
change and buffer reload.

Solution:
Clear codelens extmarks and cached row/version state in `on_reload`
before requesting fresh code lenses.
2026-04-18 18:27:02 -07:00
glepnir
b351afb1b1 fix(lsp): show CompletionItem.detail in info popup #38904
Problem: completionItem/resolve response's `detail` field is silently
dropped. Only `documentation` is shown in the popup.

Solution: Prepend `detail` as a fenced code block before `documentation`
in the info popup, skipping if documentation already contains it.
2026-04-18 15:43:20 -04:00
Justin M. Keyes
54398c5874 docs: misc #39045 2026-04-18 15:38:59 -04:00
Jaehwang Jung
97caa88972 fix(lsp): skip codelens refresh redraw for deleted buffer #39193
Problem:
After on_refresh() sends a textDocument/codeLens request, the buffer may
be deleted before the response arrives. The response callback then tries
to redraw that deleted buffer and raises Invalid buffer id error.

Solution:
Check buffer validity before redrawing.

AI-assisted: Codex
Co-authored-by: Yi Ming <ofseed@foxmail.com>
2026-04-18 15:38:09 -04:00
Aditya Malik
2cb240319b docs(events): Lua types for autocmd event-data #38518
Problem:
  No LuaLS types for event-data fields (ev.data). Types are only
  documented ad hoc in scattered locations.

Solution:
  Add runtime/lua/vim/_meta/events.lua defining vim.event.<name>.data
  classes for events that provide ev.data. Reference the types from
  each event's help in autocmd.txt, lsp.txt, and pack.txt.
2026-04-18 13:17:45 -04:00
Evgeni Chasnovski
3a4cc5db0b fix(lua): make vim._with() work with buf=0 and win=0 context #39151
Problem: Using `buf=0`/`win=0` context in `vim._with` should be
  equivalent to using explicit buffer/window identifier respectively.

Solution: Explicitly adjust context in case of `buf=0` or `win=0`.
2026-04-18 12:04:28 -04:00
Justin M. Keyes
6701b45331 refactor(vimfn): full-Lua impl of vim.fn.environ() 2026-04-18 16:57:37 +02:00
Justin M. Keyes
3ebfa2a3cb feat(vimfn): use Lua for more excmds/vimfns
Problem:
Too much boilerplate needed to use Lua to impl an excmd or f_xx
function.

Solution:
- Add `nlua_call_vimfn` which takes the args typval, executes
  Lua, and returns a typval.
- refactor(excmd): lua impl for :log, :lsp
2026-04-18 16:57:37 +02:00
Evgeni Chasnovski
6b9b4a1377 fix(vim.filetype): match() fails if g:ft_ignore_pat is not defined #39158
Problem: Calling `vim.filetype.match({ filename = '...', buf = ... })`
  during startup results in an error due to not yet defined
  `g:ft_ignore_pat`.

Solution: Add a guard to check `g:ft_ignore_pat` related properties only
  if the variable is defined. This also allows to simplify other tests
  which did not depend on `g:ft_ignore_pat` but required it explicitly
  set to work.
2026-04-18 06:50:28 -04:00
Evgeni Chasnovski
7219b816ea fix(lsp): limit number of created highlight groups (#39133)
* fix(api): allow silencing "Too many highlight groups" error

Problem: Using Lua's `vim.api.nvim_set_hl(0, 'New', {...})` can fail if
  there are too many existing highlight groups. However, this error can
  not be silenced with `pcall`.

Solution: Make it possible to silence in `nvim_set_hl` and
  `nvim_get_hl_id_by_name`.

* fix(lsp): limit number of groups created by `document_color()`

Problem: A file can contain many string colors that would be highlighted
  by an LSP server. If this number crosses 19999 (maximum number of
  allowed highlight groups), there are general issues with creating
  other highlight groups, which can break functionality outside of
  `vim.lsp.document_color`.

Solution: Limit number of highlight groups that are created by
  `vim.lsp.document_color` to 10000 (half of allowed maximum).
  This is not a 100% solution (since there can exist more than 10000
  other highlight groups), but explicitly checking number of groups is
  slow and 10000 should (hopefully) be enough for most use cases.
2026-04-17 17:16:11 -07:00
Justin M. Keyes
0d4d285bd2 perf(vim.fn): call Lua-implemented vim.fn.xx() directly #39166
Problem:
- Builtin "Vimscript" functions (f_xx) are mostly implemented in C.
  Partly that's because there is some boilerplate required to call out
  to Lua.
- Calls to `vim.fn.foo()` always marshall over the Lua <=> Vimscript
  ("typval") bridge, even if `fn.foo()` is implemented entirely in Lua:
  ```
  Lua => typval => Object => Lua => Object => typval => Lua.
  ```

Solution:
Functions declared in eval.lua with `func_lua` are implemented in
entirely in Lua (`_core/vimfn.lua`).

- `gen_eval.lua` wires `func_lua` entries to `lua_wrapper`, which handles
  the typval conversion for Vimscript callers (slow path).
- `nlua_call()` detects `func_lua` functions and calls the Lua
  implementation directly. This eliminates all conversion overhead for
  Lua callers (fast path).
- Validate at build-time that `func`, `func_float`, and `func_lua` are
  mutually exclusive.
- Migrate `hostname()` as a toy example, to show the idea.
2026-04-17 19:10:20 -04:00
zeertzjq
39410ef42b vim-patch:8.2.2440: documentation based on patches is outdated (#39144)
Problem:    Documentation based on patches is outdated.
Solution:   Add changes to documentation in a patch.

853886722c

Trailing space was removed in later patches.
Also fix a few more misplaced error numbers from #8155.

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2026-04-17 09:50:03 +08:00