0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

Improvements for ":find" completion. (Nazri Ramliy)

This commit is contained in:
Bram Moolenaar 2010-07-28 22:29:10 +02:00
parent 8e46927a32
commit 162bd91564
4 changed files with 249 additions and 50 deletions

View File

@ -1,4 +1,4 @@
*editing.txt* For Vim version 7.3c. Last change: 2010 Jul 21 *editing.txt* For Vim version 7.3c. Last change: 2010 Jul 28
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@ -1622,10 +1622,13 @@ There are three different types of searching:
In the above example you might want to set path to: > In the above example you might want to set path to: >
:set path=**,/u/user_x/** :set path=**,/u/user_x/**
< This searches: > < This searches:
/u/user_x/work/release/** /u/user_x/work/release/** ~
/u/user_x/** /u/user_x/** ~
< This searches the same directories, but in a different order. This searches the same directories, but in a different order.
Note that completion for ":find", ":sfind", and ":tabfind" commands do not
currently work with 'path' items that contain a url or use the double star
(/usr/**2) or upward search (;) notations. >
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:ft=help:norl:

View File

@ -30,22 +30,20 @@ be worked on, but only if you sponsor Vim development. See |sponsor|.
*known-bugs* *known-bugs*
-------------------- Known bugs and current work ----------------------- -------------------- Known bugs and current work -----------------------
Patch for :find completion. (Nazri Ramliy, 2010 Jul 27, and leak fix) Patch for :filetype completion. (Dominique Pelle, Jul 28)
And patch for Windows, Jul 28.
And fix for patch, Jul 28.
Windows 7: "Open with..." menu starts Vim without a file. Windows 7: "Open with..." menu starts Vim without a file.
Windows 7: installing Vim again doesn't find the previously installed Vim. Windows 7: installing Vim again doesn't find the previously installed Vim.
ftplugin/mupad.vim should not source AppendMatchGroup.vim, it should use an
autoload function.
Same for indent/GenericIndent.vim
Move more common code from if_python.c and if_python3.c to if_py_both.h Move more common code from if_python.c and if_python3.c to if_py_both.h
Add filetype completion to user commands. (Christian Brabandt, 2010 Jul 26) Add filetype completion to user commands. (Christian Brabandt, 2010 Jul 26)
But call it "filetype" instead of "syntax". But call it "filetype" instead of "syntax"?
ftplugin/mupad.vim should not source AppendMatchGroup.vim, it should use an
autoload function.
Same for indent/GenericIndent.vim
Before release 7.3: Before release 7.3:
- Rename vim73 branch to default (hints: Xavier de Gaye, 2010 May 23) - Rename vim73 branch to default (hints: Xavier de Gaye, 2010 May 23)

View File

@ -5033,6 +5033,12 @@ globpath(path, file, expand_options)
{ {
/* Copy one item of the path to buf[] and concatenate the file name. */ /* Copy one item of the path to buf[] and concatenate the file name. */
copy_option_part(&path, buf, MAXPATHL, ","); copy_option_part(&path, buf, MAXPATHL, ",");
if (path_with_url(buf))
continue;
/*
* FIXME: should we proactively skip 'path' with limiter (/usr/ **N)
* and upward search (;) notations, just like we did with url above?
*/
if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL) if (STRLEN(buf) + STRLEN(file) + 2 < MAXPATHL)
{ {
add_pathsep(buf); add_pathsep(buf);

View File

@ -9239,6 +9239,8 @@ unix_expandpath(gap, path, wildoff, flags, didstar)
static int find_previous_pathsep __ARGS((char_u *path, char_u **psep)); static int find_previous_pathsep __ARGS((char_u *path, char_u **psep));
static int is_unique __ARGS((char_u *maybe_unique, garray_T *gap, int i)); static int is_unique __ARGS((char_u *maybe_unique, garray_T *gap, int i));
static void remove_duplicates __ARGS((garray_T *gap)); static void remove_duplicates __ARGS((garray_T *gap));
static void expand_path_option __ARGS((char_u *curdir, garray_T *gap));
static char_u *get_path_cutoff __ARGS((char_u *fname, garray_T *gap));
static void uniquefy_paths __ARGS((garray_T *gap, char_u *pattern)); static void uniquefy_paths __ARGS((garray_T *gap, char_u *pattern));
static int expand_in_path __ARGS((garray_T *gap, char_u *pattern, int flags)); static int expand_in_path __ARGS((garray_T *gap, char_u *pattern, int flags));
@ -9267,8 +9269,8 @@ find_previous_pathsep(path, psep)
} }
/* /*
* Returns TRUE if maybe_unique is unique wrt other_paths in gap. maybe_unique * Returns TRUE if "maybe_unique" is unique wrt other_paths in gap.
* is the end portion of ((char_u **)gap->ga_data)[i]. * "maybe_unique" is the end portion of ((char_u **)gap->ga_data)[i].
*/ */
static int static int
is_unique(maybe_unique, gap, i) is_unique(maybe_unique, gap, i)
@ -9279,32 +9281,24 @@ is_unique(maybe_unique, gap, i)
int j; int j;
int candidate_len; int candidate_len;
int other_path_len; int other_path_len;
char_u *rival; char_u **other_paths = (char_u **)gap->ga_data;
char_u **other_paths;
other_paths = (gap->ga_data != NULL) ? (char_u **)gap->ga_data
: (char_u **)"";
for (j = 0; j < gap->ga_len && !got_int; j++) for (j = 0; j < gap->ga_len && !got_int; j++)
{ {
ui_breakcheck(); ui_breakcheck();
/* don't compare it with itself */
if (j == i) if (j == i)
continue; continue; /* don't compare it with itself */
candidate_len = (int)STRLEN(maybe_unique); candidate_len = (int)STRLEN(maybe_unique);
other_path_len = (int)STRLEN(other_paths[j]); other_path_len = (int)STRLEN(other_paths[j]);
if (other_path_len < candidate_len) if (other_path_len < candidate_len)
continue; /* it's different */ continue; /* it's different */
rival = other_paths[j] + other_path_len - candidate_len; if (fnamecmp(maybe_unique, gettail(other_paths[j])) == 0)
return FALSE; /* match */
if (fnamecmp(maybe_unique, rival) == 0)
return FALSE;
} }
return TRUE; return TRUE; /* no match found */
} }
/* /*
@ -9330,6 +9324,101 @@ remove_duplicates(gap)
} }
} }
/*
* Split the 'path' option to a an array of strings as 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: handle upward search (;) and path limiter (**N) notations by
* expanding each into their equivalent path(s).
*/
static void
expand_path_option(curdir, gap)
char_u *curdir;
garray_T *gap;
{
char_u *path_option = *curbuf->b_p_path == NUL
? p_path : curbuf->b_p_path;
char_u *buf;
ga_init2(gap, (int)sizeof(char_u *), 1);
if ((buf = alloc((int)(MAXPATHL))) == NULL)
return;
while (*path_option != NUL)
{
copy_option_part(&path_option, buf, MAXPATHL, " ,");
if (STRCMP(buf, ".") == 0) /* relative to current buffer */
{
if (curbuf->b_ffname == NULL)
continue;
STRCPY(buf, curbuf->b_ffname);
*gettail(buf) = NUL;
}
else if (buf[0] == NUL) /* relative to current directory */
STRCPY(buf, curdir);
else if (!mch_isFullName(buf))
{
/* Expand relative path to their full path equivalent */
int curdir_len = STRLEN(curdir);
int buf_len = STRLEN(buf);
if (curdir_len + buf_len + 3 > MAXPATHL)
continue;
STRMOVE(buf + curdir_len + 1, buf);
STRCPY(buf, curdir);
add_pathsep(buf);
STRMOVE(buf + curdir_len, buf + curdir_len + 1);
}
addfile(gap, buf, EW_NOTFOUND|EW_DIR|EW_FILE);
}
vim_free(buf);
}
/*
* Returns a pointer to the file or directory name in fname that matches the
* longest path in gap, or NULL if there is no match. For example:
*
* path: /foo/bar/baz
* fname: /foo/bar/baz/quux.txt
* returns: ^this
*/
static char_u *
get_path_cutoff(fname, gap)
char_u *fname;
garray_T *gap;
{
int i;
int maxlen = 0;
char_u **path_part = (char_u **)gap->ga_data;
char_u *cutoff = NULL;
for (i = 0; i < gap->ga_len; i++)
{
int j = 0;
while (fname[j] == path_part[i][j] && fname[j] != NUL
&& path_part[i][j] != NUL)
j++;
if (j > maxlen)
{
maxlen = j;
cutoff = &fname[j];
}
}
/* Skip to the file or directory name */
while (cutoff != NULL && vim_ispathsep(*cutoff) && *cutoff != NUL)
mb_ptr_adv(cutoff);
return cutoff;
}
/* /*
* Sorts, removes duplicates and modifies all the fullpath names in gap so that * 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 * they are unique with respect to each other while conserving the part that
@ -9342,13 +9431,14 @@ uniquefy_paths(gap, pattern)
{ {
int i; int i;
int len; int len;
char_u *pathsep_p;
char_u *path;
char_u **fnames = (char_u **)gap->ga_data; char_u **fnames = (char_u **)gap->ga_data;
int sort_again = 0; int sort_again = 0;
char_u *pat; char_u *pat;
char_u *file_pattern; char_u *file_pattern;
char_u *curdir = NULL;
int len_curdir = 0;
regmatch_T regmatch; regmatch_T regmatch;
garray_T path_ga;
sort_strings(fnames, gap->ga_len); sort_strings(fnames, gap->ga_len);
remove_duplicates(gap); remove_duplicates(gap);
@ -9360,8 +9450,10 @@ uniquefy_paths(gap, pattern)
*/ */
len = (int)STRLEN(pattern); len = (int)STRLEN(pattern);
file_pattern = alloc(len + 2); file_pattern = alloc(len + 2);
if (file_pattern == NULL)
return;
file_pattern[0] = '*'; file_pattern[0] = '*';
file_pattern[1] = '\0'; file_pattern[1] = NUL;
STRCAT(file_pattern, pattern); STRCAT(file_pattern, pattern);
pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE); pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE);
vim_free(file_pattern); vim_free(file_pattern);
@ -9374,25 +9466,95 @@ uniquefy_paths(gap, pattern)
if (regmatch.regprog == NULL) if (regmatch.regprog == NULL)
return; return;
if ((curdir = alloc((int)(MAXPATHL))) == NULL)
return;
mch_dirname(curdir, MAXPATHL);
len_curdir = STRLEN(curdir);
expand_path_option(curdir, &path_ga);
for (i = 0; i < gap->ga_len; i++) for (i = 0; i < gap->ga_len; i++)
{ {
path = fnames[i]; char_u *path = fnames[i];
int is_in_curdir;
char_u *dir_end = gettail(path);
len = (int)STRLEN(path); len = (int)STRLEN(path);
while (dir_end > path && !vim_ispathsep(*dir_end))
mb_ptr_back(path, dir_end);
is_in_curdir = STRNCMP(curdir, path, dir_end - path) == 0
&& curdir[dir_end - path] == NUL;
/*
* If the file is in the current directory,
* and it is not unique,
* reduce it to ./{filename}
* FIXME ^ Is this portable?
*/
if (is_in_curdir)
{
char_u *rel_path;
char_u *short_name = shorten_fname(path, curdir);
if (short_name == NULL)
short_name = path;
if (is_unique(short_name, gap, i))
{
STRMOVE(path, short_name);
continue;
}
rel_path = alloc((int)(STRLEN(short_name)
+ STRLEN(PATHSEPSTR) + 2));
if (rel_path == NULL)
goto theend;
/* FIXME Is "." a portable way of denoting the current directory? */
STRCPY(rel_path, ".");
add_pathsep(rel_path);
STRCAT(rel_path, short_name);
if (len < (int)STRLEN(rel_path))
{
vim_free(fnames[i]);
fnames[i] = alloc((int)(STRLEN(rel_path) + 1));
if (fnames[i] == NULL)
{
vim_free(rel_path);
goto theend;
}
}
STRCPY(fnames[i], rel_path);
vim_free(rel_path);
sort_again = 1;
}
else
{
/* Shorten the filename while maintaining its uniqueness */
char_u *pathsep_p;
char_u *path_cutoff = get_path_cutoff(path, &path_ga);
/* we start at the end of the path */ /* we start at the end of the path */
pathsep_p = path + len - 1; pathsep_p = path + len - 1;
while (find_previous_pathsep(path, &pathsep_p)) while (find_previous_pathsep(path, &pathsep_p))
if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0) if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
&& is_unique(pathsep_p, gap, i)) && is_unique(pathsep_p + 1, gap, i)
&& path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
{ {
sort_again = 1; sort_again = 1;
mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p)); mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
break; break;
} }
} }
}
theend:
vim_free(curdir);
ga_clear_strings(&path_ga);
vim_free(regmatch.regprog); vim_free(regmatch.regprog);
if (sort_again) if (sort_again)
{ {
sort_strings(fnames, gap->ga_len); sort_strings(fnames, gap->ga_len);
@ -9412,23 +9574,53 @@ expand_in_path(gap, pattern, flags)
int flags; /* EW_* flags */ int flags; /* EW_* flags */
{ {
int c = 0; int c = 0;
char_u *path_option = *curbuf->b_p_path == NUL char_u *files = NULL;
? p_path : curbuf->b_p_path;
char_u *files;
char_u *s; /* start */ char_u *s; /* start */
char_u *e; /* end */ char_u *e; /* end */
char_u *paths = NULL;
char_u **path_list;
char_u *curdir;
garray_T path_ga;
int i;
if ((curdir = alloc((int)(MAXPATHL))) == NULL)
return 0;
mch_dirname(curdir, MAXPATHL);
expand_path_option(curdir, &path_ga);
vim_free(curdir);
path_list = (char_u **)(path_ga.ga_data);
for (i = 0; i < path_ga.ga_len; i++)
{
if (paths == NULL)
{
if ((paths = alloc((int)(STRLEN(path_list[i]) + 1))) == NULL)
return 0;
STRCPY(paths, path_list[i]);
}
else
{
if ((paths = realloc(paths, (int)(STRLEN(paths)
+ STRLEN(path_list[i]) + 2))) == NULL)
return 0;
STRCAT(paths, ",");
STRCAT(paths, path_list[i]);
}
}
files = globpath(paths, pattern, 0);
vim_free(paths);
files = globpath(path_option, pattern, 0);
if (files == NULL) if (files == NULL)
return 0; return 0;
/* Copy each path in files into gap */ /* Copy each path in files into gap */
s = e = files; s = e = files;
while (*s != '\0') while (*s != NUL)
{ {
while (*e != '\n' && *e != '\0') while (*e != '\n' && *e != NUL)
e++; e++;
if (*e == '\0') if (*e == NUL)
{ {
addfile(gap, s, flags); addfile(gap, s, flags);
break; break;
@ -9436,7 +9628,7 @@ expand_in_path(gap, pattern, flags)
else else
{ {
/* *e is '\n' */ /* *e is '\n' */
*e = '\0'; *e = NUL;
addfile(gap, s, flags); addfile(gap, s, flags);
e++; e++;
s = e; s = e;
@ -9817,7 +10009,7 @@ get_cmd_output(cmd, infile, flags)
buffer = NULL; buffer = NULL;
} }
else else
buffer[len] = '\0'; /* make sure the buffer is terminated */ buffer[len] = NUL; /* make sure the buffer is terminated */
done: done:
vim_free(tempname); vim_free(tempname);