vim-patch:9.1.1605: cannot specify scope for chdir() (#35239)

Problem:  Cannot specify scope for chdir()
Solution: Add optional scope argument (kuuote)

closes: vim/vim#17888

8a65a49d50

Co-authored-by: kuuote <znmxodq1@gmail.com>
This commit is contained in:
zeertzjq
2025-08-08 21:50:41 +08:00
committed by GitHub
parent 36361d6e4a
commit 798cb0f19a
6 changed files with 79 additions and 33 deletions

View File

@@ -302,6 +302,7 @@ UI
VIMSCRIPT VIMSCRIPT
• |chdir()| allows optionally specifying a scope argument.
• |cmdcomplete_info()| gets current cmdline completion info. • |cmdcomplete_info()| gets current cmdline completion info.
• |getcompletiontype()| gets command-line completion type for any string. • |getcompletiontype()| gets command-line completion type for any string.
• |prompt_getinput()| gets current user-input in prompt-buffer. • |prompt_getinput()| gets current user-input in prompt-buffer.

View File

@@ -1008,16 +1008,23 @@ charidx({string}, {idx} [, {countcc} [, {utf16}]]) *charidx()*
Return: ~ Return: ~
(`integer`) (`integer`)
chdir({dir}) *chdir()* chdir({dir} [, {scope}]) *chdir()*
Change the current working directory to {dir}. The scope of Changes the current working directory to {dir}. The scope of
the directory change depends on the directory of the current the change is determined as follows:
window: If {scope} is not present, the current working directory is
- If the current window has a window-local directory changed to the scope of the current directory:
(|:lcd|), then changes the window local directory. - If the window local directory (|:lcd|) is set, it
- Otherwise, if the current tabpage has a local changes the current working directory for that scope.
directory (|:tcd|) then changes the tabpage local - Otherwise, if the tab page local directory (|:tcd|) is
directory. set, it changes the current directory for that scope.
- Otherwise, changes the global directory. - Otherwise, changes the global directory for that scope.
If {scope} is present, changes the current working directory
for the specified scope:
"window" Changes the window local directory. |:lcd|
"tabpage" Changes the tab page local directory. |:tcd|
"global" Changes the global directory. |:cd|
{dir} must be a String. {dir} must be a String.
If successful, returns the previous working directory. Pass If successful, returns the previous working directory. Pass
this to another chdir() to restore the directory. this to another chdir() to restore the directory.
@@ -1033,6 +1040,7 @@ chdir({dir}) *chdir()*
Parameters: ~ Parameters: ~
• {dir} (`string`) • {dir} (`string`)
• {scope} (`string?`)
Return: ~ Return: ~
(`string`) (`string`)

View File

@@ -873,15 +873,22 @@ function vim.fn.charcol(expr, winid) end
--- @return integer --- @return integer
function vim.fn.charidx(string, idx, countcc, utf16) end function vim.fn.charidx(string, idx, countcc, utf16) end
--- Change the current working directory to {dir}. The scope of --- Changes the current working directory to {dir}. The scope of
--- the directory change depends on the directory of the current --- the change is determined as follows:
--- window: --- If {scope} is not present, the current working directory is
--- - If the current window has a window-local directory --- changed to the scope of the current directory:
--- (|:lcd|), then changes the window local directory. --- - If the window local directory (|:lcd|) is set, it
--- - Otherwise, if the current tabpage has a local --- changes the current working directory for that scope.
--- directory (|:tcd|) then changes the tabpage local --- - Otherwise, if the tab page local directory (|:tcd|) is
--- directory. --- set, it changes the current directory for that scope.
--- - Otherwise, changes the global directory. --- - Otherwise, changes the global directory for that scope.
---
--- If {scope} is present, changes the current working directory
--- for the specified scope:
--- "window" Changes the window local directory. |:lcd|
--- "tabpage" Changes the tab page local directory. |:tcd|
--- "global" Changes the global directory. |:cd|
---
--- {dir} must be a String. --- {dir} must be a String.
--- If successful, returns the previous working directory. Pass --- If successful, returns the previous working directory. Pass
--- this to another chdir() to restore the directory. --- this to another chdir() to restore the directory.
@@ -896,8 +903,9 @@ function vim.fn.charidx(string, idx, countcc, utf16) end
--- < --- <
--- ---
--- @param dir string --- @param dir string
--- @param scope? string
--- @return string --- @return string
function vim.fn.chdir(dir) end function vim.fn.chdir(dir, scope) end
--- Get the amount of indent for line {lnum} according the --- Get the amount of indent for line {lnum} according the
--- |C-indenting| rules, as with 'cindent'. --- |C-indenting| rules, as with 'cindent'.

View File

@@ -1190,18 +1190,25 @@ M.funcs = {
signature = 'charidx({string}, {idx} [, {countcc} [, {utf16}]])', signature = 'charidx({string}, {idx} [, {countcc} [, {utf16}]])',
}, },
chdir = { chdir = {
args = 1, args = { 1, 2 },
base = 1, base = 1,
desc = [=[ desc = [=[
Change the current working directory to {dir}. The scope of Changes the current working directory to {dir}. The scope of
the directory change depends on the directory of the current the change is determined as follows:
window: If {scope} is not present, the current working directory is
- If the current window has a window-local directory changed to the scope of the current directory:
(|:lcd|), then changes the window local directory. - If the window local directory (|:lcd|) is set, it
- Otherwise, if the current tabpage has a local changes the current working directory for that scope.
directory (|:tcd|) then changes the tabpage local - Otherwise, if the tab page local directory (|:tcd|) is
directory. set, it changes the current directory for that scope.
- Otherwise, changes the global directory. - Otherwise, changes the global directory for that scope.
If {scope} is present, changes the current working directory
for the specified scope:
"window" Changes the window local directory. |:lcd|
"tabpage" Changes the tab page local directory. |:tcd|
"global" Changes the global directory. |:cd|
{dir} must be a String. {dir} must be a String.
If successful, returns the previous working directory. Pass If successful, returns the previous working directory. Pass
this to another chdir() to restore the directory. this to another chdir() to restore the directory.
@@ -1217,9 +1224,9 @@ M.funcs = {
]=], ]=],
name = 'chdir', name = 'chdir',
params = { { 'dir', 'string' } }, params = { { 'dir', 'string' }, { 'scope', 'string' } },
returns = 'string', returns = 'string',
signature = 'chdir({dir})', signature = 'chdir({dir} [, {scope}])',
}, },
cindent = { cindent = {
args = 1, args = 1,

View File

@@ -74,7 +74,19 @@ void f_chdir(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
xfree(cwd); xfree(cwd);
CdScope scope = kCdScopeGlobal; CdScope scope = kCdScopeGlobal;
if (curwin->w_localdir != NULL) { if (argvars[1].v_type != VAR_UNKNOWN) {
const char *s = tv_get_string(&argvars[1]);
if (strcmp(s, "global") == 0) {
scope = kCdScopeGlobal;
} else if (strcmp(s, "tabpage") == 0) {
scope = kCdScopeTabpage;
} else if (strcmp(s, "window") == 0) {
scope = kCdScopeWindow;
} else {
semsg(_(e_invargNval), "scope", s);
return;
}
} else if (curwin->w_localdir != NULL) {
scope = kCdScopeWindow; scope = kCdScopeWindow;
} else if (curtab->tp_localdir != NULL) { } else if (curtab->tp_localdir != NULL) {
scope = kCdScopeTabpage; scope = kCdScopeTabpage;

View File

@@ -99,10 +99,20 @@ func Test_chdir_func()
call assert_equal('y', fnamemodify(getcwd(3, 2), ':t')) call assert_equal('y', fnamemodify(getcwd(3, 2), ':t'))
call assert_equal('testdir', fnamemodify(getcwd(1, 1), ':t')) call assert_equal('testdir', fnamemodify(getcwd(1, 1), ':t'))
" Forcing scope
call chdir('.', 'global')
call assert_match('^\[global\]', trim(execute('verbose pwd')))
call chdir('.', 'tabpage')
call assert_match('^\[tabpage\]', trim(execute('verbose pwd')))
call chdir('.', 'window')
call assert_match('^\[window\]', trim(execute('verbose pwd')))
" Error case " Error case
call assert_fails("call chdir('dir-abcd')", 'E344:') call assert_fails("call chdir('dir-abcd')", 'E344:')
silent! let d = chdir("dir_abcd") silent! let d = chdir("dir_abcd")
call assert_equal("", d) call assert_equal("", d)
call assert_fails("call chdir('.', v:_null_string)", 'E475:')
call assert_fails("call chdir('.', [])", 'E730:')
" Should not crash " Should not crash
call chdir(d) call chdir(d)
call assert_equal('', chdir([])) call assert_equal('', chdir([]))