mirror of
https://github.com/neovim/neovim.git
synced 2025-10-05 09:26:30 +00:00
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
a20bf69a3b
Co-authored-by: LemonBoy <thatlemon@gmail.com>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -105,6 +105,7 @@ enum {
|
||||
EXPAND_SETTING_SUBTRACT,
|
||||
EXPAND_ARGOPT,
|
||||
EXPAND_KEYMAP,
|
||||
EXPAND_DIRS_IN_CDPATH,
|
||||
EXPAND_CHECKHEALTH,
|
||||
EXPAND_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
|
||||
|
@@ -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);
|
||||
|
@@ -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.
|
||||
|
@@ -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.
|
||||
|
Reference in New Issue
Block a user