From 9cd4dd1c1934b21cf4acc7950da6b2b811c41b71 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Tue, 4 Aug 2026 17:13:32 +0200 Subject: fix(:bcd): do not "inherit" buffer-local dir 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`. --- runtime/lua/vim/_meta/options.gen.lua | 6 +++--- runtime/lua/vim/_meta/vimfn.gen.lua | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 12 deletions(-) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/_meta/options.gen.lua b/runtime/lua/vim/_meta/options.gen.lua index dd2d1a7468..6932bbfca5 100644 --- a/runtime/lua/vim/_meta/options.gen.lua +++ b/runtime/lua/vim/_meta/options.gen.lua @@ -734,7 +734,7 @@ vim.o.cmp = vim.o.casemap vim.go.casemap = vim.o.casemap vim.go.cmp = vim.go.casemap ---- When on, `:cd`, `:tcd` and `:lcd` without an argument changes the +--- When on, `:cd`, `:tcd`, `:lcd` and `:bcd` without an argument changes the --- current working directory to the `$HOME` directory like in Unix. --- When off, those commands just print the current directory name. --- @@ -745,7 +745,7 @@ vim.go.cdhome = vim.o.cdhome vim.go.cdh = vim.go.cdhome --- This is a list of directories which will be searched when using the ---- `:cd`, `:tcd` and `:lcd` commands, provided that the directory being +--- `:cd`, `:tcd`, `:lcd` and `:bcd` commands, provided that the directory being --- searched for has a relative path, not an absolute part starting with --- "/", "./" or "../", the 'cdpath' option is not used then. --- The 'cdpath' option's value has the same form and semantics as @@ -1572,7 +1572,7 @@ vim.bo.ci = vim.bo.copyindent --- following occurrence. --- *cpo-~* --- ~ When included, don't resolve symbolic links when ---- changing directory with `:cd`, `:lcd`, or `:tcd`. +--- changing directory with `:cd`, `:tcd`, `:lcd`, or `:bcd`. --- This preserves the symbolic link path in buffer names --- and when displaying the current directory. When --- excluded (default), symbolic links are resolved to diff --git a/runtime/lua/vim/_meta/vimfn.gen.lua b/runtime/lua/vim/_meta/vimfn.gen.lua index 1806838eb4..8444b6d6f4 100644 --- a/runtime/lua/vim/_meta/vimfn.gen.lua +++ b/runtime/lua/vim/_meta/vimfn.gen.lua @@ -960,8 +960,8 @@ function vim.fn.charidx(string, idx, countcc, utf16) end --- --- If {scope} is present, changes the current working directory --- for the specified scope: ---- "window" Changes the window local directory. |:lcd| --- "buffer" Changes the buffer local directory. |:bcd| +--- "window" Changes the window local directory. |:lcd| --- "tabpage" Changes the tabpage local directory. |:tcd| --- "global" Changes the global directory. |:cd| --- @@ -3326,23 +3326,27 @@ function vim.fn.getcursorcharpos(winid) end --- is ignored. --- --- Tabs, windows and buffers are identified by their respective ---- numbers, 0 means current tab or window or buffer. Missing tab ---- number ---- implies 0. Thus the following are equivalent: >vim +--- numbers, 0 means current tab/window/buffer. Missing {tabnr} +--- implies 0 (missing {bufnr} does not; see below). Thus the +--- following are equivalent: >vim --- getcwd(0) --- getcwd(0, 0) --- vim --- getcwd(-1, -1, 0) " Get current buffer's directory --- getcwd(-1, -1, 3) " Get directory of buffer #3 @@ -4468,8 +4472,9 @@ function vim.fn.has_key(dict, key) end --- and {bufnr} has set a local path via |:bcd|, otherwise 0. --- --- Tabs, windows and buffers are identified by their respective ---- numbers, 0 means current tab, window or buffer. Missing ---- argument implies 0. Thus the following are equivalent: >vim +--- numbers, 0 means current tab/window/buffer. Missing {winnr} +--- or {tabnr} implies 0 (missing {bufnr} does not; see below). +--- Thus the following are equivalent: >vim --- echo haslocaldir() --- echo haslocaldir(0) --- echo haslocaldir(0, 0) -- cgit