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
Problem:
By default, `nvim` does not survive if its host terminal dies. This is
inconvenient if you want to use Nvim as a "session manager" (like tmux).
Solution:
Let users opt-in to the "survive" behavior via `:detach!` (bang "!").
This marks the current UI as "detachable", so the server will not
self-exit if the UI channel closes.
Problem: Traditionally, the ruler in the last line is one cell shorter
than in the statusline, leaving the last cell of the screen blank.
According to code comments, this is in order to prevent unwanted
scrolling on "some" (unspecified, but presumably ancient) terminals.
Berkeley vi is more specific in its `vs_modeline` function: dumb
terminals with hardware scroll, SunOS 4.1.1 and Ultrix 4.2 curses.
(n)curses still has a similar limitation in `(w)addstr`, but apparently
only for historical reasons.
Maintaining the different widths leads to awkward inconsistencies when
the ruler is configured with 'rulerformat', except for the special case
where it contains a top-level `%=`. Shifting the ruler in the last line
to the left would be a solution, but the empty cell at the end doesn't
seem to be relevant anymore.
Solution: extend the ruler in the last line all the way to the right
edge of the screen, just like in the statusline. The exact same amount
of place will be available to the rest of the UI as before.
BREAKING CHANGE:
- the default ruler width is now 18 cells
- the last cell of the screen is no longer empty
Closes#41076
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.
Problem:
The magic globals `it`, `describe`, etc., are more trouble than they are
worth.
- Hooking into `after_each` requires `getfenv()` hacks.
- They confuse luals/emmylua, because the top-level `.luarc.json` isn't
merged with `test/.luarc.json` (apparently a luals limitation?)
- They totally defeat discoverability because the user just has to
"know" about the various magic symbols.
So they harm DX, which means they serve no purpose at all.
Solution:
- Expose the test API from `testutil`, so tests can call `t.it()`,
`t.describe()`, etc., in the conventional way.
- Drop `getfenv()` hacks.
- Drop the `setfenv()` injection in `load_chunk`.
- Drop `test/_meta.lua`.
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>
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.
Problem:
Session files specified at startup `-S [file]`, logically conflict
with `:restart`.
Solution:
Remove `-S [file]` from `v:argv` when doing :restart.
Also for the "bang" variant `:restart!`, just because it's
simpler (if anyone reports a use-case later, we can revisit).
Problem:
`:restart` does not preserve window layout, etc.
Solution:
- Change `:restart` to save/restore a session automatically.
- Introduce "bang" variant `:restart!` to restart *without* session
save/restore.
- Introduce `v:startreason`.
- `ZR` maps to `:restart!`.
Problem:
On Windows, channel jobs inherit Nvim's stdio, so a background job
writing to CON (e.g. gutentags) draws onto the TUI and stays until
redraw.
Solution:
Give Windows job stdin/stderr libuv-created pipes (UV_CREATE_PIPE)
instead of inherited fds, so libuv spawns the child with
CREATE_NO_WINDOW and CON writes no longer leak onto the TUI.
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.
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.
This was initially added so that the __NVIM_DETACH environment variable
can be added to the jobs started in this test. That environment variable
is no longer needed, and there is also vim.tbl_extend() that can be used
to add an environment variable to a job anyway.
Also, make a shallow copy of opts.env in setup_child_nvim(), as mutating
the opts.env passed in may mask problems in other tests.
Problem: when the TUI output buffer is filled during a redraw, flushing
it to the terminal also causes `CSI ? 2026 l` to be emitted, which ends
synchronized output. This causes visible flickering with large redraws.
Solution: track whether a synchronized output is currently active, and
only emit the end sequence on the final flush.
Problem:
- Windows users can't use terminfo to configure their terminal
capabilities. #37274
- Terminfo definitions sometimes get out of date or are simply
inaccurate.
- Eventually, we may want to drop terminfo, relying primarily on
built-in definitions. Users will still need some flexibility.
Solution:
Support $NVIM_TERMDEFS environment variable, which is JSON data that
defines "terminfo" definitions that override our builtin terminfo.
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`).
ad4bc2d90c/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.
Problem:
The Lua test harness still ran through standalone -ll mode, so tests
depended on the low-level Lua path instead of the regular Nvim Lua
environment. That also meant os.exit() coverage had to carry an ASAN
workaround because Lua's raw process exit skipped Nvim teardown and let
LeakSanitizer interfere with the observed exit code.
Solution:
Run the harness and related fixtures with nvim -l. Patch os.exit() in
the main Lua state to exit through getout(), so scripts observe normal
Nvim shutdown while standalone -ll remains available for generator-style
scripts. As a consequence, the startup test can assert os.exit() without
disabling leak detection.
AI-assisted: Codex
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.
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`
RUN T339 TUI :restart ZR: Uncaught Error: test/client/uv_stream.lua:111: ECONNRESET
stack traceback:
[C]: in function 'error'
test/client/uv_stream.lua:111: in function <test/client/uv_stream.lua:109>
[C]: in function 'run'
test/client/session.lua:240: in function '_run'
test/client/session.lua:216: in function '_blocking_request'
test/client/session.lua:117: in function 'request'
...t_xdg_terminal/test/functional/terminal/tui_spec.lua:223: in function <...t_xdg_terminal/test/functional/terminal/tui_spec.lua:215>
[C]: in function 'pcall'
test/testutil.lua:82: in function 'retry'
...t_xdg_terminal/test/functional/terminal/tui_spec.lua:215: in function 'assert_restarted'
...t_xdg_terminal/test/functional/terminal/tui_spec.lua:275: in function <...t_xdg_terminal/test/functional/terminal/tui_spec.lua:232>
[C]: in function 'xpcall'
/home/runner/work/neovim/neovim/test/harness.lua:693: in function 'run_callable'
/home/runner/work/neovim/neovim/test/harness.lua:1008: in function 'run_test'
/home/runner/work/neovim/neovim/test/harness.lua:1083: in function 'run_suite'
/home/runner/work/neovim/neovim/test/harness.lua:1081: in function 'run_suite'
/home/runner/work/neovim/neovim/test/harness.lua:1081: in function 'run_suite'
/home/runner/work/neovim/neovim/test/harness.lua:1507: in function 'run_test_file'
/home/runner/work/neovim/neovim/test/harness.lua:1577: in function 'run_iteration'
/home/runner/work/neovim/neovim/test/harness.lua:1665: in function 'main'
/home/runner/work/neovim/neovim/test/runner.lua:30: in main chunk
-- Tests exited non-zero: 255
CMake Error at /home/runner/work/neovim/neovim/cmake/RunTests.cmake:135 (message):
functional tests failed with error: 255
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.
Problem:
failures in s390x CI.
Solution:
- runtime/lua/man.lua: parse_path() can return nil but 3 callers didn't handle it.
- skip some tests on s390x.
TODO:
- TODO: why "build/bin/xxd is not executable" on s390x?
- TODO: other failures, not addressed (see below).
OTHER FAILURES:
FAILED test/functional/treesitter/fold_spec.lua @ 87: treesitter foldexpr recomputes fold levels after lines are added/removed
test/functional/treesitter/fold_spec.lua:95: Expected objects to be the same.
Passed in:
(table: 0x4013c18940) {
[1] = '0'
[2] = '0'
[3] = '0'
*[4] = '0'
[5] = '0'
...
Expected:
(table: 0x4005acf900) {
[1] = '0'
[2] = '0'
[3] = '>1'
*[4] = '1'
[5] = '1'
...
stack traceback:
(tail call): ?
test/functional/treesitter/fold_spec.lua:95: in function <test/functional/treesitter/fold_spec.lua:87>
FAILED test/functional/treesitter/select_spec.lua @ 52: treesitter incremental-selection works
test/functional/treesitter/select_spec.lua:63: Expected objects to be the same.
Passed in:
(string) 'bar(2)'
Expected:
(string) 'foo(1)'
stack traceback:
(tail call): ?
test/functional/treesitter/select_spec.lua:63: in function <test/functional/treesitter/select_spec.lua:52>
FAILED test/functional/treesitter/select_spec.lua @ 69: treesitter incremental-selection repeat
test/functional/treesitter/select_spec.lua:82: Expected objects to be the same.
Passed in:
(string) '2'
Expected:
(string) '4'
stack traceback:
(tail call): ?
test/functional/treesitter/select_spec.lua:82: in function <test/functional/treesitter/select_spec.lua:69>
FAILED test/functional/treesitter/select_spec.lua @ 98: treesitter incremental-selection history
test/functional/treesitter/select_spec.lua:111: Expected objects to be the same.
Passed in:
(string) 'bar(2)'
Expected:
(string) 'foo(1)'
stack traceback:
(tail call): ?
test/functional/treesitter/select_spec.lua:111: in function <test/functional/treesitter/select_spec.lua:98>
FAILED test/functional/treesitter/select_spec.lua @ 186: treesitter incremental-selection with injections works
test/functional/treesitter/select_spec.lua:201: Expected objects to be the same.
Passed in:
(string) 'lua'
Expected:
(string) 'foo'
stack traceback:
(tail call): ?
test/functional/treesitter/select_spec.lua:201: in function <test/functional/treesitter/select_spec.lua:186>
FAILED test/functional/treesitter/select_spec.lua @ 216: treesitter incremental-selection with injections ignores overlapping nodes
test/functional/treesitter/select_spec.lua:231: Expected objects to be the same.
Passed in:
(string) ' )'
Expected:
(string) ' foo('
stack traceback:
(tail call): ?
test/functional/treesitter/select_spec.lua:231: in function <test/functional/treesitter/select_spec.lua:216>
FAILED test/functional/treesitter/select_spec.lua @ 307: treesitter incremental-selection with injections handles disjointed trees
test/functional/treesitter/select_spec.lua:337: Expected objects to be the same.
Passed in:
(string) 'int'
Expected:
(string) '1}'
stack traceback:
(tail call): ?
test/functional/treesitter/select_spec.lua:337: in function <test/functional/treesitter/select_spec.lua:307>
ERROR test/functional/treesitter/parser_spec.lua @ 562: treesitter parser API can run async parses with string parsers
test/functional/treesitter/parser_spec.lua:565: attempt to index a nil value
stack traceback:
test/functional/testnvim/exec_lua.lua:124: in function <test/functional/testnvim/exec_lua.lua:105>
(tail call): ?
(tail call): ?
test/functional/treesitter/parser_spec.lua:563: in function <test/functional/treesitter/parser_spec.lua:562>
FAILED test/functional/core/job_spec.lua @ 1157: jobs jobstop() kills entire process tree #6530
test/functional/core/job_spec.lua:1244: retry() attempts: 94
test/functional/core/job_spec.lua:1246: Expected objects to be the same.
Passed in:
(table: 0x401dd74b30) {
[name] = 'sleep <defunct>'
[pid] = 33579
[ppid] = 1 }
Expected:
(userdata) 'vim.NIL'
stack traceback:
test/testutil.lua:89: in function 'retry'
test/functional/core/job_spec.lua:1244: in function <test/functional/core/job_spec.lua:1157>
Problem:
The "restart" event has some problems:
- all UI clients must implement a somewhat complex set of setups
- UI must be on the same machine as the server
- only works for the "current" UI
- race/edge case: If the user config has errors / waiting for input, are
all UIs able to attach while Nvim is waiting for input?
Solution:
- Perform the restart on the server, not the client.
- Pass listen address (instead of CLI args) in the UI event.
- Simplifies UI logic: they only need to attach to new address.
- Opens the door for more enhancements in the future, such as allowing
all UIs to reattach instead of only the "current" UI.
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
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.
Problem:
When a terminal process exits, "[Process Exited]" text is added
to the buffer contents.
Solution:
- Return `exitcode` field from `nvim_get_chan_info`.
- Show it in the default 'statusline'.
- Show exitcode as virtual text in the terminal buffer.