diff options
author | zeertzjq <zeertzjq@outlook.com> | 2024-07-12 07:11:54 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2024-07-12 07:39:36 +0800 |
commit | 83f42aa450582594f0be044c9f0710809ef0f93d (patch) | |
tree | 6625e078592d6139f2ebdd1de699e4f28b62050d | |
parent | f1827d877d3dece7d743e9db28384ebd5e10550c (diff) | |
download | rneovim-83f42aa450582594f0be044c9f0710809ef0f93d.tar.gz rneovim-83f42aa450582594f0be044c9f0710809ef0f93d.tar.bz2 rneovim-83f42aa450582594f0be044c9f0710809ef0f93d.zip |
vim-patch:9.1.0568: Cannot expand paths from 'cdpath' setting
Problem: Cannot expand paths from 'cdpath' setting
(Daniel Hahler)
Solution: Implement 'cdpath' completion, add the new 'dir_in_path'
completion type (LemonBoy)
fixes vim/vim#374
closes: vim/vim#15205
https://github.com/vim/vim/commit/a20bf69a3b32024cb7809be87af33bf9dc490a19
Co-authored-by: LemonBoy <thatlemon@gmail.com>
-rw-r--r-- | runtime/doc/builtin.txt | 1 | ||||
-rw-r--r-- | runtime/doc/map.txt | 1 | ||||
-rw-r--r-- | runtime/lua/vim/_meta/vimfn.lua | 1 | ||||
-rw-r--r-- | runtime/syntax/vim.vim | 2 | ||||
-rw-r--r-- | src/nvim/cmdexpand.c | 14 | ||||
-rw-r--r-- | src/nvim/cmdexpand_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/eval.lua | 1 | ||||
-rw-r--r-- | src/nvim/path.c | 41 | ||||
-rw-r--r-- | src/nvim/path.h | 3 | ||||
-rw-r--r-- | src/nvim/usercmd.c | 1 | ||||
-rw-r--r-- | test/old/testdir/test_cd.vim | 8 | ||||
-rw-r--r-- | test/old/testdir/test_cmdline.vim | 3 |
12 files changed, 54 insertions, 23 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 334531cec7..de8bfc3aff 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -2412,6 +2412,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 f5cbb7b732..ce2fbda045 100644 --- a/runtime/doc/map.txt +++ b/runtime/doc/map.txt @@ -1385,6 +1385,7 @@ completion can be enabled: -complete=command Ex command (and arguments) -complete=compiler compilers -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/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index d9bd683bbb..b18ca1ecf8 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -2942,6 +2942,7 @@ function vim.fn.getcmdwintype() end --- 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/syntax/vim.vim b/runtime/syntax/vim.vim index e5b0c24447..4262636496 100644 --- a/runtime/syntax/vim.vim +++ b/runtime/syntax/vim.vim @@ -353,7 +353,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/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index d98293f84b..e544ea14ea 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -105,6 +105,7 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const 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 @@ -159,7 +160,8 @@ static void wildescape(expand_T *xp, const char *str, int numfiles, char **files || 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 '~'. for (int i = 0; i < numfiles; i++) { @@ -1228,7 +1230,8 @@ char *addstar(char *fname, size_t len, int context) 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 // use with vim_regcomp(). First work out how long it will be: @@ -1842,7 +1845,7 @@ static const char *set_context_by_cmdname(const char *cmd, cmdidx_T cmdidx, expa case CMD_tcd: case CMD_tchdir: if (xp->xp_context == EXPAND_FILES) { - xp->xp_context = EXPAND_DIRECTORIES; + xp->xp_context = EXPAND_DIRS_IN_CDPATH; } break; case CMD_help: @@ -2506,6 +2509,8 @@ static int expand_files_and_dirs(expand_T *xp, char *pat, char ***matches, int * 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; } @@ -2718,7 +2723,8 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM 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/nvim/cmdexpand_defs.h b/src/nvim/cmdexpand_defs.h index c1fb85859c..3369790151 100644 --- a/src/nvim/cmdexpand_defs.h +++ b/src/nvim/cmdexpand_defs.h @@ -105,6 +105,7 @@ enum { EXPAND_SETTING_SUBTRACT, EXPAND_ARGOPT, EXPAND_KEYMAP, + EXPAND_DIRS_IN_CDPATH, EXPAND_CHECKHEALTH, EXPAND_LUA, }; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index 72a3246da5..dfb1cab542 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -3672,6 +3672,7 @@ M.funcs = { 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/src/nvim/path.c b/src/nvim/path.c index 770d15e2fc..e33e34fff3 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -842,17 +842,18 @@ static bool is_unique(char *maybe_unique, garray_T *gap, int i) return true; // no match found } -// Split the 'path' option into an array of strings in garray_T. Relative -// paths are expanded to their equivalent fullpath. This includes the "." -// (relative to current buffer directory) and empty path (relative to current -// directory) notations. -// -// TODO(vim): handle upward search (;) and path limiter (**N) notations by -// expanding each into their equivalent path(s). -static void expand_path_option(char *curdir, garray_T *gap) +/// Split the 'path' option into an array of strings in garray_T. Relative +/// paths are expanded to their equivalent fullpath. This includes the "." +/// (relative to current buffer directory) and empty path (relative to current +/// directory) notations. +/// +/// @param path_option p_path or p_cdpath +/// +/// TODO(vim): handle upward search (;) and path limiter (**N) notations by +/// expanding each into their equivalent path(s). +static void expand_path_option(char *curdir, char *path_option, garray_T *gap) FUNC_ATTR_NONNULL_ALL { - char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char *buf = xmalloc(MAXPATHL); while (*path_option != NUL) { @@ -942,7 +943,9 @@ static char *get_path_cutoff(char *fname, garray_T *gap) /// Sorts, removes duplicates and modifies all the fullpath names in "gap" so /// that they are unique with respect to each other while conserving the part /// that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len". -static void uniquefy_paths(garray_T *gap, char *pattern) +/// +/// @param path_option p_path or p_cdpath +static void uniquefy_paths(garray_T *gap, char *pattern, char *path_option) FUNC_ATTR_NONNULL_ALL { char **fnames = gap->ga_data; @@ -978,7 +981,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) char *curdir = xmalloc(MAXPATHL); os_dirname(curdir, MAXPATHL); - expand_path_option(curdir, &path_ga); + expand_path_option(curdir, path_option, &path_ga); in_curdir = xcalloc((size_t)gap->ga_len, sizeof(char *)); @@ -1127,12 +1130,17 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl FUNC_ATTR_NONNULL_ALL { garray_T path_ga; + char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char *const curdir = xmalloc(MAXPATHL); os_dirname(curdir, MAXPATHL); ga_init(&path_ga, (int)sizeof(char *), 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); + } xfree(curdir); if (GA_EMPTY(&path_ga)) { return 0; @@ -1148,7 +1156,7 @@ static int expand_in_path(garray_T *const gap, char *const pattern, const int fl 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)); xfree(paths); return gap->ga_len; @@ -1229,6 +1237,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i static bool recursive = false; int add_pat; bool did_expand_in_path = false; + char *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, // it calls ExpandOne(), which brings us back here. In this case, always @@ -1302,7 +1311,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i // Otherwise: Add the file name if it exists or when EW_NOTFOUND is // given. if (path_has_exp_wildcard(p) || (flags & EW_ICASE)) { - if ((flags & EW_PATH) + if ((flags & (EW_PATH | EW_CDPATH)) && !path_is_absolute(p) && !(p[0] == '.' && (vim_ispathsep(p[1]) @@ -1338,8 +1347,8 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i } } - if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & EW_PATH)) { - uniquefy_paths(&ga, p); + if (did_expand_in_path && !GA_EMPTY(&ga) && (flags & (EW_PATH | EW_CDPATH))) { + uniquefy_paths(&ga, p, path_option); } if (p != pat[i]) { xfree(p); diff --git a/src/nvim/path.h b/src/nvim/path.h index a8eb893bb3..26c2bdf14e 100644 --- a/src/nvim/path.h +++ b/src/nvim/path.h @@ -25,7 +25,8 @@ enum { EW_DODOT = 0x4000, ///< also files starting with a dot EW_EMPTYOK = 0x8000, ///< no matches is not an error EW_NOTENV = 0x10000, ///< do not expand environment variables - EW_NOBREAK = 0x20000, ///< do not invoke breakcheck + EW_CDPATH = 0x20000, ///< search in 'cdpath' too + EW_NOBREAK = 0x40000, ///< do not invoke breakcheck }; // Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND // is used when executing commands and EW_SILENT for interactive expanding. diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index 2893c7cf9f..cb084edcf0 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -98,6 +98,7 @@ static const char *command_complete[] = { [EXPAND_USER_VARS] = "var", [EXPAND_BREAKPOINT] = "breakpoint", [EXPAND_SCRIPTNAMES] = "scriptnames", + [EXPAND_DIRS_IN_CDPATH] = "dir_in_path", }; /// List of names of address types. Must be alphabetical for completion. diff --git a/test/old/testdir/test_cd.vim b/test/old/testdir/test_cd.vim index 7ef64d6ffb..dd92fc6c38 100644 --- a/test/old/testdir/test_cd.vim +++ b/test/old/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/test/old/testdir/test_cmdline.vim b/test/old/testdir/test_cmdline.vim index 24811d49db..d00b5bbf46 100644 --- a/test/old/testdir/test_cmdline.vim +++ b/test/old/testdir/test_cmdline.vim @@ -645,7 +645,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 |