diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.lua | 1 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 38 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 96 | ||||
-rw-r--r-- | src/nvim/testdir/test_cd.vim | 41 |
4 files changed, 133 insertions, 43 deletions
diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 70aa2bb1f8..dfc51d80af 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -72,6 +72,7 @@ return { chansend={args=2}, char2nr={args={1, 2}, base=1}, charidx={args={2, 3}}, + chdir={args=1, base=1}, cindent={args=1, base=1}, clearmatches={args={0, 1}, base=1}, col={args=1, base=1}, diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index da129c1170..fd3353e18b 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -28,6 +28,7 @@ #include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/globals.h" #include "nvim/if_cscope.h" #include "nvim/indent.h" #include "nvim/indent_c.h" @@ -1062,6 +1063,43 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, FunPtr fptr) rettv->vval.v_number = len > 0 ? len - 1 : 0; } +// "chdir(dir)" function +static void f_chdir(typval_T *argvars, typval_T *rettv, FunPtr fptr) +{ + char_u *cwd; + CdScope scope = kCdScopeGlobal; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = NULL; + + if (argvars[0].v_type != VAR_STRING) { + return; + } + + // Return the current directory + cwd = xmalloc(MAXPATHL); + if (cwd != NULL) { + if (os_dirname(cwd, MAXPATHL) != FAIL) { +#ifdef BACKSLASH_IN_FILENAME + slash_adjust(cwd); +#endif + rettv->vval.v_string = vim_strsave(cwd); + } + xfree(cwd); + } + + if (curwin->w_localdir != NULL) { + scope = kCdScopeWindow; + } else if (curtab->tp_localdir != NULL) { + scope = kCdScopeTab; + } + + if (!changedir_func(argvars[0].vval.v_string, scope)) { + // Directory change failed + XFREE_CLEAR(rettv->vval.v_string); + } +} + /* * "cindent(lnum)" function */ diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index cc30557ead..9191c2590c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7753,51 +7753,68 @@ void post_chdir(CdScope scope, bool trigger_dirchanged) } } -/// `:cd`, `:tcd`, `:lcd`, `:chdir`, `:tchdir` and `:lchdir`. -void ex_cd(exarg_T *eap) +/// Change directory function used by :cd/:tcd/:lcd Ex commands and the chdir() function. +/// @return true if the directory is successfully changed. +bool changedir_func(char_u *new_dir, CdScope scope) { - char_u *new_dir; char_u *tofree; + bool retval = false; - new_dir = eap->arg; -#if !defined(UNIX) - // for non-UNIX ":cd" means: print current directory - if (*new_dir == NUL) { - ex_pwd(NULL); - } else -#endif - { - if (allbuf_locked()) { - return; - } + if (allbuf_locked()) { + return false; + } - // ":cd -": Change to previous directory - if (STRCMP(new_dir, "-") == 0) { - if (prev_dir == NULL) { - EMSG(_("E186: No previous directory")); - return; - } - new_dir = prev_dir; + // ":cd -": Change to previous directory + if (STRCMP(new_dir, "-") == 0) { + if (prev_dir == NULL) { + EMSG(_("E186: No previous directory")); + return false; } + new_dir = prev_dir; + } - // Save current directory for next ":cd -" - tofree = prev_dir; - if (os_dirname(NameBuff, MAXPATHL) == OK) { - prev_dir = vim_strsave(NameBuff); - } else { - prev_dir = NULL; - } + // Save current directory for next ":cd -" + tofree = prev_dir; + if (os_dirname(NameBuff, MAXPATHL) == OK) { + prev_dir = vim_strsave(NameBuff); + } else { + prev_dir = NULL; + } #if defined(UNIX) - // On Unix ":cd" means: go to home directory. - if (*new_dir == NUL) { - // Use NameBuff for home directory name. - expand_env((char_u *)"$HOME", NameBuff, MAXPATHL); - new_dir = NameBuff; - } + // On Unix ":cd" means: go to home directory. + if (*new_dir == NUL) { + // Use NameBuff for home directory name. + expand_env((char_u *)"$HOME", NameBuff, MAXPATHL); + new_dir = NameBuff; + } #endif - CdScope scope = kCdScopeGlobal; // Depends on command invoked + bool dir_differs = prev_dir == NULL || pathcmp((char *)prev_dir, (char *)new_dir, -1) != 0; + if (dir_differs && vim_chdir(new_dir)) { + EMSG(_(e_failed)); + } else { + post_chdir(scope, dir_differs); + retval = true; + } + xfree(tofree); + + return retval; +} + +/// ":cd", ":tcd", ":lcd", ":chdir", "tchdir" and ":lchdir". +void ex_cd(exarg_T *eap) +{ + char_u *new_dir; + new_dir = eap->arg; +#if !defined(UNIX) && !defined(VMS) + // for non-UNIX ":cd" means: print current directory + if (*new_dir == NUL) { + ex_pwd(NULL); + } else +#endif + { + CdScope scope = kCdScopeGlobal; switch (eap->cmdidx) { case CMD_tcd: case CMD_tchdir: @@ -7810,19 +7827,12 @@ void ex_cd(exarg_T *eap) default: break; } - - bool dir_differs = prev_dir == NULL || pathcmp((char *)prev_dir, (char *)new_dir, -1) != 0; - if (dir_differs && vim_chdir(new_dir)) { - EMSG(_(e_failed)); - } else { - post_chdir(scope, dir_differs); + if (changedir_func(new_dir, scope)) { // Echo the new current directory if the command was typed. if (KeyTyped || p_verbose >= 5) { ex_pwd(eap); } } - - xfree(tofree); } } diff --git a/src/nvim/testdir/test_cd.vim b/src/nvim/testdir/test_cd.vim index 02a23bf82f..7500c35563 100644 --- a/src/nvim/testdir/test_cd.vim +++ b/src/nvim/testdir/test_cd.vim @@ -69,6 +69,47 @@ func Test_cd_with_cpo_chdir() bw! endfunc +" Test for chdir() +func Test_chdir_func() + let topdir = getcwd() + call mkdir('Xdir/y/z', 'p') + + " Create a few tabpages and windows with different directories + new + cd Xdir + tabnew + tcd y + below new + below new + lcd z + + tabfirst + call chdir('..') + call assert_equal('y', fnamemodify(getcwd(1, 2), ':t')) + call assert_equal('z', fnamemodify(getcwd(3, 2), ':t')) + tabnext | wincmd t + call chdir('..') + call assert_equal('Xdir', fnamemodify(getcwd(1, 2), ':t')) + call assert_equal('Xdir', fnamemodify(getcwd(2, 2), ':t')) + call assert_equal('z', fnamemodify(getcwd(3, 2), ':t')) + call assert_equal('testdir', fnamemodify(getcwd(1, 1), ':t')) + 3wincmd w + call chdir('..') + call assert_equal('Xdir', fnamemodify(getcwd(1, 2), ':t')) + call assert_equal('Xdir', fnamemodify(getcwd(2, 2), ':t')) + call assert_equal('y', fnamemodify(getcwd(3, 2), ':t')) + call assert_equal('testdir', fnamemodify(getcwd(1, 1), ':t')) + + " Error case + call assert_fails("call chdir('dir-abcd')", 'E472:') + silent! let d = chdir("dir_abcd") + call assert_equal("", d) + + only | tabonly + exe 'cd ' . topdir + call delete('Xdir', 'rf') +endfunc + func Test_cd_from_non_existing_dir() CheckNotMSWindows |