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`. --- src/nvim/eval.lua | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'src/nvim/eval.lua') diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 4df067481e..3181857b53 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -1265,8 +1265,8 @@ M.funcs = { 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| @@ -4101,23 +4101,27 @@ M.funcs = { 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 @@ -5435,8 +5439,9 @@ M.funcs = { 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