Commit Graph
41 Commits
Author SHA1 Message Date
Lewis Russell c171a697cb fix(lua): add missing param annotations (#41911) 2026-09-15 14:14:21 +01:00
Justin M. Keyes 9a29622b54 feat(multicursor): MC HAMMER #41587
Other (squashed) commits:

fix(tui): emit ui_send output atomically with the frame

Problem:
tui_ui_send() writes directly to the TTY, bypassing the output buffer.
Sequences sent via nvim_ui_send() (e.g. kitty multiple-cursors, or
visual-dot-repeat) always arrive in a separate TTY write from the frame
they were computed for. This manifests as "tearing", or e.g. in the case
of multicursor the terminal renders text with stale cursor overlays.

Solution:
- tui_ui_send(): while a frame is being assembled (pending invalid
  regions or buffered output), buffer instead of writing directly.
  - Out-of-frame sends (tty queries, clear-on-disable) still write
    immediately.
- mcursor.lua: emit the terminal-cursor update at the end of the redraw
  cycle (`on_end`, when screen positions are final) instead of
  vim.schedule().
2026-09-01 15:17:22 +00: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
Justin M. Keyes 726d1a92d2 feat(options): lua closure/function options
Problem:
Cannot assign Lua functions/closures to "func" ('completefunc',
'tagfun', …) or "expr" ('foldexpr', 'indentexpr', …) options.

Solution:
- Store "func"/"expr" options as `Callback` instead of string.
- Delete oceans of copy-pasted code.
- BREAKING: LuaRef returned via RPC/Vimscript is now represented as
  `"<Lua N: file:line>"` (like what `:map` shows) instead of `nil`.
- Note: `man.vim` still uses `v:lua` string, bc it's a vimscript ftplugin.

Helped-by: Lewis Russell <lewis6991@gmail.com>
2026-07-31 21:50:04 +02:00
Justin M. Keyes 359459dec6 refactor(exmode): Ex-mode as cmdwin + Lua #40991
Problem:
POSIX-compatible Ex-mode requires special-cases all over the codebase to
match various quirks that don't actually matter to users.
- The main utility of *interactive* Ex-mode is its REPL behavior, and
  that can be achieved with `cmdwin`, which also gains extra UX
  benefits.
- The main utility of *non-interactive* `nvim -es` is for shell
  scripting, where Ex-mode quirks are mostly unhelpful (e.g. the
  "Entering Ex mode" message).

Solution:
- Reimplement *interactive* Ex-mode as a "persistent, insert-mode
  cmdwin" in Lua.
  - "nvim -e/-E" is simply an alias to "gQ".
- Reframe *non-interactive* Ex-mode (`nvim -es`) as "script mode".
  - Drop POSIX Ex-mode quirks.

Improvements:
- "nvim -V1 -es" output ends with a final newline!
- "nvim -V1 -es" no longer shows the "Entering Ex mode" msg. (This was
  pointless noise, unwanted for scripting purposes.)
- stdin is no longer typeahead. Scripts (":lua io.read()") can read
  stdin as data.
- Empty line is a no-op: a stray blank line no longer moves the cursor
  (deviates from POSIX ex "+1"), no longer exits 1 at EOF (E501).

Preserved behavior:
- cursor starts at "$"
- mode()=="cv" (for non-interactive)
- multiline commands (:append/:function/heredoc pull continuation lines)
- bare-range print
- :print=>stdout
- -V1=>stderr
- CRLF input
- continue-after-error and exit codes

Dropped (regressed) POSIX behavior (non-interactive):
- Event loop only ticks while/between commands, not while blocked
  waiting for a stdin line.
- ":g/pat/visual...Q"
- input()/getchar()/":s/x/y/c" no longer consume stdin lines as
  answers: Nvim stops at end-of-input, skipping the rest of the script,
  exit 0. Use ":lua io.read()" instead.
  - If users care about this they should use interactive Ex-mode (`gQ`).
- ":@r" stops at end of the register instead of continuing to read
  cmdline input from stdin.
2026-07-27 06:25:21 -04:00
Justin M. Keyes 9982f6e0e4 refactor(api): omit optional param 2026-07-13 19:44:15 +02:00
Barrett Ruth 20a4b1bc5e fix(dir): user/plugin can override default "-" mapping #40676 2026-07-10 11:52:24 -04:00
Barrett Ruth 7325e3b55a fix(dir): define "-" (up/parent) mapping earlier #40531
Problem:
The dir.lua "-" mapping cannot be easily overridden (because of autocmd
ordering).

Solution:
- Move it to defaults.lua.
- Also to be extra polite: fall back to builtin `-` motion if the user
  disabled the `dir.lua` plugin.
2026-07-02 15:55:48 -04:00
Barrett Ruth 8bf7fc810a fix(tty): filter terminal probes by channel #40356
Problem:
Terminal probes sent with `nvim_ui_send()` can reach more than one stdout TTY
UI. Probes with a known TTY UI owner should not accept `TermResponse`s from
unrelated UI channels. 

Solution:
Thread the existing `chan` filter through owned terminal probes. This covers
startup/attach background detection, fallback truecolor detection, and
`vim.tty.query()` forwarding opts to `vim.tty.request()`.

Note: Not every terminal escape path is updated here. I only passed `chan` when
the caller already knows which TTY UI owns the probe. For example, this does
not include:
- (Followup) OSC 52 (system clipboard) detection. It needs to capture the
  `UIEnter` channel. Adding `{ chan = ... }` only to the nested query would be
  half a fix.
- OSC 52 _paste_ is left global because the provider callback does not have
  a UI channel (paste is invoked without a ui channel/tty ui object).
2026-06-24 10:40:36 -04:00
Barrett Ruth db30608058 fix(tui): attribute TermResponse to source channel #40330
Problem: Attach-time terminal probes cannot distinguish responses from
different attached UIs.

Solution: Identify the UI by RPC channel id in `TermResponse` and make
`vim.tty.request()` filter responses by channel.
2026-06-23 06:19:56 -04:00
Barrett Ruth 74f163c67d fix(defaults): detect 'background'/'termguicolors' on UI attach #40175
Problem:  Terminal background and truecolor detection runs only at startup,
          gated on a UI being attached. A headless server has no UI then, so
          `'background'` and `'termguicolors'` are never detected and remote
          UIs ignore the terminal's theme.
Solution: Also (re)detect on UIEnter. The most recently attached terminal
          wins; an explicit user value is preserved.
2026-06-20 20:09:34 -04:00
Justin M. Keyes 436761cba2 fix(tui): late-arriving OSC11 response triggers OptionSet #40270
Problem:
This test is flaky since fff9897ce3 :

    FAILED   ...Xtest_xdg_terminal/test/functional/terminal/tui_spec.lua @ 4359:
    TUI bg color does not trigger OptionSet from automatic background processing
    Expected values to be equal.
    Expected:
    { true, 0 }
    Actual:
    { true, 1 }
    stack traceback:
    ...Xtest_xdg_terminal/test/functional/terminal/tui_spec.lua:4380:
    in function <...Xtest_xdg_terminal/test/functional/terminal/tui_spec.lua:4359>

`apply_optionset_autocmd_now` does not emit `OptionSet` during startup:

    void apply_optionset_autocmd_now(...) {
      // Don't do this while starting up, failure or recursively.
      if (starting || errmsg != NULL || *get_vim_var_str(VV_OPTION_TYPE) != NUL) {
        return;
      }
      ...
    }

but if OSC 11 response arrives AFTER VimEnter, then
`nvim_set_option_value('background',…)` call triggers `OptionSet`.

Solution:
Use `:noautocmd` when setting 'background'.
Per fff9897ce3, OSC11 is not intended to trigger OptionSet.

fix https://github.com/neovim/neovim/issues/40235
2026-06-15 09:12:15 -04:00
Justin M. Keyes 9aa4608401 refactor: introduce nvim_on internally #39883
Problem:
`nvim_create_autocmd` is too verbose and its `callback` requires extra
"nesting".

Solution:
Introduce `nvim_on`. Start using it internally. Then we can get a feel
for how it should look before making it public.
2026-05-20 17:33:01 -04:00
Puneet Dixit fff9897ce3 fix(startup): emitting useless OptionSet #39830
Problem:
During startup, we manually trigger a useless and misleading `OptionSet`
event, which doesn't set `v:option_*` values (this is a limitation of
`nvim_exec_autocmds`).
https://github.com/neovim/neovim/blob/ad4bc2d90c5109c24bf6f0119ad31276f1518c6f/runtime/lua/vim/_core/defaults.lua#L939.

Solution:
The `nvim_exec_autocmds('OptionSet',…)` call does not serve any purpose
since 5cbb9d613b, so just drop it.
2026-05-17 12:18:24 -04:00
Nathan Zeng db7f818728 refactor(defaults): use public treesitter select()
Problem: Default mappings use the private module.

Solution: Use the public method.
2026-05-09 10:00:03 +02:00
Justin M. Keyes d9ed4c8566 refactor(tty): tty.request() #39489
Problem:
- Various `TermRequest` handlers which all do similar things.
- `tty.query` is specific to `XTGETTCAP DCS`, can't be reused for other kinds of terminal queries.

Solution:
Provide `tty.request()`.
2026-04-30 07:26:40 -04:00
Justin M. Keyes b70224e3bd docs: misc #39256 2026-04-25 11:16:18 -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
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 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
Justin M. Keyes 646ce85aa5 refactor: update usages of deprecated "buffer" param #39089 2026-04-15 18:45:26 +00:00
zeertzjq 9c5fba5df0 fix(messages): truncate warning messages only in display (#38901)
For now, add a private "_truncate" flag to nvim_echo, using a truncation
method similar to showmode().
2026-04-09 04:11:32 +00:00
Olivia Kinnear 13faa0ef84 feat(defaults): :Open without args opens current file #38776
Problem:
Running `:Open` on an open buffer does not run `vim.ui.open()` on that file, requiring the user to type `:Open %`. This is inconsistent with most other vim commands which accept files, which default to the current buffer's file.

Solution:
Default to the current file when `:Open` is used without arguments.
2026-04-05 19:46:45 -04:00
zeertzjq da58fe8fd2 fix(defaults): check for TUI on non-stdio channel on startup (#38581) 2026-03-31 11:17:33 +08:00
Justin M. Keyes 3a3c6f0907 refactor: rename termcap.lua -> tty.lua #38437
Problem:
The `termcap.lua` module is too narrowly named. We may need a place for
tty-related functionality in the future.
https://github.com/neovim/neovim/pull/31399#discussion_r1882598297

Solution:
This isn't a public/documented interface, so just rename it.
2026-03-23 10:14:48 -04:00
skewb1k 4d3a67cd62 feat(lua): replace buffer with buf in vim.keymap.set/del #38360
The `buffer` option remains functional but is now undocumented.
Providing both will raise an error. Since providing `buf` was disallowed
before, there is no code that will break due to using `buffer` alongside
`buf`.
2026-03-21 12:00:06 -04:00
Yi Ming 06befe1e34 feat(defaults): map "grx" to vim.lsp.codelens.run() #37689
Problem
Unlike inlay hints, code lenses are closely related to running commands;
a significant number of code lenses are used to execute a command (such
as running tests). Therefore, it is necessary to provide a default
mapping for them.

Solution
Add a new default mapping "grx" (mnemonic: "eXecute", like "gx").
2026-03-19 13:47:52 -04:00
286b78de9b docs: misc, terminal
Close #38319
Close #38348

Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Co-authored-by: Barrett Ruth <br.barrettruth@gmail.com>
2026-03-18 20:40:20 +01: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
Justin M. Keyes 017d8aa298 refactor: rename _ensure_integer => _assert_integer 2026-03-13 20:32:01 +01:00
Lewis Russell ce1154048b refactor: integer functions, optimize asserts #34112
refactor(lua): add integer coercion helpers

Add vim._tointeger() and vim._ensure_integer(), including optional base
support, and switch integer-only tonumber()/assert call sites in the Lua
runtime to use them.

This also cleans up related integer parsing in LSP, health, loader, URI,
tohtml, and Treesitter code.

supported by AI
2026-03-12 11:04:05 -04:00
Justin M. Keyes 7ea148a1dc docs: use "ev" convention in event-handlers
Problem:
In autocmd examples, using "args" as the event-object name is vague and
may be confused with a user-command.

Solution:
Use "ev" as the conventional event-object name.
2026-03-12 11:12:56 +01:00
32aee065a8 feat(startup): warn if NVIM_LOG_FILE is inaccessible #38070
Problem:
If NVIM_LOG_FILE, or the default fallback, is inaccessible (e.g.
directory is owned by root), users get confused.

Solution:
Show a warning when $NVIM_LOG_FILE or $XDG_STATE_HOME are inaccessible.

Also fix a latent memory leak: `os_mkdir_recurse` returns a uv error
code (int), but it was stored as `bool`, causing `os_strerror` to
receive an invalid error code and leak memory.

See: https://docs.libuv.org/en/v1.x/errors.html#c.uv_strerror

Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2026-03-12 04:40:07 -04:00
Justin M. Keyes b8a976afda docs: api, messages, lsp, trust
gen_vimdoc.lua: In prepare for the upcoming release, comment-out the
"Experimental" warning for prerelease features.
2026-03-11 18:00:18 +01:00
altermoandGyörgy Andorka 72d3a57f27 feat(treesitter): incremental selection
Co-authored-by: György Andorka <gyorgy.andorka@protonmail.com>
2026-03-08 11:07:49 +01:00
zeertzjq dea8430d59 test: suppress DSR wait warning when running tests (#38126)
Problem:
The DSR wait warning causes any test that involves Nvim TUI to become
flaky on Windows. Example:

FAILED   test/functional/terminal/cursor_spec.lua @ 367: :terminal cursor can be positioned arbitrarily
test/functional/terminal\cursor_spec.lua:377: Row 1 did not match.
Expected:
  |*^                                                  |
  |*~                                                 |
  |*~                                                 |
  |*~                                                 |
  |*~                                                 |
  |*                                                  |
  |{5:-- TERMINAL --}                                    |
Actual:
  |*                                                  |
  |*                                                  |
  |*{2:                                                  }|
  |*{103:defaults.lua: Did not detect DSR response from ter}|
  |*{103:minal. This results in a slower startup time.     }|
  |*{UNEXPECTED foreground = tonumber('0x000006'):Press ENTER or type command to continue^           }|
  |{5:-- TERMINAL --}                                    |

Solution:
Don't show the DSR wait warning when running tests.
2026-03-02 20:34:11 +08:00
Kyle 5cbb9d613b fix(startup): wait for bg detection before user config #37075
Problem:
Automatic background detection sets the background option too late,
which loads colorschemes twice and causes problems when the user's
terminal background doesn't match the default (#32109, #36211, #36416).

Solution:
Use a DA1 query to determine whether the TTY supports OSC 11. Wait for
background detection and setting to complete before processing user
config.

Note: To preserve the existing behavior as much as possible, this triggers
OptionSet manually on VimEnter (since it won't trigger automatically if
we set bg during startup). However, I'm unsure if this behavior is
truly desired given that the documentation says OptionSet is triggered
"After setting an option (except during |startup|)."

Also fixes flickering issue #28667. To check for flickering:

    nvim --clean --cmd "set termguicolors" --cmd "echo \"foo\"" --cmd "sleep 10"

On master, this gives me a black screen for 10 seconds, but on this
branch, the background is dark or light depending on the terminal
background (since the option is now set during startup rather than after
VimEnter).
2026-02-27 04:52:52 -05:00
Maria Solano 05bd4398c5 feat(lsp): support textDocument/documentLink (#37644) 2026-02-16 11:05:33 -08:00
Justin M. Keyes 20e77c5d88 build: ship "_core/*" as bytecode (built-into Nvim binary)
Problem:
We want to encourage implementing core features in Lua instead of C, but
it's clumsy because:
- Core Lua code (built into `nvim` so it is available even if VIMRUNTIME
  is missing/invalid) requires manually updating CMakeLists.txt, or
  stuffing it into `_editor.lua`.
- Core Lua modules are not organized similar to C modules, `_editor.lua`
  is getting too big.

Solution:
- Introduce `_core/` where core Lua code can live. All Lua modules added
  there will automatically be included as bytecode in the `nvim` binary.
- Move these core modules into `_core/*`:
  ```
  _defaults.lua
  _editor.lua
  _options.lua
  _system.lua
  shared.lua
  ```

TODO:
- Move `_extui/ => _core/ui2/`
2025-12-30 01:44:24 -05:00