aboutsummaryrefslogtreecommitdiff
path: root/test/functional/core
Commit message (Collapse)AuthorAge
* fix(startup): respect --noplugin when used with --clean #42362Max Coplan3 days
| | | | | | | | | | | | | | | Problem: When starting Nvim with both `--clean` and `--noplugin` (in either order), `--noplugin` is silently ignored and built-in runtime plugins are loaded anyway. `command_line_scan()` sets `p_lpl = false` for `--noplugin`, and `--clean` sets `params.use_vimrc = "NONE"` and `params.clean = true`, which later overwrites `p_lpl` back to `true` via `p_lpl = vimrc_none ? params.clean : p_lpl`. Solution: Only reset `p_lpl = false` when `vimrc_none && !params.clean`, preserving `p_lpl = false` if `--noplugin` was passed. AI-assisted
* fix(lua): regression with `print()` in headless modebfredl13 days
| | | | | | | | | This is a bunch of hacks so we can override msg_puts_printf specifically while still allowing redirecting and "normal" message flow to happen, as this still has observable side-effects (even with no screen attached, screenstring() is still valid..) fixes #42218
* fix(fileio): do not remove destination file before rename (#42152)Qiming zhao2026-10-03
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * fix(fileio): do not remove destination file before rename Problem: `vim_rename()` unconditionally removes the destination file `to` via `os_remove(to)` before calling `os_rename(from, to)`. If Neovim is killed or a crash occurs between `os_remove()` and `os_rename()`, the destination file is lost. For example, during `shada_write_file()`, `main.shada` is deleted before being replaced by `main.shada.tmp.a`, which can lead to silent loss of command history, marks, and registers. Furthermore, if `os_rename()` subsequently fails, the destination was already destroyed. Solution: In Neovim, `os_rename()` uses `uv_fs_rename()`, which atomically replaces existing destination files on both POSIX (`rename(2)`) and Windows (`MoveFileExW(..., MOVEFILE_REPLACE_EXISTING)`). Attempt `os_rename(from, to)` first. Only if it fails (e.g. cross-device link) and copying is required as a fallback, remove `to` before `vim_copyfile()`. Fixes #41940 AI-assisted * fix(fileio): retry rename after removing destination Retry the native rename after successfully removing the destination so a directory can still replace an existing file. Keep the initial rename attempt before removal and the existing copy fallback. AI-assisted
* feat(lua): in script mode -l, use raw output for print()bfredl2026-10-02
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | consider the following test_script.lua : print 'hello\n' -- TWO new lines print 'this is \027[31mRED FOR AN AMAZING REASON\027[0m' print 'foo' print '' -- newline despite empty! print 'bar' -- a bit later: os.execute 'sleep 2' -- CPU goes BRR, cursor in column zero print 'more bar' before this PR, `nvim -l test_script.lua` had some weird behaviors compared to `lua test_script.lua` or the now removed `nvim -ll test_script.lua`. - one extra '\n' at the end of a print is ignored, one would need TWO '\n' for a single extra '\n' - an empty print'' is supposed to print an empty line - print'\027[31mRED' is being escaped so it does not work - the cursor gets stuck at the end of a message, instead of after emitting the new line, this looks like the CPU lag has something to do with the _last_ printed message which is likely not the case. I consider these behaviors to be unintentional (a consequence of stragglig through the message.c meta-machine, which is optimized for message handling in _an interative text editor_) and getting closer to plain lua behavior would be better. An alternative would be to restore the builtin print(), but our implemenation still has some benefits, like try `print(setmetatable({}, {__tostring=error})` in plain lua..
* fix(options): extend nvim_set_option_value() dry-run validationLewis Russell2026-09-18
| | | | | | | | | | | | | | | | Problem: nvim_set_option_value() dry runs skip checks in did_set_* callbacks. Solution: Split validation out of these callbacks so dry runs and normal assignments use the same checks. Read 'mkspellmem' limits when building spell files. Keep the 'spellsuggest' limit unchanged when an assignment fails. AI-assisted
* feat(multicursor): MC HAMMER #41587Justin M. Keyes2026-09-01
| | | | | | | | | | | | | | | | | | | | | 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().
* fix(restart): preserve global cwd on :restart #41304Nathan Zeng2026-08-16
| | | | | | | Problem: On :restart, the new Nvim may "inherit" a local dir as its global CWD. Solution: Inherit the global CWD explicitly.
* feat(exmode): "1q:", :exmode #41010Justin M. Keyes2026-07-27
| | | | | | | | | Problem: Want `gQ` for _le multicursor_. Solution: - Don't use `gQ` for exmode. - Introduce `:exmode`. - Introduce `[count]q:` as an alias to `:exmode`.
* refactor(exmode): Ex-mode as cmdwin + Lua #40991Justin M. Keyes2026-07-27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* test(harness): migrate away from magic globalsJustin M. Keyes2026-07-21
| | | | | | | | | | | | | | | | | | | | | 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`.
* fix(lua): vim.keycode cleanup #40817Justin M. Keyes2026-07-18
|
* refactor(detach): eliminate `nvim__ui_detach` #40793Justin M. Keyes2026-07-17
| | | | | | | | | | | | | | | Problem: `nvim__ui_detach` was added in 85e0559d46c7 in order to implement `detach_others` from Lua. Using Lua in this case is doing more harm than good. Solution: Extract `ui_detach_channel`, which also allows it to be used for the "self detach" path from `ex_detach`. Bonus: the old MSWIN path always called `os_swap_to_hidden_console()`; now `ui_detach_channel` only does so for a stdio channel. For the common stdio TUI this is identical; for a socket UI it's more correct (no parent console to swap).
* feat(ui): ":%detach!" detaches all other UIs #39216Jason Woodland2026-07-17
| | | | | | | Problem: Not easy for one UI to kick the others off a shared Nvim server. Solution: Treat `:%detach` as detach-other-UIs.
* feat(marks): :marks completion, list extmarks #40743Justin M. Keyes2026-07-15
| | | | | | | | | Problem: - No UI for listing extmarks. - `:marks` doesn't support cmdline-completion. Solution: - Add completion and extmarks support to `:marks`. - Update `get_buf_local_marks` to include the ":" (prompt-buffer) mark.
* fix(path): normalize separators (slashes) #39155tao2026-07-12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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>
* fix(socket): --listen silently truncates long paths #40625MAAZIZ Adel Ayoub2026-07-09
| | | | | | | | | | | | | | | | | | | | | | | | | | Problem: A `--listen` path longer than the system socket path limit (~104 bytes on macOS, 108 on Linux) is silently truncated by `uv_pipe_bind()`. Nvim either serves a socket at a different path than `v:servername` reports, or fails with an error that blames the full untruncated path (confusing): nvim: Failed to --listen: address already in use: "<full path>" Steps to reproduce: $ nvim --listen /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide --embed -p nvim: Failed to --listen: address already in use: "/var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide" $ ls /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide "/var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/-Users-rpatterson-Projects-src-github.com-neovide-neovide": No such file or directory (os error 2) $ ls -l /var/folders/g7/9y_ydbnj2fs_fvp8xf44p8gc0000gn/T//nvim/ srwxr-xr-x@ - rpatterson 31 Mar 10:24 -Users-rpatterson-Projects-src-github.com-neovid Solution: Bind with `uv_pipe_bind2()` and `UV_PIPE_NO_TRUNCATE` (libuv 1.46+), so a too-long path fails up front with the actual reason: nvim: Failed to --listen: invalid argument: "<full path>"
* feat(channel): add ChanClose event #40568Barrett Ruth2026-07-04
| | | | | | | | | Problem: Plugins using RPC sockets cannot detect when the peer closes a `sockconnect()` channel, so reconnect logic has no reliable trigger. Solution: Add a `ChanClose` event with channel info before the channel is removed, matching the existing `ChanOpen`/`ChanInfo` event model.
* feat(health): report ulimit infoJustin M. Keyes2026-07-01
| | | | | | | | | Problem: Nvim shows `(libuv) kqueue(): Too many open files` on macos. ref https://github.com/neovim/neovim/issues/40238 Solution: Add a healthcheck for this situation.
* feat(:restart)!: ":restart" (no bang) saves/restores session #40321Nathan Zeng2026-06-29
| | | | | | | | | | | 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!`.
* fix(lua): reject process exit in fast callbacks #39937Barrett Ruth2026-06-27
| | | | | | | | | | | | Problem: `os.exit()` in `nvim -l` exits through normal teardown. But, as #39783 shows, when it is called from a libuv callback, teardown polling the main loop when inside `uv_run()` can trip the recursive poll guard and cause a crash. Fast callbacks are not safe to teardown, so it's better to schedule an exit out of a callback rather than convolutedly handle this as I tried before. Solution: Reject `os.exit()` from fast callbacks with `E5560` error.
* feat(cmdwin): implement cmdwin as a normal buf+winJustin M. Keyes2026-06-25
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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).
* refactor(test): move swapfile testJustin M. Keyes2026-06-20
|
* fix(tests): use builtin default attributes in more placesbfredl2026-06-19
|
* feat(:restart): v:startreason #40186Nathan Zeng2026-06-18
| | | | | | | | Problem: It's clumsy for scripts to handle a "restart", without custom mappings or global vars. Solution: Introduce `v:startreason`
* fix(path): open swapfile when using device path #39982tao2026-06-16
| | | | | | | | | | | | | Problem: Can't open swapfile when using a device path starting with `//?/`, because `?` is a reserved char on Widnows. Solution: For device UNC paths, replace `//?/UNC/` and `//./UNC/` with `//`. For other device paths, just strip their prefix (i.e. `//?/`, `//./`). This aligns swapfile naming for device paths with regular UNC and DOS paths. Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
* test(windows): unskip some channel/job tests #38515Justin M. Keyes2026-06-12
|
* fix(path): prevent infinite loop when re-editing file without drive-lettertao2026-06-02
| | | | | | | | | | | | | | | Problem: Edit a file with a drive-letter path, then re-edit it without the drive letter and colon. This cause `path_fnamencmp` to loop infinitely as `len` never reaches 0, while `c1` and `c2` are already NUL. Commit e18a578 accidentally used || before `(p_fic`, commit 4bcee96 fixed that, but also moved the NUL check into a grouped condition. The bug remained hidden because there weren't any cases where strings had different lengths and c1 and c2 could both reach NUL. `c:/foo` vs `/foo` happens to be such a case, which is why the infinite loop finally showed up. Solution: Break the loop when either `c1` or `c2` is NUL.
* refactor: introduce nvim_on internally #39883Justin M. Keyes2026-05-20
| | | | | | | | | 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.
* fix(messages): avoid recursive rtp build due to msg_show #39888luukvbaal2026-05-20
| | | | | | Problem: If there are pending messages when starting to build the runtime search path, a msg_show callback may invoke runtime_search_path_validate() recursively. Solution: Avoid msg_show callback by ensuring messages are flushed.
* test: run Lua harness with nvim -lLewis Russell2026-05-13
| | | | | | | | | | | | | | | | | | 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
* feat(server): add v:useractive, use it in serverlist(info=true) #39423Szymon Wilczek2026-05-07
| | | | | | | | | | | | Problem: When showing the :connect menu, it is useful to know which servers are most-recently active. But we don't have a good way to detect that. Solution: - Introduce `v:useractive`. - Include this timestamp in `serverlist({info=true})`. Co-authored-by: Justin M. Keyes <justinkz@gmail.com> Signed-off-by: Szymon Wilczek <swilczek.lx@gmail.com>
* feat(server): serverlist({info=true}) gets detailed info #39392Szymon Wilczek2026-05-06
| | | | | | | | | | | | | | | | | Problem: UI tools and orchestration engines need more context than just raw socket addresses from serverlist(). Without knowing if a server belongs to the current instance or knowing its PID, UIs cannot display meaningful options to users. Solution: - Added the `info=v:true` option to `serverlist()`. - When `info` is requested, it implies `peer=true` and returns a list of dictionaries (defined as `vim.ServerInfo`) with `addr`, `pid` and `own`. - Uses an RPC request to `getpid()` across the socket to fetch the peer's actual process ID. Signed-off-by: Szymon Wilczek <swilczek.lx@gmail.com>
* feat(ui): use vim.ui.select for :oldfiles, :recoverJustin M. Keyes2026-04-30
| | | | | | | | | | | | Problem: followup to 55ceb314ca96 #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()`).
* refactor(tty): tty.request() #39489Justin M. Keyes2026-04-30
| | | | | | | | 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()`.
* feat(ui): use vim.ui.select for :tselect, z= #39478Justin M. Keyes2026-04-28
| | | | | | | | | | | | | | | | | | | | | Problem: `:tselect` and `z=` (spell suggest) have their own bespoke select menus. Solution: - Delegate to `vim.ui.select` instead. - Bonus: - `:tselect` gains mouse support. `print_tag_list` didn't suport mouseclick. This causes some minor regressions, which are not blockers: - `z=` no longer draws the list right-left if 'rightleft' is set. - TODO: can/should `vim.ui.select` / `vim.fn.inputlist()` handle that? - `:tselect` - No "column" headings (`# pri kind tag file`). - No highlighting: (HLF_T: tag name, HLF_D: file, HLF_CM: extra fields). - TODO: can `vim.ui.select()` support highlighted chunks (`[[text, hl_id], ...]`) ? fix https://github.com/neovim/neovim/issues/25814 fix https://github.com/neovim/neovim/issues/31987
* fix(channel): stack-buffer-overflow with exit during connection (#39387)zeertzjq2026-04-25
| | | | | | Problem: When Nvim exits while connecting to a socket it leads to stack-buffer-overflow. Solution: Associate the handle with the Stream and use the Stream's internal_close_cb to update the "closed" status.
* fix(path): normalize path slashes on Windows #37729tao2026-04-24
| | | | | | | | | | | | | | | | | | | | 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>
* fix(trust): always use "/" slashes in filepaths #39355Justin M. Keyes2026-04-24
| | | | | | | | 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.
* feat(excmd): add :uptime command #39331Olivia Kinnear2026-04-23
| | | | | | | 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)).
* ci: drop cirrus #39321Justin M. Keyes2026-04-22
| | | | | | | | Problem: cirrus will shutdown soon, and we are running out of minutes anyway, which causes ci failures. Solution: Drop cirrus config.
* feat(:restart): v:starttime, v:exitreason #39282Justin M. Keyes2026-04-22
| | | | | | | | | | | | 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`
* perf(lsp): clear table by table.clear() #39222Yi Ming2026-04-22
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |