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.
This reverts commit ab8371a26c.
Need to think of a different solution, which may require adding new
flags to nvim_ui_attach() (e.g. passing stdout or stderr fd).
Problem: If Nvim server fails to --listen and prints error before the
TUI enters alternate screen, the error isn't visible.
Solution: Forward server stderr using client side stderr handler instead
of having the server inherit client stderr file descriptor.
This does mean that `stderr_isatty` will be `false` in the server, but
that value doesn't matter in embedded mode.
Always pass `stdin_fd` to embedded server to avoid a hang when reading
from stdin when it's a TTY (not sure why one wants to do that, perhaps
by mistake), because if `stdin_fd` isn't passed, the server will try to
use stderr as stdin.
Example test failure on CI:
FAILED test/functional/terminal/tui_spec.lua @ 41: TUI exit status 1 and error message with server --listen error #34365
test/functional/terminal\tui_spec.lua:55: Failed to match any screen lines.
Expected (anywhere): "nvim%.exe: Failed to %-%-listen: address already in use:"
Actual:
|{114:nvim.exe -h"} |
| |
|[Process exited 1]^ |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|{5:-- TERMINAL --} |
Snapshot:
screen:expect([[
{114:nvim.exe -h"} |
|
[Process exited 1]^ |
|*13
{5:-- TERMINAL --} |
]])
stack traceback:
test\functional\ui\screen.lua:909: in function '_wait'
test\functional\ui\screen.lua:537: in function 'expect'
test/functional/terminal\tui_spec.lua:55: in function <test/functional/terminal\tui_spec.lua:41>
In this case, it appears that the client entered alternate screen in the
middle of the server's print_mainerr().
fix: allocate hidden console for detached server
Starting the server with UV_PROCESS_DETACHED results in DETACHED_PROCESS, leaving the child without a console. Without a console:
CONIN$ / CONOUT$ cannot resolve, causing channel_from_stdio to fail.
ConPTY cannot attach, breaking :terminal.
This patch allocates a hidden console via AllocConsole() when the server has none, restoring working stdio and enabling ConPTY.
Also updates os_set_cloexec to clear HANDLE_FLAG_INHERIT on the RPC pipe
handles, matching the Unix F_DUPFD_CLOEXEC behavior.
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).
Problem: When nvim is started with "-s -" (read from stdin), ":restart"
drops the "-" argument but keeps "-s", leaving an orphaned "-s" in the
restarted server's argv, causing a crash.
Solution: Drop "-s" and its scriptfile argument when copying v:argv for
the restarted server. Like "-- [files…]", the scriptfile is a one-shot
startup input that should not be replayed on restart
Problem:
- `:restart <cmd>` prepends `-c <cmd>` before the original `-c` args (if
any). So the original `-c` args may "override" it, which is
surprising.
- Confusing logic: `v:argv` is partially prepared in `ex_docmd.c`, and
then later `ui.c` skips other parts of it.
Current behavior is nonsense, for example this sequence:
:restart echo "Hello"
:restart +qall echo "Hello" | echo "World"
results in this v:argv:
[
'nvim'
'-c'
'echo "Hello" | echo "World"'
'--embed'
'-c'
'echo "Hello"'
...
]
Whereas after this commit, v:argv is:
[
'nvim'
'--embed'
...
'-c'
'echo "Hello" | echo "World"'
]
Solution:
- Append `-c <cmd>` at the _end_ of `v:argv`, not the start.
- Use a dummy placeholder `+:::` to mark where the "restart command"
appears in `v:argv`.
- Do all `v:argv` preparation in `ex_docmd.c`. This simplifies `ui.c`.
- Drop `-- [files…]` from `v:argv` since it is probably more annoying
than useful. (Users can use sessions to restore files on restart.)
Problem: Terminal doesn't detect if the PTY process is suspended or
offer a convenient way for the user to resume the process.
Solution: Detect suspended PTY process on SIGCHLD and show virtual text
"[Process suspended]" at the bottom-left. Resume the process
when the user presses a key.
Problem:
restart hangs when nvim was started with stdin input, "-" marker stays
in v:argv, causing the restarted instance to block reading from stdin.
Solution:
filter out the "-" argument when rebuilding v:argv during restart.
Stdin content is ephemeral and shouldn't be re-read after restart.