aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/buffer.c
Commit message (Collapse)AuthorAge
* refactor(charset)!: delete 'isprint' and cleanup 'iskeyword' and friendsbfredl2026-09-22
| | | | | | | | | | | | | In the `enc=utf-8` only world, the 'isprint' option is quite obsolete. The function is only consulted for decoded U+0080 to U+00FF chars whose printability is defined by the unicode charset, just like higher codepoints. Meanwhile, invalid `\x80` to `\xFF` bytes are always unprintable. Disentangle 'iskeyword', 'isfname' and 'isident' from each other by giving them all separate bitsets. Now these can be updated individually. These updaters can back out of errors gracefully, no need for extra panic logic in option[str].c to restore partially updated chartabs.
* refactor(option): simplify error buffer handlingLewis Russell2026-09-21
| | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Option validators and setters repeatedly pass error buffers and their sizes separately. Some setters return messages in static storage. Solution: - Add CharBuf for borrowed writable storage, with its length including space for a terminating NUL. - Move option error buffers to the callers that report errors. Preserve existing buffer sizes, truncation, and calls that do not need a message. - Consolidate option error formatting and the duplicated code that lists valid option values. - Return error messages directly from do_one_set_option(). - Remove unused arguments from get_option_newval() and set_option_value_for(). - Handle legacy TTY assignments in the existing callers and remove the redundant compatibility wrapper. - Reuse CharBuf for Tree-sitter query errors. - Pass CharBuf through the statusline and statuscolumn builders, retaining the buffer sizes provided by their callers, including title formatting. AI-assisted
* vim-patch:9.2.1091: memory leak for 'completeslash' on MS-Windows (#41891)zeertzjq2026-09-13
| | | | | | | | | | | | | | | | Problem: buf_copy_options() allocates the buffer-local value of 'completeslash' with vim_strsave(), but free_buf_options() does not clear b_p_csl. The previous value is lost every time a buffer's options are copied again, and once more when the buffer is freed. Only built when BACKSLASH_IN_FILENAME is defined. Solution: Clear b_p_csl in free_buf_options(), next to b_p_cpt, where buf_copy_options() also puts it (dyingc). closes: vim/vim#21290 https://github.com/vim/vim/commit/dfe8124814ca9e65369afa5d1e32fcaa323ac76a Co-authored-by: dyingc <dyingc@hotmail.com>
* 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.
* 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().
* 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.
* fix(cwd): keep buffer-local dir when re-editing #41215Justin M. Keyes2026-08-07
| | | | | | | | | | | Problem: Re-editing a buffer (`:edit!`, re-reading a dir.lua buffer, etc.) drops its `:bcd` directory, so the CWD falls back to the global one. Whereas other buffer-local state (`b:` vars, local options) survives a reload. Solution: Don't clear buf dir in `buf_freeall()`; `do_ecmd()` calls that when reloading/re-editing. `free_buffer_stuff()` still clears them when a buffer is freed or reused for another file.
* fix(:bcd): do not "inherit" buffer-local dirJustin M. Keyes2026-08-04
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: Buffer-local CWD (:bcd) is "sticky", similar to window-local CWD (:lcd). But this contradicts one of its main benefits: per-buffer "project root" for LSP, OSC7. Other problems: - A buffer created with :edit/:enew/:new silently inherits b_localdir (and b_prevdir) from the previous buffer. - curbuf_reusable() refuses to recycle a scratch buffer that has `b_localdir`. - After :new/:vnew/:tabnew the CWD sticks to previous buffer's `b_localdir` even though the new curbuf has none, so :new is not equivalent to ":split | enew", and getcwd() disagrees with haslocaldir(). - Requires "which buffer spawned this buffer" semantics that no other buffer-local state has. Solution: Drop sticky/inherit behavior of buffer-local CWD (:bcd). - do_ecmd: always apply the new curbuf's dir (`fix_current_dir`), like `do_autochdir` already does. :tabnew from a :bcd buffer now reverts to global CWD (and fires DirChanged), same as :tabnew from a :lcd window. - curbuf_reusable(): recycling a scratch buffer frees its b_localdir. To get sticky/inherit behavior of CWD, use `:lcd`.
* 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>
* vim-patch:9.2.0882: :bwipe crashes if WinLeave wipes all other buffers (#41082)zeertzjq2026-07-31
| | | | | | | | | | Problem: :bwipe crashes if WinLeave wipes all other buffers (after 9.1.2068). Solution: Check for NULL pointer. related: neovim/neovim#41066 closes: vim/vim#20888 https://github.com/vim/vim/commit/3e4019a082701f48bb44de0cc7a92f6a3077bd4e
* 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>
* 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(globals): group Visual-mode globals in VisualState #40777Justin M. Keyes2026-07-16
|
* fix(dir): let 3P dir-browser plugin rename the dir buffer #40529Barrett Ruth2026-07-13
| | | | | | | | | | | | | | | | | | | Problem: `FileType directory` fires *before* the `BufEnter` path where `dir.lua` populates the buffer, in order to allow a 3P dir-browser plugin to handle the event and (optionally) rename the buffer to e.g. `example:///tmp/foo/`. But currently, `open_buffer()` continues after `filetypedetect BufRead` as if the original directory buffer is *still* current and valid, which may fall through to the built-in `nvim.dir` path after a 3P plugin ALREADY handled the directory. Solution: Keep a buf ref around the early `filetypedetect BufRead` call for directory buffers. If the `FileType directory` handler switches away from/deletes the original directory buffer, stop the open path instead of continuing into the built-in `nvim.dir` flow.
* 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(input): rename getchar.c => input.c #40698Justin M. Keyes2026-07-12
| | | | | | | | | | | | 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.
* refactor(ctx): drop switch_win/restore_win #40693Justin M. Keyes2026-07-11
|
* refactor(ctx): drop aucmd_prepbuf/aucmd_restbuf #40692Justin M. Keyes2026-07-11
|
* fix(filetype): ensure directory bufname ends w/ slash sep #40552Barrett Ruth2026-07-10
| | | | | | | | | | | | Problem: `vim.filetype.match()` needs a cheap way to recognize directory buffers without doing filesystem stat work. Solution: Ensure full buffer names for directories end in a trailing slash. Now directory buffers can proceed through the normal 'filetype' path. Note side-effects: session and ShaDa buffer-list restore behavior must be compatible, so those + corresponding tests must be updated.
* refactor: unify context-switching conceptsJustin M. Keyes2026-07-10
|
* 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).
* vim-patch:9.2.0581: After maximizing and deleting the quickfix buffer, ↵zeertzjq2026-06-02
| | | | | | | | | | | | | | | window height is wrong (#40092) Problem: After maximizing and deleting the quickfix buffer, window height is wrong (tertium) Solution: Reset the winfixheight option when a quickfix buffer is deleted from a window (Yegappan Lakshmanan) fixes: vim/vim#3378 closes: vim/vim#20403 https://github.com/vim/vim/commit/07f055f5790cd57b83532928d8e74c1eabe45e5f Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
* docs: misc, options, pos/rangeJustin M. Keyes2026-05-30
|
* fix(float): simplify :bufdelete focus retry #39928glepnir2026-05-21
| | | | | | | | | | | | Problem: Followup to #39858. close_windows returned a holder window just so do_buffer_ext could retry there, but the non-float branch was dead code and close_windows was called twice. Solution: Check one_window directly in do_buffer_ext, drop the holder, make close_windows void again. Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
* fix(float): :bufdelete in floatwin may change focus #39858glepnir2026-05-21
| | | | | | | | | | Problem: (Followup to 54f22a8f01c0feb27a531b52aedf5cdbd5e51b24.) Deleting another buffer from a floatwin could move focus into the holder window and fire BufEnter for the buffer being deleted. Solution: Use switch_win_noblock() instead of buf_jump_open_win() before recursing into do_buffer_ext().
* vim-patch:9.2.0506: home_replace() function can be improved (#39925)zeertzjq2026-05-21
| | | | | | | | | | | | | | | | Problem: home_replace() function can be improved Solution: Refactor home_replace() to return the length of the string (John Marriott). In addition: - in function set_b0_fname() move ulen into the block where it is used. - In function findswapname() rework logic around displaying "swap file already exists" dialogue so that literal message text is set once. closes: vim/vim#20249 https://github.com/vim/vim/commit/a0931a90eeee6692556f330b5ba1fb413f9ea85d Co-authored-by: John Marriott <basilisk@internode.on.net>
* refactor: simplify aucmd_restbuf usage #39879Justin M. Keyes2026-05-19
| | | | | | | | Problem: `aucmd_restbuf` must be guarded in case `aucmd_prepbuf` wasn't called. Solution: Update `aucmd_restbuf` to be a no-op if `aucmd_prepbuf` wasn't called. This requires `aco` to be zero-initialized.
* fix(excmd): :bufdelete may fail from floating window #39800glepnir2026-05-16
| | | | | | | | | | Problem: with a float focused and the target buf only shown in the last non-float window, do_buffer_ext goes down the buf != curbuf path. close_windows can't touch the last non-float, b_nwindows stays > 0, close_buffer is skipped, returns OK silently. Solution: if a non-float still holds buf after close_windows, jump into it and recurse. Then buf == curbuf and the existing replacement path takes over.
* fix(options): default 'titlestring' shows CWD #39233Nick Krichevsky2026-04-22
| | | | | | | Problem: In the default 'titlestring', if the containing directory is the CWD, it renders as "." Solution: Add `:p` to the titlestring.
* fix(marks): adjust marks when unloading "nofile" buffer #39118luukvbaal2026-04-18
| | | | | | | | Problem: Marks are not adjusted unloading a buffer that doesn't exist on disk. E.g. extmarks are still valid (and will be beyond the end of the buffer if the buffer is reloaded), even though the text is lost. Solution: Adjust marks for a cleared buffer when unloading a buffer that doesn't exist on disk.
* build: update clang v21, fix warningsdundargoc2026-04-14
| | | | | - `src/nvim/ex_cmds_defs.h`: use "U" instead of "u" per `readability-uppercase-literal-suffix`
* vim-patch:9.2.0232: fileinfo not shown after :bd of last listed buffer (#38453)zeertzjq2026-03-31
| | | | | | | | | | | | | | | | | | | | | | Problem: fileinfo not shown after :bd of last listed buffer (memeplex) Solution: Set need_fileinfo to true in empty_curbuf() (Hirohito Higashi) When deleting the last listed buffer with :bd, the new empty buffer's file info (e.g. "[No Name]" --No lines in buffer--) was not displayed. do_ecmd() only calls fileinfo() for existing buffers (oldbuf), not for newly created empty buffers. Set need_fileinfo in empty_curbuf() so the file info is displayed after redraw. fixes: vim/vim#548 closes: vim/vim#19802 https://github.com/vim/vim/commit/3d472d86753c451ce6914f70161ffc40ee37ea96 Co-authored-by: Hirohito Higashi <h.east.727@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(buffer.c): fix coverity warning (#38589)zeertzjq2026-03-30
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The NULL checks added in #35679 are no longer needed after #38473. _____________________________________________________________________________________________ *** CID 645258: (REVERSE_INULL) /src/nvim/buffer.c: 645 in close_buffer() 639 // Autocommands deleted the buffer. 640 emsg(_(e_auabort)); 641 return false; 642 } 643 buf->b_locked--; 644 buf->b_locked_split--; >>> CID 645258: (REVERSE_INULL) >>> Null-checking "win" suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 645 if (abort_if_last && win != NULL && one_window(win, NULL)) { 646 // Autocommands made this the only window. 647 emsg(_(e_auabort)); 648 return false; 649 } 650 } /src/nvim/buffer.c: 626 in close_buffer() 620 // Autocommands deleted the buffer. 621 emsg(_(e_auabort)); 622 return false; 623 } 624 buf->b_locked--; 625 buf->b_locked_split--; >>> CID 645258: (REVERSE_INULL) >>> Null-checking "win" suggests that it may be null, but it has already been dereferenced on all paths leading to the check. 626 if (abort_if_last && win != NULL && one_window(win, NULL)) { 627 // Autocommands made this the only window. 628 emsg(_(e_auabort)); 629 return false; 630 } 631
* vim-patch:9.2.0254: w_locked can be bypassed when setting recursivelySean Dewar2026-03-29
| | | | | | | | | | | | | | | | Problem: w_locked can be bypassed when recursively set if not restored to its prior value. Solution: Rather than save/restore everywhere, just make it a count, like other locks (Sean Dewar) Requires the previous commit, otherwise b_nwindows will be wrong in tests, which causes a bunch of weird failures. closes: vim/vim#19728 https://github.com/vim/vim/commit/7cb43f286e55853cf21b9d8870a430390c1cc8f1 Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
* vim-patch:9.2.0253: various issues with wrong b_nwindows after closing buffersSean Dewar2026-03-29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Problem: close_buffer() callers incorrectly handle b_nwindows, especially after nasty autocmds, allowing it to go out-of-sync. May lead to buffers that can't be unloaded, or buffers that are prematurely freed whilst displayed. Solution: Modify close_buffer() and review its callers; let them decrement b_nwindows if it didn't unload the buffer. Remove some now unneeded workarounds like 8.2.2354, 9.1.0143, 9.1.0764, which didn't always work (Sean Dewar) (endless yapping omitted) related: vim/vim#19728 https://github.com/vim/vim/commit/bf21df1c7bc772e3a29961c961d0821584d50ee0 b_nwindows = 0 change for free_all_mem() was already ported. Originally Nvim returned true when b_nwindows was decremented before the end was reached (to better indicate the decrement). That's not needed anymore, so just return true only at the end, like Vim. (retval isn't used anywhere now anyways) Set textlock for dict watchers at the end of close_buffer() to prevent them from switching windows, as that can leave a window with a NULL buffer. (possible before this PR, but the new assert catches it; added a test) Despite textlock, things still aren't ideal, as watchers may observe the buffer as unloaded and hidden (b_nwindows was decremented), yet still in a window... Likewise, for Nvim, wipe_qf_buffer()'s comment may not be entirely accurate; autocmds are blocked, but on_detach callbacks (textlocked) and dict watchers may still run. Might be problematic, but those aren't new issues. Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
* vim-patch:9.2.0252: Crash when ending Visual mode after curbuf was unloadedSean Dewar2026-03-29
| | | | | | | | | | | | | | | | | | | | | Problem: if close_buffer() in set_curbuf() unloads curbuf, NULL pointer accesses may occur from enter_buffer() calling end_visual_mode(), as curbuf is already abandoned and possibly unloaded. Also, selection registers may not contain the selection with clipboard+=autoselect(plus). Solution: Move close_buffer()'s end_visual_mode() call to buf_freeall(), after any autocmds that may restart it, but just before freeing anything (Sean Dewar) related: vim/vim#19728 https://github.com/vim/vim/commit/a8fdfd4fcb92b9fcbed3ad0a6769cb6bad34d965 Maybe this should be considered partial? clipboard+=autoselect isn't implemented. If it is, we may need to update these comments to mention TextYankPost being possible, and unskip its test. Co-authored-by: Sean Dewar <6256228+seandewar@users.noreply.github.com>
* feat(prompt): prompt_appendbuf() appends to prompt buffer #37763Shadman2026-03-27
| | | | | | | | | | | Problem: Currently, we recommend always inserting text above prompt-line in prompt-buffer. This can be done using the `:` mark. However, although we recommend it this way it can sometimes get confusing how to do it best. Solution: Provide an api to append text to prompt buffer. This is a common use-case for things using prompt-buffer.
* fix: :ball w_locked check, reset b_nwindows in free_all_mem() #38484Sean Dewar2026-03-25
| | | | | | | | | | | | | |