aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/ex_docmd.c
Commit message (Collapse)AuthorAge
* fix(channel): emit ChanInfo for :detach! #42295Sanzhar Kuandyk7 days
| | | | | | | | | Problem: :detach! changes the channel's detach property without emitting ChanInfo, so plugins watching channel updates cannot react to changes. Solution: Schedule ChanInfo after setting detach=true. Add a test covering emit on :detach!. AI-assisted
* fix(api): crash on invalid :tab address #42328glepnir7 days
| | | | | | | | Problem: nvim_parse_cmd("'btab", {}) and typing ":'btab" crash, parse_cmdline() continues with a NULL eap->cmd after an invalid :tab address. Solution: Fail if parse_command_modifiers() set an error.
* feat(api): nvim_chan_set()Justin M. Keyes11 days
| | | | | | | | | | | | | | | | | | | Problem: Only the stdio channel can "own" a server (self-exit on close). After :restart the TUI reconnects over a socket, so the restarted server does not have "self-exit" behavior when the channel closes (e.g. by UI disconnect, host-terminal close, etc.), which leaves a dangling server. Solution: - Introduce `nvim_chan_set`. (`nvim_set_client_info` doesn't fit: exposing it to Lua would require a `channel` param, which is not backwards-compatible, plus it's awkward because it doesn't merge info.) - Broadcast per-channel properties in the "restart" UI event as an opaque dict (a potentially useful pattern for other UI-events in the future). - UIs are expected to restore the channel properties on restart. - `nvim_get_chan_info()` reports "detach". - Remove `nvim__chan_set_detach()`.
* vim-patch:9.2.1159: :append in a block that is not executed reads its text ↵zeertzjq2026-10-01
| | | | | | | | | | | | | | | as commands (#42196) Problem: In a block that is not executed, the text lines of :append, :insert and :change are parsed as commands, so e.g. a text line "endif" ends the block Solution: Read and discard the text up to "." while skipping. Add the commands to the ":help :bar" list. closes: vim/vim#21331 https://github.com/vim/vim/commit/ae8837c19d33801426cb2dfa1cdbd7be7c1cf8e2 Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
* vim-patch:partial:9.2.1132: skip condition not considered for certain ↵zeertzjq2026-09-26
| | | | | | | | | | | | | | commands (#42102) Problem: "if 0" condition not correctly skipped for :command, :autocmd, :class, :interface, :enum and :loadkeymap Solution: Skip those commands and discard the blocks they read (Hirohito Higashi). closes: vim/vim#21349 https://github.com/vim/vim/commit/f3dc0fee778439ac8ff8680b42552f7f13d47396 Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
* refactor(api): reuse parse_cmdline in nvim_cmd #38508glepnir2026-09-22
| | | | | | | | | Problem: nvim_cmd() duplicates Ex parsing: it sets the address type and default range itself and builds the whole command line in build_cmdline_str(). Solution: Build only the range, command name and arguments, and let parse_cmdline() fill in exarg_T.
* vim-patch:9.2.1101: modifier_len() scans the whole command modifier tablezeertzjq2026-09-15
| | | | | | | | | | | | | | | | | | | | Problem: modifier_len() always iterates every entry of cmdmod_info_tab[] when checking for a command modifier, even though the table is sorted by name; this runs for every sourced line via has_loop_cmd() and shows up when loading large syntax scripts. Solution: Break out of the loop as soon as the table entry's first letter is past the command's first letter, since no later entry can match in a name-sorted table (Julien Voisin). Adding an early break roughly halves the instruction count spent in modifier_len() and shaves about 1.5% to 2% off single-file syntax load across common filetypes, with no change in behaviour. closes: vim/vim#21304 https://github.com/vim/vim/commit/4600f4afec028c049d254a89929e762f6442d549 Co-authored-by: Julien Voisin <julien.voisin@dustri.org>
* feat(api): add ev.win to autocmd callback args #39826glepnir2026-09-09
| | | | | | | | Problem: Autocmd callbacks currently have to rely on curwin, which may already have changed by the time they run. This is especially noticeable for WinNew, WinClosed, WinResized and WinScrolled. Solution: Track the window in the autocmd context and expose it as ev.win. Pass it explicitly for the window events that need it.
* fix(multicursor): cascade mapping atoms with insert entry #41714Justin M. Keyes2026-09-05
| | | | | | | | | | | | | | | | | | Problem: Pending mapping atoms prevent live insert-cascading (`nnoremap i ^i`). Flushing them at insert-session start (3a02a399578c) adds a separate cascade boundary, which muddles the architecture. Solution: Let the first insert-span cascade pending mapping atoms on insert-entry. This is an alternative fix for #41692. Composite children (`.atoms`) BEFORE: { { 'motion', '^' }, { 'insert', '1iX<Esc>' } } Composite children (`.atoms`) AFTER: { { 'motion', '^' }, { 'insert', '1i<Esc>' }, { 'insert', 'iX<Esc>' } }
* fix(multicursor): 'autocomplete' during insert-cascade raises E565 #41625Justin M. Keyes2026-09-02
| | | | | | | | | | Problem: With mcursors and 'autocomplete', a non-literal key (`<BS>`) during an active completion attempts to insert-cascade, which attempts a nested `edit()`, which refuses with E565. Solution: Defer the flush while completion is active; the pending keys will be handled later.
* fix(tabpage): focusing a tab while closing it, fails assert #41475Rob Pilling2026-08-28
| | | | | | | | | | | | | | | | | | | | | Problem: If an autocommand handler focuses the tab page we're closing during a `:tabonly` (with some conditions), we hit an assert failure in `win_close_othertab()`. For this to occur, we need: - `nvim_buf_delete()` to trigger `close_windows()` (as is done in `cmdwin.lua`'s `_cleanup()`) - `close_windows()` then calls `win_close_othertab()`, removing the window (`win_free_mem()`) - then in the caller, `tabpage_close_other()`, the loop continues (we don't detect `tp_lastwin == wp` since we've unlinked the window) - the loop assumes that `curtab != tp` but we've refocused `curtab` so the `ex_win_close()` call passes `tp` as `curtab`, causing the assert to fail Solution: Detect the focus of `curtab` and abort closing the tab.
* 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(input)!: CmdAtom event #41297Justin M. Keyes2026-08-14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: There is no unified notion of a "user action". Vim processes input by one-char-at-a-time, and mostly throws away any hints it might gather about the user's action, with one exception: it stores the last _edit_ action (the "redo buffer", encoded as unstructured `["x][v][count]body` bytes). Plugins can only observe individual keys (vim.on_key) and high-level effects (TextChanged, CursorMoved). Solution: - Users can subscribe to `CmdAtom` events to handle any user action. - Event is deferred; handlers cannot cancel or interfere with user actions. - Capture `CmdSpec` from the normal/insert/visual subsystems. - typeahead/readahead stay unstructured (`buffheader_T`): they are key streams, not commands. - the redo/record buffers become `StringBuilder`: fewer allocations/copies. - Repurpose the input/redo engine to accept `CmdSpec` objects. "atom": one repeatable unit of user input, as a resolved (post-mapping) keysequence plus structured fields. Only user actions, not `:normal`, API calls, or non-"t" `feedkeys`. BREAKING: dot-repeat of an Insert session, replays the entire session including cursor-moves (:help ins-repeat). BREAKING: dot-repeat of a Visual operation, replays the selection instead of operating on a fixed-size region.
* refactor(ex_cmds): use function arguments for magic behaviorbfredl2026-08-10
| | | | | | | | | | | | Now this was a cargo cult anti-pattern to write home about. Doing painful save-and-restore bookkeeping around a separate `magic_overruled` decoy global is just as messy as doing painful save-and-restore logic around `p_magic` itself. only that now you need to wrap every access to the effective value in a function call. This replaces this with a marvellous new Clean Code technique™: passing in the intended behavior as a function parameter to functions where either the option or an explicit value might be used.
* refactor(path): pathcmp() #41035tao2026-08-07
| | | | | | | | | | | | | | | | | | | | | | 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.
* feat(cwd)!: :lcd! (bang), rearrange :bcd/:lcd/… scope precedence #41194Justin M. Keyes2026-08-07
| | | | | | | | | | | | | | | | Problem: - buf-local CWD scope is lower priority than :lcd, which is weird. ``` win > buf > tab > global ``` - No way to clear current CWD at a given scope. Solution: - Rerrange scope precedence to: ``` buf > win > tab > global ``` - Introduce "bang" variants (`:bcd!`/`:lcd!`/`:tcd!`) which clears the local CWD for the given scope.
* feat(cwd): support explicit chdir (:bcd/:tcd/…) in temp contextJustin M. Keyes2026-08-06
| | | | | | | | | | | | | | | | | | Problem: - Explicit `:bcd` (etc.) persists from `nvim_buf_call()` but not from an autocmd handler targeting a hidden buf (`LspAttach`, `TermRequest`, …), which needs a `vim.schedule()` workaround. - `vim._with()` is supposed to work as a "sandbox", discarding side-effects, but it leaks CWD changes: `:lcd` from a `win` context, any chdir from a visible-buffer context. Solution: - Explicit :cd/:tcd/:bcd during a temp context persists by default. - "Ambient" directory changes ('autochdir', existing win-local CWD, etc.) are still undone, as before. - Add `kCtxKeepDirs`: snapshot/restore the target's full CWD state (w/b/tp-local, global, cwd). Used by `vim._with()` and `'inccommand'`, which must not leak state.
* fix(cwd): validate getcwd(…, -1)Justin M. Keyes2026-08-04
|
* refactor(editor): cleanup change-directory (:bcd) logicJustin M. Keyes2026-08-04
|
* feat(editor): `:bcd` changes buffer-local directorysaher2026-08-04
| | | | | | | | | | | | | | | | | | Problem: No way to set a buffer-local directory. Use-cases: - "Root dir" for LSP (and the "project" concept). - `:terminal` OSC 7 Solution: Add `:bcd` command. - Extend `getcwd()` to take a third arg; `getcwd(-1, -1, bunfr)` returns the buffer-local working directory. - Buffer-local directories have less priority than window-local ones, and more priority than tab-local ones. Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
* feat(detach): opt-in to "server keeps running" #41133Justin M. Keyes2026-08-04
| | | | | | | | | | 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.
* fix(ui2): `:$q` should not target hidden windows #40992Rob Pilling2026-08-02
| | | | | | | | | | | | | | | | | | | | | | | Similar to #36123, the ui2 windows confuse `:$q`, which doesn't close the last window on the tab, but targets a hidden ui2 window. The problem seems to be a combination of using `FOR_ALL_WINDOWS_IN_TAB()`, which includes hidden windows, and then counting the windows without factoring in `win_has_winnr()`. There are examples of using `win_has_winnr()`, such as: - [`eval/buffer.c`'s `buf_win_common()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/eval/buffer.c#L474-L475) - [`eval/window.c`'s `f_getwininfo()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/eval/window.c#L130-L135) - [`window.c`'s `win_get_tabwin()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/window.c#L7860-L7869) But possibly problematic ones: - `ex_docmd.c`'s: - [`invalid_range()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/ex_docmd.c#L3891-L3893) - ^ should this include hidden windows? Can a user address them by number? `win_has_winnr()` suggests not - [`ex_close()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/ex_docmd.c#L5233-L5244) - [`ex_hide()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/ex_docmd.c#L5478-L5484) - `eval/window.c`'s: - [`f_winrestcmd()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/eval/window.c#L797-L808) - [`find_win_by_nr()`](https://github.com/neovim/neovim/blob/4a5062cda69fa6cb59b7dc0c488dfb05accf99de/src/nvim/eval/window.c#L172-L180)
* feat(options): lua closure/function optionsJustin M. Keyes2026-07-31
| | | | | | | | | | | | | | | Problem: Cannot assign Lua functions/closures to "func" ('completefunc', 'tagfun', …) or "expr" ('foldexpr', 'indentexpr', …) options. Solution: - Store "func"/"expr" options as `Callback` instead of string. - Delete oceans of copy-pasted code. - BREAKING: LuaRef returned via RPC/Vimscript is now represented as `"<Lua N: file:line>"` (like what `:map` shows) instead of `nil`. - Note: `man.vim` still uses `v:lua` string, bc it's a vimscript ftplugin. Helped-by: Lewis Russell <lewis6991@gmail.com>
* refactor(options): drop OptVal, use ObjectJustin M. Keyes2026-07-29
| | | | | | | | | | | | | 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`.
* 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.
* fix(dir): `:browse edit` opens dir browser #40930Barrett Ruth2026-07-25
| | | | | | | | Problem: `:browse edit` (and variants) without an argument fails instead of opening a browser. Solution: Dispatch to dir.lua using the cwd as the implied directory. Replace the inherited GUI-only documentation with the supported behavior. Support vsplit, split, tabedit variants.
* feat(options): schema, "dict" options, messagesJustin M. Keyes2026-07-24
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Options parsing is still painful for dict-style options. Solution: schema-maxxing => better `opt:get()` (will be the basis for `vim.o()`), unified (and more-detailed) err msgs. - Drop bespoke structure-builder in `_core/options.lua`. - Define `schema` for all non-primitive options (except 'guicursor' and statusline-style options); generate reified keysets `OptKeyDict`). - Generate 'fillchars' => `fcs_tab`, 'listchars' => `lcs_tab`. - `nvim_set_option_value`: - Return the improved structures. Also from `vim.opt.x:get()`. - Eliminate api <=> lua roundtrip, centralize option structure handling. - Improve/unify errors. - Bump ERR_BUFLEN 80 → 256 so the "one of" list isn't truncated. - Eliminate old 'diffopt' order-dependence (`iwhiteall` before `iwhite`) Error samples: Typed-key path (opt_strings_check → diffopt/mousescroll/breakindentopt): E474: Unknown item 'foo' E474: 'context' requires a number E474: 'ver' number is out of range E474: 'algorithm' must be one of: myers, minimal, patience, histogram E474: 'filler' does not take a value Related: - #31084 - #34661 - #31820 - #14739 - #20107 - fix #18875 - :get() returns `{ sbr = true, shift = '3' }` (reified-keyset) instead of `{'sbr', 'shift:3'}` - Setting via table now works too. `object_as_optval_for` `is_map` now recognizes struct options. - fix #30296 - instead of `E474: Invalid argument`, errors now look like: ``` E474: Invalid value 'x', expected one of: single, double: ambiwidth=x E474: Unknown item 'foo': diffopt=foo E474: 'context' requires a number: diffopt=context:x ``` simplify `win_float_parse_option` from #26799.
* feat(float): 'previewpopup' option #26799glepnir2026-07-23
| | | | | | | | Problem: The preview-window (:pedit, etc.) always uses a split, but it would be useful as a floatwin (or "popup"). Solution: Support Vim's 'previewpopup' option.
* refactor(:restart): unnecessary console allocation on Windows #40919Sanzhar Kuandyk2026-07-23
| | | | | | | | | | | | | | | | | | | | | | | | | Problem: `:restart` on Windows always forces `AllocConsole`, even though we could reuse old server's existing console + unnecessary env. Analysis: After d5516daf121aa718e79bcd423ee24c24492893c0 changed the restart lifecycle and 789741bb83d1f31b7162cd8944bc2d846fa2fa51 separated the Windows console paths, we no longer need to force `AllocConsole()` for `:restart`. The `:detach` path now allocates its own console when it actually runs. Solution: Try to attach the replacement server to its parent’s console and fall back to `AllocConsole()` if attachment fails. Drop the restart-specific env that forced allocation. As documented by Microsoft, [“A console is closed when the last process attached to it terminates or calls `FreeConsole`.”](https://learn.microsoft.com/en-us/windows/console/attachconsole) Btw, this way we can preserve `io.stdout:write()`, though if for some reason `AttachConsole` would fail then it won't work; but now at least it's not always not rendering on `:restart`.
* refactor(path): path_has_wildcard() #40893tao2026-07-22
| | | | | | | | | | | Problem: Redundant code. Solution: Combine path_has_wildcard() and path_has_exp_wildcard(). They have similar logic. Also, the latter operates on whatever wildcards remain after shell/env/backtick expansion, so the two felt somewhat related. Also drop some unnecessary MB_PTR_ADV calls.
* vim-patch:9.2.0827: :startinsert enters Insert mode in a non-modifiable ↵zeertzjq2026-07-22
| | | | | | | | | | | | | | | | | | | buffer (#40906) Problem: ":startinsert" enters Insert mode in a buffer where 'modifiable' is off, the error only appears when a character is typed. Typing "i" gives the error right away (Barrett Ruth) Solution: Give the error when the buffer is not modifiable, like "i" does. Keep ignoring the command in a terminal window, where ":startinsert" is documented to be ineffective, and keep accepting it when 'insertmode' is set, like "i" does (Hirohito Higashi). fixes: vim/vim#20804 closes: vim/vim#20806 https://github.com/vim/vim/commit/6ab1976e49135c0d03b06e3cddd26dc86edff085 Co-authored-by: Hirohito Higashi <h.east.727@gmail.com>
* fix(restart): distinguish v:exitreason for :restart! #40801Barrett Ruth2026-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.
* fix(restart): messages EXX error codes #40759Olivia Kinnear2026-07-17
|
* refactor(globals): group Visual-mode globals in VisualState #40777Justin M. Keyes2026-07-16
|
* refactor(search): SearchStateJustin M. Keyes2026-07-16
|
* refactor(globals): group search state into SearchState structcarladams1299-lab2026-07-16
|
* refactor(core): group insert-mode globals in `InsState` #40712Justin M. Keyes2026-07-13
| | | | | | | | | Problem: Insert-mode globals are scattered. Solution: Group them into one struct. Besides improving readability and discoverability, this greatly helps with save/restore of an insert-mode session.
* fix(coverity): RESOURCE_LEAK, USE_AFTER_FREEJustin M. Keyes2026-07-13
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | /src/nvim/ex_docmd.c: 5033 in ex_restart() 5027 // The address after --listen may be in use by the current server. 5028 if (i > 0 && strequal(arg, "--listen")) { 5029 const listitem_T *next_li = li->li_next; 5030 if (next_li != NULL) { 5031 const char *addr = tv_get_string(TV_LIST_ITEM_TV(next_li)); 5032 if (strstr(addr, ":") || strstr(addr, "/") || strstr(addr, "\\")) { >>> CID 649201: Resource leaks (RESOURCE_LEAK) >>> Overwriting "listen_arg" in "listen_arg = xstrdup(addr)" leaks the storage that "listen_arg" points to. 5033 listen_arg = TO_SLASH_SAVE(addr); 5034 #ifdef MSWIN 5035 // On Windows, don't pass --listen to new server (named pipe can't be reused immediately). 5036 // Instead pass the address via RPC; new server rebinds after startup. 5037 li = next_li; 5038 continue; *** CID 649200: Memory - illegal accesses (USE_AFTER_FREE) /src/nvim/eval/fs.c: 228 in modify_fname() 222 223 // ":h" - head, remove "/file_name", can be repeated 224 // Don't remove the logical root, see `FileInfo`. 225 while (src[*usedlen] == ':' && src[*usedlen + 1] == 'h') { 226 valid |= VALID_HEAD; 227 *usedlen += 2; >>> CID 649200: Memory - illegal accesses (USE_AFTER_FREE) >>> Using freed pointer "s". 228 while (tail > s && after_pathsep(s, tail)) { 229 MB_PTR_BACK(*fnamep, tail); 230 } 231 *fnamelen = tail <= s ? (size_t)(s - *fnamep) : (size_t)(tail - *fnamep); 232 if (*fnamelen == 0) { 233 // Result is empty. Turn it into "." to make ":cd %:h" work.
* 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>
* refactor(insert): rename edit.c => insert.c #40705Justin M. Keyes2026-07-12
| | |