feat(editor): :bcd changes buffer-local directory

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>
This commit is contained in:
saher
2025-04-02 18:17:15 +03:00
committed by Justin M. Keyes
parent 838f130e6a
commit ea3868bcf9
23 changed files with 940 additions and 178 deletions

View File

@@ -938,6 +938,9 @@ bool buf_freeall(buf_T *buf, int flags)
}
syntax_clear(&buf->b_s); // reset syntax info
buf->b_flags &= ~BF_READERR; // a read error is no longer relevant
XFREE_CLEAR(buf->b_localdir);
XFREE_CLEAR(buf->b_prevdir);
return true;
}
@@ -1023,6 +1026,8 @@ static void free_buffer_stuff(buf_T *buf, int free_flags)
map_clear_mode(buf, MAP_ALL_MODES, true, false); // clear local mappings
map_clear_mode(buf, MAP_ALL_MODES, true, true); // clear local abbrevs
XFREE_CLEAR(buf->b_start_fenc);
XFREE_CLEAR(buf->b_localdir);
XFREE_CLEAR(buf->b_prevdir);
buf_free_callbacks(buf);
}
@@ -1771,6 +1776,9 @@ void set_curbuf(buf_T *buf, int action, bool update_jumplist)
if (bufref_valid(&prevbufref) && prevbuf->terminal != NULL) {
terminal_check_size(prevbuf->terminal);
}
// Maybe cd to buffer-local directory
fix_current_dir(false);
}
/// Enter a new current buffer.
@@ -2023,6 +2031,8 @@ buf_T *buflist_new(char *ffname_arg, char *sfname_arg, linenr_T lnum, int flags)
trigger_undo_ftplugin(buf, curwin);
// It's like this buffer is deleted. Watch out for autocommands that
// change curbuf! If that happens, allocate a new buffer anyway.
// We also ask it to not free the buffer-local directory so we can reuse
// it.
buf_freeall(buf, BFA_WIPE | BFA_DEL);
if (aborting()) { // autocmds may abort script processing
xfree(ffname);
@@ -2152,6 +2162,8 @@ bool curbuf_reusable(void)
&& curbuf->b_ffname == NULL
&& curbuf->b_nwindows <= 1
&& !curbuf->terminal
&& curbuf->b_localdir == NULL
&& curbuf->b_prevdir == NULL
&& (curbuf->b_ml.ml_mfp == NULL || buf_is_empty(curbuf))
&& !bt_quickfix(curbuf)
&& !curbufIsChanged());