Commit Graph

660 Commits

Author SHA1 Message Date
Justin M. Keyes
73e766f8f6 fix(lifecycle): json_create_config leak
Problem:
As it turns out, when you have 17 different ways to "exit", you need to
plug 17 different holes.

Leak still reported by ASAN CI, even after 1eae512285 f238788601.

    ERROR: LeakSanitizer: detected memory leaks
        strbuf_init src/cjson/strbuf.c:62:22
        json_create_config src/cjson/lua_cjson.c:635:5
        lua_cjson_new src/cjson/lua_cjson.c:2060:5
        nlua_state_add_stdlib src/nvim/lua/stdlib.c:840:3
        nlua_state_init src/nvim/lua/executor.c:973:3

Analysis:
`os_breakcheck()` may process a `exit_event` placed by
`exit_on_closed_chan()` during shutdown. This would re-enter
`preserve_exit()`, which then skips everything because it sees
`really_exiting=true`.

Solution:
Set `exiting` in `preserve_exit()`, not only in `getout()`.
2026-08-18 21:43:35 +02:00
Justin M. Keyes
c184ca2c68 fix(lifecycle): ignore signals during os_exit
Problem:
SIGTERM received during `os_exit()` can cause it to "nest":

    os_exit src/nvim/main.c:720
    preserve_exit src/nvim/main.c:910
    deadly_signal src/nvim/os/signal.c:205
    on_signal src/nvim/os/signal.c:240
    signal_event src/nvim/event/signal.c:45
    multiqueue_process_events src/nvim/event/multiqueue.c:159
    event_teardown src/nvim/main.c:178
    os_exit src/nvim/main.c:720

Solution:
Call `signal_reject_deadly()` at the start of `os_exit()` like
`preserve_exit()` already does.
2026-08-18 18:04:19 +02:00
tao
f0a0182285 refactor(path): pathcmp() #41035
Problem:
Redudant code

Solution:
Add `path_fold_char()` to normalize path sep.
Refactor `pathcmp()` and `path_fnamencmp()` into `path_cmp`.

| feature                  | pathcmp        | path_fnamencmp | path_cmp(now) |
| ------------------------ | -------------- | -------------- | ------------- |
| case folding             | `mb_toupper()` | `utf_fold()`   | `utf_fold()`  |
| consults fileignorecase  |              |              | `ic` param    |
| `maxlen`                 |              |              |             |
| `/` == `\`               |              |              |             |
| MSWIN drive letter       |              |              |             |
| sep affects sorting      |              |              |             |
| ignores a trailing slash |              |              |             |

Refactor `path_fnamecmp` and `path_full_compare` into `path_equal`,
with flags controlling "no filesystem" comparison (i.e. `path_cmp`), env
variables expansion, absolute path resolution and filesystem access.
2026-08-07 19:54:29 -04:00
Justin M. Keyes
cb7c019167 refactor(options): drop OptVal, use Object
Problem:
The object subsystem has an intermediate representation for no real
reason. Besides the code cost, this also adds an extra (api <=> OptVal)
conversion step, which is a (small) perf cost.

Solution:
We already have `Object`, so use it instead.

- drop `OptVal`, `OptValData`, `OptValType`, and related boilerplate.
- add `kObjectTypeUnset`.
2026-07-29 15:27:45 +02:00
Justin M. Keyes
fbcb7a056c feat(exmode): "1q:", :exmode #41010
Problem:
Want `gQ` for _le multicursor_.

Solution:
- Don't use `gQ` for exmode.
- Introduce `:exmode`.
- Introduce `[count]q:` as an alias to `:exmode`.
2026-07-27 11:12:47 -04: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
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
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
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
Justin M. Keyes
6bb1aa74e6 refactor: unify context-switching concepts 2026-07-10 03:27:37 +02:00
Justin M. Keyes
a6d7193f07 refactor(lua): rename nlua_call_typval 2026-07-06 22:17:25 +02:00
Justin M. Keyes
f46857d1df refactor(os): deduplicate console/fd boilerplate #40509
Problem:
Scattered, redundant boilerplate for Windows console/fd plumbing.

Solution:
- Add os_dup_cloexec()
- Add os_reattach_console_stdio().
- Use os_open_conin_fd().
2026-06-30 15:31:35 -04:00
Justin M. Keyes
b2bf7bcfb1 feat(cmdwin): implement cmdwin as a normal buf+win
Problem:

cmdwin (the `:q` cmdline buffer) has various limitations which require
special-casing all over the codebase.

Besides complicating the code, it also breaks async plugins if they try
to create buffers/windows after some work is done, if the user happens
to open cmdwin at the wrong the moment:

    Lua callback: …/guh.nvim/lua/guh/util.lua:531:
    E11: Invalid in command-line window; <CR> executes, CTRL-C quits
    stack traceback:
        [C]: in function 'nvim_buf_delete'
        …/guh.nvim/lua/guh/util.lua:531: in function <…/guh.nvim/lua/guh/util.lua:526>

Solution:

Just say no to "inception". Reimplement cmdwin as a normal buffer+window.

All of the cmdwin contortions (in both core, and innocent plugins) exist
literally only to support "inception": recursive
cmdwin-in-cmdline-things, like `<c-r>=`, `/`, search-during-substitute,
`:input()`, etc. So we just won't support that (though I have
a potential plan for that later, which I call "modal parking lot").

The benefit is that plugins, and core, no longer have to care about
cmdwin.

BONUS:
- mouse-drag on vertical separators works (it only worked for
  horizontal/statusline before)
- inccommand-in-cmdwin now works correctly, for free (thus don't need
  #40077).

POTENTIAL FOLLOWUPS
- Drop `CHECK_CMDWIN` ("E11: Invalid in command-line window"), allow chaos.
- Unify `BUFLOCK_OK` / `LOCK_OK` ?

DESIGN:
- Eliminate lots of C globals, `EX_CMDWIN`, etc.
- `text_locked()` no longer reports true for cmdwin.
- cmdwin = a normal window with 'winfixbuf', 'bufhidden=wipe',
  'buftype=nofile'. Invariants come from those options rather than
  special cases throughout the codebase.
- `nv_record` for q:/q//q? calls Lua
  `nlua_call_vimfn("vim._core.cmdwin", …)`. No `K_CMDWIN`
  / cmdline-reader detour.
- `cedit_key` (`c_CTRL-F`) schedules a deferred event that calls
  `vim._core.cmdwin.open(type, content, pos)` and returns `Ctrl_C` so
  the in-flight cmdline cancels. Reader state is not serialized; instead
  the captured `(type, line, col)` is replayed via
  `nvim_feedkeys(type..line.."<CR>", "nt", …)` after user confirms.
- On confirm/cancel: `<CR>` / `<C-C>` calls into Lua which closes the
  window and re-feeds the cmdline.

BREAKING CHANGES:
- Expression-register cmdline (`<C-R>=` from insert-mode) no longer
  supports cmdwin. Same applies to `input()` / `inputlist()` (already
  covered by `text_locked`).
- Usage of cmdwin in macros/mappings will probably break (assuming they
  ever worked).
2026-06-25 18:36:24 +02:00
bfredl
03aff28b73 feat(startup)!: "standalone" mode -ll is kill
This was originally used because we needed a lua interpreter to run the
standalone _busted_ lua application (except we used fuckery behind the
scenes to fake its binary dependencies with our own binary
dependencies). Now we longer do that, we instead run `test.harness` as a
standard nvim -l script. as this mode is no longer used in tests it
risks going to bitrot anyway.

NB: -ll mode still had some theoretical benefits like quicker
initialization and more "native" printing behavior, etc.
But we can incrementally work on "nvim -l" mode instead
of maintaining a separate special thing.
2026-06-04 14:35:41 +02:00
Lewis Russell
9432e6c1e2 test: run Lua harness with nvim -l
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
2026-05-13 13:14:07 +01:00
li
807f3703c4 refactor(main.c): unused "cwd" variable #39751 2026-05-12 15:45:01 +00:00
Justin M. Keyes
18d7dd485b feat(ui): use vim.ui.select for :oldfiles, :recover
Problem:
followup to 55ceb314ca #39478
`:oldfiles` and swapfile `:recover` do not delegate to `vim.ui.select`.

Solution:
- Delegate to `vim.ui.select`.
- Fix a long-standing `recover_names` bug where `concat_fnames(dir_name,
  files[i], true)` produced malformed `<dir>//<dir>/<file>` paths (also
  fixes `swapfilelist()`).
2026-04-30 17:44:31 +02:00
Till Bungert
a0820481f2 fix(excmd): use realtime for v:starttime, :uptime #39425
Problem:
`v:starttime`, `:uptime` use a monotonic high-resolution timer. This
only works as long as the timer keeps running (if the computer is
suspended the timer is paused). This is somewhat unintuitive, and
doesn't match the behavior of the `uptime` shell command.

Solution:
Implement `os_realtime` to get the real time since the
epoch in nanoseconds.
2026-04-27 19:01:47 -04:00
tao
f130922744 fix(path): normalize path slashes on Windows #37729
Problem:
On Windows, path separators may become inconsistent for various reasons,
which makes normalization quite painful.

Solution:
Normalize paths to `/` at the entry boundaries and always use it
internally, converting back only in rare cases where `\` is really
needed (e.g. cmd.exe/bat scripts?).

This is the first commit in a series of incremental steps.

Note:
* some funcs won't respect shellslash. e.g. `expand/fnamemodify`
* some funcs still respect shellslash, but will be updated in a follow
  PR. e.g. `ex_pwd/f_chdir/f_getcwd`
* uv's built-in funcs always return `\`. e.g. `uv.cwd/uv.exepath`

Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2026-04-24 13:20:25 -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
zeertzjq
4d7dfa081b vim-patch:9.2.0291: too many strlen() calls
Problem:  too many strlen() calls
Solution: refactor concat_fname() and remove calls to strlen()
          (John Marriott)

Function `concat_fnames()` can make up to 5 calls to `STRLEN()` (either
directly or indirectly via `STRCAT()`). In many cases the lengths of
arguments `fname1` and/or `fname2` are either known or can simply be
calculated.

This Commit refactors this function to accept the lengths of arguments
`fname1` and `fname2` as arguments. It also adds new argument `ret` to
return the resulting string as a `string_T`.

Additionally:
- function `add_pack_dir_to_rtp()` in `scriptfile.c`:
   Use a `string_T` to store local variables `new_rtp` and `afterdir`.
   Replace calls to `STRCAT()` with calls to `STRCPY()`.
   Change type of variable `keep` to `size_t` for consistency with
   other lengths.

- function `qf_get_fnum()` in `quickfix.c`:
  Use a `string_T` to store local variables `ptr` and `bufname`
- function `qf_push_dir()` in `quickfix.c`:
  Use a `string_T` to store local variable `dirname`.
  Replace call to `vim_strsave()` with `vim_strnsave()`.

- function `qf_guess_filepath()` in `quickfix.c`:
  Use a `string_T` to store local variable `fullname`.

- function `make_percent_swname()` in `memline.c`:
  Rename some variables to better reflect their use.
  Use a `string_T` to store local variables `d` and `fixed_name`.
  Slightly refactor to remove need to create an extra string.
- function `get_file_in_dir()` in `memline.c`:
  Use a `string_T` to store local variables `tail` and `retval`.
  Move some variables closer to where they are used.

- function `cs_resolve_file()` in `if_cscope.c`:
  Use a `string_T` to store local variable `csdir`.
  Remove one call to `STRLEN()`.

- function `add_pathsep()` in `filepath.c`:
  Refactor and remove 1 call to `STRLEN()`

- function `set_init_xdg_rtp()` in `option.c`:
  Use a `string_T` to store local variable `vimrc_xdg`.

closes: vim/vim#19854

cb51add7ae

Co-authored-by: John Marriott <basilisk@internode.on.net>
Co-authored-by: Christian Brabandt <cb@256bit.org>
2026-04-06 11:47:44 +08:00
zeertzjq
a3a48392c5 fix(:restart): only pass --headless when there is no UI (#38580)
Change --embed so that the first UI can be on non-stdio channel even if
neither --headless nor --listen is passed.
2026-03-31 07:00:34 +08:00
zeertzjq
79ebe54634 refactor(ui_client.c): remove unused variable (#38552)
It's been unused since #36319.
2026-03-29 11:24:52 +00:00
Sathya Pramodh
d5516daf12 fix(:restart): formalize restart event #35223
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>
2026-03-28 15:25:09 -04:00
zeertzjq
781ea5b41b fix(exit): stop listening before closing channels (#38480)
Fixes the following flaky test on FreeBSD:

FAILED   test/functional/terminal/tui_spec.lua @ 218: TUI :restart works
test/functional/testterm.lua:223: Row 1 did not match.
Expected:
  |*^                                                  |
  |*{100:~                                                 }|
  |*{100:~                                                 }|
  |*{100:~                                                 }|
  |*{3:[No Name]                                         }|
  |*{MATCH:%d+ +}|
  |{5:-- TERMINAL --}                                    |
Actual:
  |*nvim: Failed to --listen: address already in use: |
  |*"/tmp/cirrus-ci-build/build/Xtest_tmpdir_terminal/|
  |*nvim.cirrus/LLdBdg/nvim.18878.1"                  |
  |*                                More info with "nv|
  |*im -h"                                            |
  |*[Proce^ss exited 1]                                |
  |{5:-- TERMINAL --}                                    |
2026-03-25 10:03:23 +08:00
zeertzjq
29fa072b34 vim-patch:partial:9.2.0126: String handling can be improved (#38214)
Problem:  String handling can be improved
Solution: Pass string length where it is known to avoid strlen() calls,
          do a few minor refactors (John Marriott).

This commit changes some calls to function `set_vim_var_string()` to pass
the string length where it is known or can be easily calculated.

In addition:
In `evalvars.c`:
  * In function `set_reg_var()` turn variable `regname` into a C string
    because that is how it used.
  * Small cosmetics.
In `option.c`:
  * Slightly refactor function `apply_optionset_autocmd()` to move some
    variables closer to where they are used.
In `getchar.c`:
  * Slightly refactor function `do_key_input_pre()`:
    -> change call to `dict_add_string()` to `dict_add_string_len()` and
       pass it the length of `buf`.
    -> only call `get_vim_var_string()` once.
In `message.c`:
  * Use a `string_T` to store local variable `p`.
In `normal.c`:
  * Move some variables closer to where they are used.

closes: vim/vim#19618

727f6e2686

Co-authored-by: John Marriott <basilisk@internode.on.net>
2026-03-10 09:13:30 +08:00
zeertzjq
066891f5d3 revert: "fix(tui): server --listen error sometimes not visible (#38027)" (#38175)
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).
2026-03-06 08:49:09 +08:00
zeertzjq
5048d9aa2a fix(tui): call tcdrain() on stdout and stderr on exit (#38154)
Problem:
On FreeBSD, output written to TTY may be lost on exit.
Example test failure:

FAILED
test/functional/terminal/tui_spec.lua @
2521:
TUI no assert failure on deadly signal #21896
test/functional/terminal/tui_spec.lua:2523: Row 1 did not match.
Expected:
  |*Nvim: Caught deadly signal 'SIGTERM'              |
  |*                                                  |
  |*[Process exited 1]^                                |
  |*                                                  |
  |*                                                  |
  |                                                  |
  |{5:-- TERMINAL --}                                    |
Actual:
  |*                                                  |
  |*[Process exited 1]{100:^                                }|
  |*{100:~                                                 }|
  |*{100:~                                                 }|
  |*{3:[No Name]                                         }|
  |                                                  |
  |{5:-- TERMINAL --}                                    |
To print the expect() call that would assert the current screen state, use
screen:snapshot_util(). In case of non-deterministic failures, use
screen:redraw_debug() to show all intermediate screen states.
Snapshot:
screen:expect([[
                                                    |
  [Process exited 1]{100:^                                }|
  {100:~                                                 }|*2
  {3:[No Name]                                         }|
                                                    |
  {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:2523: in function <test/functional/terminal/tui_spec.lua:2521>

Solution:
Call tcdrain() on stdout and stderr on exit.

This problem is only observed on FreeBSD, but it probably doesn't hurt
to do this on all platforms with termios.h. In fact using tcdrain() on
PTY slave is no-op on Linux according to Linux kernel source code.
2026-03-05 10:48:07 +08:00
zeertzjq
ab8371a26c fix(tui): server --listen error sometimes not visible (#38027)
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().
2026-03-02 20:39:05 +08:00
Sanzhar Kuandyk
b40ca5a01c fix(channel): support :detach, :restart on Windows #37977
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.
2026-02-28 08:21:13 -05:00
Sanzhar Kuandyk
cf874cee33 feat(startup): provide v:argf for file arguments #35889
Problem:
- `:args` and `argv()` can change after startup.
- `v:arg` includes options/commands, not just files.
- Plugins (e.g. Oil) may rewrite directory args.

Solution:
- New read-only var `v:argf`: snapshot of file/dir args at startup.
- Unaffected by `:args` or plugins.
- Unlike `v:argv`, excludes options/commands.
- Paths are resolved to absolute paths when possible

Example:

    nvim file1.txt dir1 file2.txt
    :echo v:argf
    " ['/home/user/project/file1.txt', '/home/user/project/dir1', '/home/user/project/file2.txt']
2026-02-25 03:38:08 -05:00
Sathya Pramodh
c5b8ed870b fix(coverity/644326): NULL ptr deref in socket_address_is_tcp #38010 2026-02-23 04:18:20 -05:00
Sathya Pramodh
d79a9dcd42 refactor(net): socket_address_is_tcp #37947 2026-02-20 18:41:55 -05:00
Jesse van der Pluijm
5c51b45a82 fix(startup): respect $NVIM_APPNAME in $XDG_CONFIG_DIRS paths
Problem:

$NVIM_APPNAME was not respected when searching $XDG_CONFIG_DIRS for
config files. Nvim hardcoded "nvim" when constructing paths like
`$XDG_CONFIG_DIRS/nvim/init.lua`, ignoring the $NVIM_APPNAME environment
variable.

This meant that config files like `$XDG_CONFIG_DIRS/myapp/init.lua` were
not loaded, even though $NVIM_APPNAME was set to "myapp".

Solution:

Use `get_appname()` instead of hardcoded "nvim" for $XDG_CONFIG_DIRS
paths in `do_system_initialization()` and `do_user_initialization()`.
This makes $XDG_CONFIG_DIRS behave consistently with $XDG_CONFIG_HOME,
which already respected $NVIM_APPNAME.

As documented in `runtime/doc/starting.txt` (L1440-L1441):
"In the help wherever `$XDG_CONFIG_…/nvim` is mentioned it is understood
as `$XDG_CONFIG_…/$NVIM_APPNAME`."

See:
43339dee40/runtime/doc/starting.txt (L1440-L1441)

Relates to #37405
2026-02-06 16:12:01 +01:00
Jesse van der Pluijm
f899045adc refactor(startup): extract conflicting configs error to errors.h
Problem:
The E5422 error message was duplicated in two places in main.c, and
hardcoded error strings should be centralized in errors.h for consistency.

Solution:
Add e_conflicting_configs to errors.h and replace both inline error
strings with the centralized constant.
2026-02-06 16:11:22 +01:00
Jesse van der Pluijm
c785d5cdf0 fix(startup): source init.lua from XDG_CONFIG_DIRS
Problem:

`init.lua` files in `$XDG_CONFIG_DIRS` directories were not being sourced during startup, even though the documentation states they should be searched alongside `init.vim`.

See:

e51f5e17e1/runtime/doc/starting.txt (L495-L496)

Solution:

Modify `do_user_initialization()` to search for `init.lua` in each `$XDG_CONFIG_DIRS` directory before falling back to `init.vim`, matching the behavior for `$XDG_CONFIG_HOME`. Also show `E5422` error if both `init.lua` and `init.vim` exist in the same directory.

Fixes #37405
2026-02-06 16:11:22 +01:00
Jan Edmund Lazo
c81f7aeee2 vim-patch:8.2.0098: exe stack length can be wrong without being detected (#37136)
Problem:    Exe stack length can be wrong without being detected.
Solution:   Add a check when ABORT_ON_INTERNAL_ERROR is defined.

e31ee86859

vim-patch:8.2.3262: build failure when ABORT_ON_INTERNAL_ERROR is defined

Port patch 9.0.1454 for "make formatc".

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2025-12-28 14:26:29 +08:00
Justin M. Keyes
2eb11f21eb test(messages): skip os_delay during tests
Problem:
Tests that trigger `os_delay` messages may take 1-3 seconds, wasting
build/CI time, since this serves no purpose in tests.

Solution:
- Introduce `msg_delay` for cases where `os_delay` is being used as
  a "UI feature".
- Skip `msg_delay` in tests.
2025-12-20 18:38:11 -05:00
€šm̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰̰�Ř§Ů Â£╟©舐æØ¢£ðsÞ¥¿—
ed9abb1851 fix(exrc): ensure consistent 'exrc' loading sequence #35148
Problem:
The execution of startup scripts in parent directories are too late
compared to scripts in current direcctory.

Solution:
Execute all startup scripts with `lua/_core/exrc.lua`.

closes: #35147
2025-12-08 22:22:10 -05:00
Nathan Smith
551bb63d44 feat(events): MarkSet event, aucmd_defer() #35793
Problem:
- Can't subscribe to "mark" events.
- Executing events is risky because they can't be deferred.

Solution:
- Introduce `MarkSet` event.
- Introduce `aucmd_defer()`.

Helped-by: zeertzjq <zeertzjq@outlook.com>
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
2025-12-07 15:13:31 -05:00
Anatolii Sakhnik
a141fd2c4d fix(remote): remote-ui connect timeout on slow networks #36800
Problem:
Connecting to a remote Neovim fails on slow network:

```
$ nvim --remote-ui --server 10.0.3.100:11111
Remote ui failed to start: connection refused
```

Strace reveals that the connection wasn't actually refused, but was still in progress:
```
15:52:50.678223 socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_IP) = 11
15:52:50.678278 setsockopt(11, SOL_TCP, TCP_NODELAY, [1], 4) = 0
15:52:50.678320 connect(11, {sa_family=AF_INET, sin_port=htons(11111), sin_addr=inet_addr("10.0.3.100")}, 16) = -1 EINPROGRESS (Дія зараз виконується)
15:52:50.678443 clock_gettime(CLOCK_MONOTONIC, {tv_sec=21736, tv_nsec=57625406}) = 0
15:52:50.678489 io_uring_enter(4, 3, 3, IORING_ENTER_GETEVENTS, NULL, 0) = 3
15:52:50.678544 epoll_pwait(3, [], 1024, 50, NULL, 8) = 0
15:52:50.728911 clock_gettime(CLOCK_MONOTONIC, {tv_sec=21736, tv_nsec=108159596}) = 0
15:52:50.729203 epoll_ctl(3, EPOLL_CTL_DEL, 11, 0x7ffd6ec9a3bc) = 0
15:52:50.729527 close(11)               = 0
```

Solution:
Increase hardcoded timeout from 50ms to 500ms.
2025-12-02 11:14:10 -05:00
zeertzjq
003b429a86 vim-patch:9.1.1892: Not possible to know once Vim is done with sourcing vimrc (#36429)
Problem:   A plugin does not know when startup scripts were already
           triggered. This is useful to determine if a function is
           called inside vimrc or after (like when sourcing 'plugin/'
           files).
Solution:  Add the v:vim_did_init variable (Evgeni Chasnovski)

closes: vim/vim#18668

294bce21ee

Nvim has two more steps between sourcing startup scripts and loading
plugins. Set this variable after these two steps.

Co-authored-by: Evgeni Chasnovski <evgeni.chasnovski@gmail.com>
2025-11-02 18:07:33 +08:00
Jan Edmund Lazo
ffdb316491 vim-patch:8.2.4772: old Coverity warning for not checking ftell() return value
Problem:    Old Coverity warning for not checking ftell() return value.
Solution:   Check return value of fseek() and ftell().

3df8f6e353

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2025-10-10 21:20:55 -04:00
Jan Edmund Lazo
96e9041a78 vim-patch:partial:8.1.1939: code for handling v: variables in generic eval file (#35968)
Problem:    Code for handling v: variables in generic eval file.
Solution:   Move v: variables to evalvars.c. (Yegappan Lakshmanan,
            closes vim/vim#4872)

e5cdf153bc

Remove direct reference to "vimvars" for following functions:
- assert_error()
- get_vim_var_nr()
- get_vim_var_list()
- get_vim_var_dict()
- get_vim_var_str()
- set_cmdarg()
- set_reg_var()
- set_vcount()
- set_vexception()
- set_vthrowpoint()
- set_vim_var_bool()
- set_vim_var_dict()
- set_vim_var_list()
- set_vim_var_nr()
- set_vim_var_special()
- set_vim_var_string()
- set_vim_var_type()

Reorder functions based on v8.2.4930 for
eval_one_expr_in_str() and eval_all_expr_in_str().

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2025-10-04 04:28:30 +00:00
Jan Edmund Lazo
406f9e3c8c vim-patch:8.1.2077: the ops.c file is too big
Problem:    The ops.c file is too big.
Solution:   Move code for dealing with registers to a new file. (Yegappan
            Lakshmanan, closes vim/vim#4982)

4aea03eb87

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2025-09-26 00:29:40 -04:00
Cameron Ring
0f64f0f5b6 fix(startup): crash in read_stdin #35699
Problem:
Crash on startup in some situations due to call to `set_curbuf`
with the current value of `cur_buf`.

Solution:
Switch buffers before doing the wipeout of the stdin buffer.
Use cmdline cmds instead of raw buffer pointers to avoid lifetime issues.
2025-09-10 21:37:42 -07:00
Jan Edmund Lazo
681ec17b50 vim-patch:8.1.1940: script tests fail
Problem:    Script tests fail.
Solution:   Don't set vimvars type in set_vim_var_nr().

34ed68d40e

Co-authored-by: Bram Moolenaar <Bram@vim.org>
2025-09-09 23:45:56 -04:00
Luna Razzaghipour
f9ce939bf5 perf: scheduler priority clamping on macOS #35488
Problem:
All of Nvim’s threads are clamped to the Default QoS class. This means
that Nvim is forced to compete for CPU time with compilers and other
batch work, and is even prioritized beneath user-initiated work in GUI
apps like e.g. file imports. This significantly harms responsiveness.

Solution:
Tell the kernel that the Nvim process takes part in rendering a UI.

Implementation:
Remove the process-wide QoS clamp. This doesn’t directly do anything to
the main thread, but rather has the side-effect of letting the main
thread run at its actual QoS (User Interactive QoS).
2025-09-02 18:34:46 -07:00
glepnir
eeba0dc2ed fix: memory leak from double buffer initialization in read_stdin #35413
Problem: When stdin follows files, set_curbuf() initializes buffer via
enter_buffer(), then open_buffer() initializes again, causing memory leaks.

Solution: Use readfile() directly for new buffers already initialized by
enter_buffer(), only call open_buffer() for original buffer case.
2025-08-22 14:50:30 -07:00
Cameron Ring
30dae87de4 fix(startup): file buf is lost if stdin is empty and "-" is last #35402
Problem:
Running `echo dummy | nvim file1 file2` closes the file1 buffer if
file1 doesn't exist.

Solution:
Logic changed in 43e8ec9 such that stdin buffer may now be created *after*
file args. Handle that case.
2025-08-20 20:34:49 -07:00