summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2024-07-11 22:35:53 +0200
committerChristian Brabandt <cb@256bit.org>2024-07-11 22:45:42 +0200
commita20bf69a3b32024cb7809be87af33bf9dc490a19 (patch)
treea7d62b4c59841d2a466f82dbe26d5be861308602
parent764526e2799fbed040fc867858ee2eb0677afe98 (diff)
patch 9.1.0568: Cannot expand paths from 'cdpath' settingv9.1.0568
Problem: Cannot expand paths from 'cdpath' setting (Daniel Hahler) Solution: Implement 'cdpath' completion, add the new 'dir_in_path' completion type (LemonBoy) fixes #374 closes: #15205 Signed-off-by: LemonBoy <thatlemon@gmail.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r--runtime/doc/builtin.txt1
-rw-r--r--runtime/doc/map.txt3
-rw-r--r--runtime/doc/todo.txt3
-rw-r--r--runtime/doc/version9.txt5
-rw-r--r--runtime/syntax/vim.vim2
-rw-r--r--src/cmdexpand.c14
-rw-r--r--src/filepath.c8
-rw-r--r--src/findfile.c22
-rw-r--r--src/proto/findfile.pro2
-rw-r--r--src/testdir/test_cd.vim8
-rw-r--r--src/testdir/test_cmdline.vim3
-rw-r--r--src/usercmd.c1
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h3
14 files changed, 56 insertions, 21 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index b25bb93902..5c8d9d89b9 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -4065,6 +4065,7 @@ getcompletion({pat}, {type} [, {filtered}]) *getcompletion()*
customlist,{func} custom completion, defined via {func}
diff_buffer |:diffget| and |:diffput| completion
dir directory names
+ dir_in_path directory names in |'cdpath'|
environment environment variable names
event autocommand events
expression Vim expression
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 365f49ad19..432a98671b 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1,4 +1,4 @@
-*map.txt* For Vim version 9.1. Last change: 2024 May 05
+*map.txt* For Vim version 9.1. Last change: 2024 Jul 11
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1631,6 +1631,7 @@ completion can be enabled:
-complete=compiler compilers
-complete=cscope |:cscope| suboptions
-complete=dir directory names
+ -complete=dir_in_path directory names in |'cdpath'|
-complete=environment environment variable names
-complete=event autocommand events
-complete=expression Vim expression
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 5b15a46b8c..e0ebe7eedb 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1,4 +1,4 @@
-*todo.txt* For Vim version 9.1. Last change: 2024 Jul 04
+*todo.txt* For Vim version 9.1. Last change: 2024 Jul 11
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -539,7 +539,6 @@ SpellCap doesn't show below a closed fold. #12420
- Adding "~" to 'cdpath' doesn't work for completion? (Davido, 2013 Aug 19)
- Problem with 'cdpath' on MS-Windows when a directory is equal to $HOME.
(2006 Jul 26, Gary Johnson)
-- Completion of ":cd" doesn't use 'cdpath'. #374.
Make "g>" and "g<" in Visual mode move the text right or left.
Also for a block selection. #8558
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index cfeb28c7b9..7a2cbe4164 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.1. Last change: 2024 Jul 10
+*version9.txt* For Vim version 9.1. Last change: 2024 Jul 11
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41583,6 +41583,9 @@ Changed~
- moving in the buffer list using |:bnext| and similar commands, behaves as
documented and skips help buffers (if not run from a help buffer, else
moves to the next/previous help buffer).
+- allow to complete directories from 'cdpath' for |:cd| and similar commands,
+ add the "cd_in_path" completion type for e.g. |:command-complete| and
+ |getcompletion()|
*added-9.2*
Added ~
diff --git a/runtime/syntax/vim.vim b/runtime/syntax/vim.vim
index 8ea2c1c130..b10531e961 100644
--- a/runtime/syntax/vim.vim
+++ b/runtime/syntax/vim.vim
@@ -400,7 +400,7 @@ endif
syn case ignore
syn keyword vimUserAttrbKey contained bar ban[g] cou[nt] ra[nge] com[plete] n[args] re[gister]
" GEN_SYN_VIM: vimUserAttrbCmplt, START_STR='syn keyword vimUserAttrbCmplt contained', END_STR=''
-syn keyword vimUserAttrbCmplt contained arglist augroup behave buffer color command compiler cscope diff_buffer dir environment event expression file file_in_path filetype function help highlight history keymap locale mapclear mapping menu messages syntax syntime option packadd runtime shellcmd sign tag tag_listfiles user var breakpoint scriptnames
+syn keyword vimUserAttrbCmplt contained arglist augroup behave buffer color command compiler cscope diff_buffer dir environment event expression file file_in_path filetype function help highlight history keymap locale mapclear mapping menu messages syntax syntime option packadd runtime shellcmd sign tag tag_listfiles user var breakpoint scriptnames dir_in_path
syn keyword vimUserAttrbCmplt contained custom customlist nextgroup=vimUserAttrbCmpltFunc,vimUserCmdError
syn match vimUserAttrbCmpltFunc contained ",\%([sS]:\|<[sS][iI][dD]>\)\=\%(\h\w*\%([.#]\h\w*\)\+\|\h\w*\)"hs=s+1 nextgroup=vimUserCmdError
diff --git a/src/cmdexpand.c b/src/cmdexpand.c
index 8d8bf06b5f..0267d28e0f 100644
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -46,6 +46,7 @@ cmdline_fuzzy_completion_supported(expand_T *xp)
&& xp->xp_context != EXPAND_COLORS
&& xp->xp_context != EXPAND_COMPILER
&& xp->xp_context != EXPAND_DIRECTORIES
+ && xp->xp_context != EXPAND_DIRS_IN_CDPATH
&& xp->xp_context != EXPAND_FILES
&& xp->xp_context != EXPAND_FILES_IN_PATH
&& xp->xp_context != EXPAND_FILETYPE
@@ -107,7 +108,8 @@ wildescape(
|| xp->xp_context == EXPAND_FILES_IN_PATH
|| xp->xp_context == EXPAND_SHELLCMD
|| xp->xp_context == EXPAND_BUFFERS
- || xp->xp_context == EXPAND_DIRECTORIES)
+ || xp->xp_context == EXPAND_DIRECTORIES
+ || xp->xp_context == EXPAND_DIRS_IN_CDPATH)
{
// Insert a backslash into a file name before a space, \, %, #
// and wildmatch characters, except '~'.
@@ -1404,7 +1406,8 @@ addstar(
if (context != EXPAND_FILES
&& context != EXPAND_FILES_IN_PATH
&& context != EXPAND_SHELLCMD
- && context != EXPAND_DIRECTORIES)
+ && context != EXPAND_DIRECTORIES
+ && context != EXPAND_DIRS_IN_CDPATH)
{
// Matching will be done internally (on something other than files).
// So we convert the file-matching-type wildcards into our kind for
@@ -2138,7 +2141,7 @@ set_context_by_cmdname(
case CMD_lcd:
case CMD_lchdir:
if (xp->xp_context == EXPAND_FILES)
- xp->xp_context = EXPAND_DIRECTORIES;
+ xp->xp_context = EXPAND_DIRS_IN_CDPATH;
break;
case CMD_help:
xp->xp_context = EXPAND_HELP;
@@ -2845,6 +2848,8 @@ expand_files_and_dirs(
flags |= EW_FILE;
else if (xp->xp_context == EXPAND_FILES_IN_PATH)
flags |= (EW_FILE | EW_PATH);
+ else if (xp->xp_context == EXPAND_DIRS_IN_CDPATH)
+ flags = (flags | EW_DIR | EW_CDPATH) & ~EW_FILE;
else
flags = (flags | EW_DIR) & ~EW_FILE;
if (options & WILD_ICASE)
@@ -3098,7 +3103,8 @@ ExpandFromContext(
if (xp->xp_context == EXPAND_FILES
|| xp->xp_context == EXPAND_DIRECTORIES
- || xp->xp_context == EXPAND_FILES_IN_PATH)
+ || xp->xp_context == EXPAND_FILES_IN_PATH
+ || xp->xp_context == EXPAND_DIRS_IN_CDPATH)
return expand_files_and_dirs(xp, pat, matches, numMatches, flags,
options);
diff --git a/src/filepath.c b/src/filepath.c
index 788d3bbe5b..d514aaf8ef 100644
--- a/src/filepath.c
+++ b/src/filepath.c
@@ -4003,6 +4003,8 @@ gen_expand_wildcards(
int add_pat;
int retval = OK;
int did_expand_in_path = FALSE;
+ char_u *path_option = *curbuf->b_p_path == NUL ?
+ p_path : curbuf->b_p_path;
/*
* expand_env() is called to expand things like "~user". If this fails,
@@ -4092,7 +4094,7 @@ gen_expand_wildcards(
*/
if (mch_has_exp_wildcard(p) || (flags & EW_ICASE))
{
- if ((flags & EW_PATH)
+ if ((flags & (EW_PATH | EW_CDPATH))
&& !mch_isFullName(p)
&& !(p[0] == '.'
&& (vim_ispathsep(p[1])
@@ -4126,8 +4128,8 @@ gen_expand_wildcards(
vim_free(t);
}
- if (did_expand_in_path && ga.ga_len > 0 && (flags & EW_PATH))
- uniquefy_paths(&ga, p);
+ if (did_expand_in_path && ga.ga_len > 0 && (flags & (EW_PATH | EW_CDPATH)))
+ uniquefy_paths(&ga, p, path_option);
if (p != pat[i])
vim_free(p);
}
diff --git a/src/findfile.c b/src/findfile.c
index d1cd5f0614..4310a508c1 100644
--- a/src/findfile.c
+++ b/src/findfile.c
@@ -2211,10 +2211,11 @@ is_unique(char_u *maybe_unique, garray_T *gap, int i)
* expanding each into their equivalent path(s).
*/
static void
-expand_path_option(char_u *curdir, garray_T *gap)
+expand_path_option(
+ char_u *curdir,
+ char_u *path_option, // p_path or p_cdpath
+ garray_T *gap)
{
- char_u *path_option = *curbuf->b_p_path == NUL
- ? p_path : curbuf->b_p_path;
char_u *buf;
char_u *p;
int len;
@@ -2329,7 +2330,10 @@ get_path_cutoff(char_u *fname, garray_T *gap)
* that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len".
*/
void
-uniquefy_paths(garray_T *gap, char_u *pattern)
+uniquefy_paths(
+ garray_T *gap,
+ char_u *pattern,
+ char_u *path_option) // p_path or p_cdpath
{
int i;
int len;
@@ -2372,7 +2376,7 @@ uniquefy_paths(garray_T *gap, char_u *pattern)
if ((curdir = alloc(MAXPATHL)) == NULL)
goto theend;
mch_dirname(curdir, MAXPATHL);
- expand_path_option(curdir, &path_ga);
+ expand_path_option(curdir, path_option, &path_ga);
in_curdir = ALLOC_CLEAR_MULT(char_u *, gap->ga_len);
if (in_curdir == NULL)
@@ -2520,13 +2524,17 @@ expand_in_path(
garray_T path_ga;
char_u *paths = NULL;
int glob_flags = 0;
+ char_u *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
if ((curdir = alloc(MAXPATHL)) == NULL)
return 0;
mch_dirname(curdir, MAXPATHL);
ga_init2(&path_ga, sizeof(char_u *), 1);
- expand_path_option(curdir, &path_ga);
+ if (flags & EW_CDPATH)
+ expand_path_option(curdir, p_cdpath, &path_ga);
+ else
+ expand_path_option(curdir, path_option, &path_ga);
vim_free(curdir);
if (path_ga.ga_len == 0)
return 0;
@@ -2540,7 +2548,7 @@ expand_in_path(
glob_flags |= WILD_ICASE;
if (flags & EW_ADDSLASH)
glob_flags |= WILD_ADD_SLASH;
- globpath(paths, pattern, gap, glob_flags, FALSE);
+ globpath(paths, pattern, gap, glob_flags, !!(flags & EW_CDPATH));
vim_free(paths);
return gap->ga_len;
diff --git a/src/proto/findfile.pro b/src/proto/findfile.pro
index 95601011ac..1c28221576 100644
--- a/src/proto/findfile.pro
+++ b/src/proto/findfile.pro
@@ -12,7 +12,7 @@ char_u *file_name_at_cursor(int options, long count, linenr_T *file_lnum);
char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u *rel_fname, linenr_T *file_lnum);
char_u *find_file_name_in_path(char_u *ptr, int len, int options, long count, char_u *rel_fname);
int vim_ispathlistsep(int c);
-void uniquefy_paths(garray_T *gap, char_u *pattern);
+void uniquefy_paths(garray_T *gap, char_u *pattern, char_u *path_option);
int expand_in_path(garray_T *gap, char_u *pattern, int flags);
void simplify_filename(char_u *filename);
void f_simplify(typval_T *argvars, typval_T *rettv);
diff --git a/src/testdir/test_cd.vim b/src/testdir/test_cd.vim
index 9fb5958fe6..13a3eba370 100644
--- a/src/testdir/test_cd.vim
+++ b/src/testdir/test_cd.vim
@@ -200,12 +200,20 @@ endfunc
func Test_cd_completion()
call mkdir('XComplDir1', 'D')
call mkdir('XComplDir2', 'D')
+ call mkdir('sub/XComplDir3', 'pD')
call writefile([], 'XComplFile', 'D')
for cmd in ['cd', 'chdir', 'lcd', 'lchdir', 'tcd', 'tchdir']
call feedkeys(':' .. cmd .. " XCompl\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"' .. cmd .. ' XComplDir1/ XComplDir2/', @:)
endfor
+
+ set cdpath+=sub
+ for cmd in ['cd', 'chdir', 'lcd', 'lchdir', 'tcd', 'tchdir']
+ call feedkeys(':' .. cmd .. " XCompl\<C-A>\<C-B>\"\<CR>", 'tx')
+ call assert_equal('"' .. cmd .. ' XComplDir1/ XComplDir2/ XComplDir3/', @:)
+ endfor
+ set cdpath&
endfunc
func Test_cd_unknown_dir()
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 8651a9dbba..f83d673346 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -658,7 +658,8 @@ func Test_getcompletion()
unlet g:cmdline_compl_params
" For others test if the name is recognized.
- let names = ['buffer', 'environment', 'file_in_path', 'mapping', 'tag', 'tag_listfiles', 'user']
+ let names = ['buffer', 'environment', 'file_in_path', 'dir_in_path', 'mapping', 'tag',
+ \ 'tag_listfiles', 'user']
if has('cmdline_hist')
call add(names, 'history')
endif
diff --git a/src/usercmd.c b/src/usercmd.c
index e2c0114ca3..3f0781c4fc 100644
--- a/src/usercmd.c
+++ b/src/usercmd.c
@@ -102,6 +102,7 @@ static struct
{EXPAND_BREAKPOINT, "breakpoint"},
{EXPAND_SCRIPTNAMES, "scriptnames"},
#endif
+ {EXPAND_DIRS_IN_CDPATH, "dir_in_path"},
{0, NULL}
};
diff --git a/src/version.c b/src/version.c
index c7499bb3f5..3b4cca66d4 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 568,
+/**/
567,
/**/
566,
diff --git a/src/vim.h b/src/vim.h
index a35916246e..c022f2e7f4 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -843,6 +843,8 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define EXPAND_ARGOPT 56
#define EXPAND_TERMINALOPT 57
#define EXPAND_KEYMAP 58
+#define EXPAND_DIRS_IN_CDPATH 59
+
// Values for exmode_active (0 is no exmode)
#define EXMODE_NORMAL 1
@@ -898,6 +900,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define EW_DODOT 0x4000 // also files starting with a dot
#define EW_EMPTYOK 0x8000 // no matches is not an error
#define EW_NOTENV 0x10000 // do not expand environment variables
+#define EW_CDPATH 0x20000 // search in 'cdpath' too
// Flags for find_file_*() functions.
#define FINDFILE_FILE 0 // only files