mirror of
https://github.com/vim/vim.git
synced 2025-10-06 05:44:14 -04:00
Improvements for :find completion.
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
*todo.txt* For Vim version 7.3f. Last change: 2010 Aug 10
|
*todo.txt* For Vim version 7.3f. Last change: 2010 Aug 12
|
||||||
|
|
||||||
|
|
||||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@@ -32,6 +32,8 @@ be worked on, but only if you sponsor Vim development. See |sponsor|.
|
|||||||
|
|
||||||
'cursorline' stops too early in a help file, caused by conceal feature.
|
'cursorline' stops too early in a help file, caused by conceal feature.
|
||||||
|
|
||||||
|
Have a close look at :find completion, anything that could be wrong?
|
||||||
|
|
||||||
Test 73 fails on MS-Windows when compiled with DJGPP.
|
Test 73 fails on MS-Windows when compiled with DJGPP.
|
||||||
:find completion with 'path' set to "./**" results in full path for
|
:find completion with 'path' set to "./**" results in full path for
|
||||||
"./subdir/file", should shorten to start with "./".
|
"./subdir/file", should shorten to start with "./".
|
||||||
|
143
src/misc1.c
143
src/misc1.c
@@ -9263,6 +9263,7 @@ is_unique(maybe_unique, gap, i)
|
|||||||
int candidate_len;
|
int candidate_len;
|
||||||
int other_path_len;
|
int other_path_len;
|
||||||
char_u **other_paths = (char_u **)gap->ga_data;
|
char_u **other_paths = (char_u **)gap->ga_data;
|
||||||
|
char_u *rival;
|
||||||
|
|
||||||
for (j = 0; j < gap->ga_len && !got_int; j++)
|
for (j = 0; j < gap->ga_len && !got_int; j++)
|
||||||
{
|
{
|
||||||
@@ -9275,7 +9276,8 @@ is_unique(maybe_unique, gap, i)
|
|||||||
if (other_path_len < candidate_len)
|
if (other_path_len < candidate_len)
|
||||||
continue; /* it's different */
|
continue; /* it's different */
|
||||||
|
|
||||||
if (fnamecmp(maybe_unique, gettail(other_paths[j])) == 0)
|
rival = other_paths[j] + other_path_len - candidate_len;
|
||||||
|
if (fnamecmp(maybe_unique, rival) == 0)
|
||||||
return FALSE; /* match */
|
return FALSE; /* match */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9301,8 +9303,6 @@ expand_path_option(curdir, gap)
|
|||||||
char_u *buf;
|
char_u *buf;
|
||||||
char_u *p;
|
char_u *p;
|
||||||
|
|
||||||
ga_init2(gap, (int)sizeof(char_u *), 1);
|
|
||||||
|
|
||||||
if ((buf = alloc((int)MAXPATHL)) == NULL)
|
if ((buf = alloc((int)MAXPATHL)) == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -9413,15 +9413,21 @@ uniquefy_paths(gap, pattern)
|
|||||||
int i;
|
int i;
|
||||||
int len;
|
int len;
|
||||||
char_u **fnames = (char_u **)gap->ga_data;
|
char_u **fnames = (char_u **)gap->ga_data;
|
||||||
int sort_again = 0;
|
int sort_again = FALSE;
|
||||||
char_u *pat;
|
char_u *pat;
|
||||||
char_u *file_pattern;
|
char_u *file_pattern;
|
||||||
char_u *curdir = NULL;
|
char_u *curdir = NULL;
|
||||||
regmatch_T regmatch;
|
regmatch_T regmatch;
|
||||||
garray_T path_ga;
|
garray_T path_ga;
|
||||||
|
char_u **in_curdir = NULL;
|
||||||
|
char_u *short_name;
|
||||||
|
|
||||||
sort_strings(fnames, gap->ga_len);
|
sort_strings(fnames, gap->ga_len);
|
||||||
remove_duplicates(gap);
|
remove_duplicates(gap);
|
||||||
|
if (gap->ga_len == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ga_init2(&path_ga, (int)sizeof(char_u *), 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to prepend a '*' at the beginning of file_pattern so that the
|
* We need to prepend a '*' at the beginning of file_pattern so that the
|
||||||
@@ -9447,17 +9453,21 @@ uniquefy_paths(gap, pattern)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if ((curdir = alloc((int)(MAXPATHL))) == NULL)
|
if ((curdir = alloc((int)(MAXPATHL))) == NULL)
|
||||||
return;
|
goto theend;
|
||||||
mch_dirname(curdir, MAXPATHL);
|
mch_dirname(curdir, MAXPATHL);
|
||||||
|
|
||||||
expand_path_option(curdir, &path_ga);
|
expand_path_option(curdir, &path_ga);
|
||||||
|
in_curdir = (char_u **)alloc(gap->ga_len * sizeof(char_u *));
|
||||||
|
if (in_curdir == NULL)
|
||||||
|
goto theend;
|
||||||
|
|
||||||
for (i = 0; i < gap->ga_len; i++)
|
for (i = 0; i < gap->ga_len; i++)
|
||||||
{
|
{
|
||||||
char_u *path = fnames[i];
|
char_u *path = fnames[i];
|
||||||
int is_in_curdir;
|
int is_in_curdir;
|
||||||
char_u *dir_end = gettail(path);
|
char_u *dir_end = gettail(path);
|
||||||
char_u *short_name;
|
char_u *pathsep_p;
|
||||||
|
char_u *path_cutoff;
|
||||||
|
|
||||||
len = (int)STRLEN(path);
|
len = (int)STRLEN(path);
|
||||||
while (dir_end > path &&
|
while (dir_end > path &&
|
||||||
@@ -9468,63 +9478,16 @@ uniquefy_paths(gap, pattern)
|
|||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
mb_ptr_back(path, dir_end);
|
mb_ptr_back(path, dir_end);
|
||||||
is_in_curdir = STRNCMP(curdir, path, dir_end - path) == 0
|
is_in_curdir = fnamencmp(curdir, path, dir_end - path) == 0
|
||||||
&& curdir[dir_end - path] == NUL;
|
&& 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?
|
|
||||||
*
|
|
||||||
* Note: If the full filename is /curdir/foo/bar/{filename}, we don't
|
|
||||||
* want to shorten it to ./foo/bar/{filename} yet because 'path' might
|
|
||||||
* contain ". / * *", in which case the shortened filename could be
|
|
||||||
* shorter than ./foo/bar/{filename}.
|
|
||||||
*/
|
|
||||||
if (is_in_curdir)
|
if (is_in_curdir)
|
||||||
{
|
in_curdir[i] = vim_strsave(path);
|
||||||
char_u *rel_path;
|
|
||||||
|
|
||||||
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
|
else
|
||||||
{
|
in_curdir[i] = NULL;
|
||||||
|
|
||||||
/* Shorten the filename while maintaining its uniqueness */
|
/* Shorten the filename while maintaining its uniqueness */
|
||||||
char_u *pathsep_p;
|
path_cutoff = get_path_cutoff(path, &path_ga);
|
||||||
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;
|
||||||
@@ -9534,11 +9497,10 @@ uniquefy_paths(gap, pattern)
|
|||||||
&& is_unique(pathsep_p + 1, gap, i)
|
&& is_unique(pathsep_p + 1, gap, i)
|
||||||
&& path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
|
&& path_cutoff != NULL && pathsep_p + 1 >= path_cutoff)
|
||||||
{
|
{
|
||||||
sort_again = 1;
|
sort_again = TRUE;
|
||||||
mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
|
mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (mch_isFullName(path))
|
if (mch_isFullName(path))
|
||||||
{
|
{
|
||||||
@@ -9564,8 +9526,68 @@ uniquefy_paths(gap, pattern)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Shorten filenames in /in/current/directory/{filename} */
|
||||||
|
for (i = 0; i < gap->ga_len; i++)
|
||||||
|
{
|
||||||
|
char_u *rel_path;
|
||||||
|
char_u *path = in_curdir[i];
|
||||||
|
|
||||||
|
if (path == NULL)
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* If the file is in the current directory,
|
||||||
|
* and it is not unique,
|
||||||
|
* reduce it to ./{filename}
|
||||||
|
* FIXME ^ Is this portable?
|
||||||
|
* else reduce it to {filename}
|
||||||
|
*
|
||||||
|
* Note: If the full filename is /curdir/foo/bar/{filename}, we don't
|
||||||
|
* want to shorten it to ./foo/bar/{filename} yet because 'path' might
|
||||||
|
* contain ". / * *", in which case the shortened filename could be
|
||||||
|
* shorter than ./foo/bar/{filename}.
|
||||||
|
*/
|
||||||
|
short_name = shorten_fname(path, curdir);
|
||||||
|
if (short_name == NULL)
|
||||||
|
short_name = path;
|
||||||
|
if (is_unique(short_name, gap, i))
|
||||||
|
{
|
||||||
|
STRCPY(fnames[i], 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 = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
theend:
|
theend:
|
||||||
vim_free(curdir);
|
vim_free(curdir);
|
||||||
|
if (in_curdir != NULL)
|
||||||
|
{
|
||||||
|
for (i = 0; i < gap->ga_len; i++)
|
||||||
|
vim_free(in_curdir[i]);
|
||||||
|
vim_free(in_curdir);
|
||||||
|
}
|
||||||
ga_clear_strings(&path_ga);
|
ga_clear_strings(&path_ga);
|
||||||
vim_free(regmatch.regprog);
|
vim_free(regmatch.regprog);
|
||||||
|
|
||||||
@@ -9598,6 +9620,7 @@ expand_in_path(gap, pattern, flags)
|
|||||||
return 0;
|
return 0;
|
||||||
mch_dirname(curdir, MAXPATHL);
|
mch_dirname(curdir, MAXPATHL);
|
||||||
|
|
||||||
|
ga_init2(&path_ga, (int)sizeof(char_u *), 1);
|
||||||
expand_path_option(curdir, &path_ga);
|
expand_path_option(curdir, &path_ga);
|
||||||
vim_free(curdir);
|
vim_free(curdir);
|
||||||
if (path_ga.ga_len == 0)
|
if (path_ga.ga_len == 0)
|
||||||
|
@@ -6,7 +6,8 @@ STARTTEST
|
|||||||
:" delete the Xfind directory during cleanup
|
:" delete the Xfind directory during cleanup
|
||||||
:"
|
:"
|
||||||
:" This will cause a few errors, do it silently.
|
:" This will cause a few errors, do it silently.
|
||||||
:set nocp viminfo+=nviminfo visualbell
|
:set visualbell
|
||||||
|
:set nocp viminfo+=nviminfo
|
||||||
:"
|
:"
|
||||||
:function! DeleteDirectory(dir)
|
:function! DeleteDirectory(dir)
|
||||||
: if has("win16") || has("win32") || has("win64") || has("dos16") || has("dos32")
|
: if has("win16") || has("win32") || has("win64") || has("dos16") || has("dos32")
|
||||||
@@ -20,32 +21,33 @@ STARTTEST
|
|||||||
:call DeleteDirectory("Xfind")
|
:call DeleteDirectory("Xfind")
|
||||||
:new
|
:new
|
||||||
:let cwd=getcwd()
|
:let cwd=getcwd()
|
||||||
:!mkdir Xfind
|
:let test_out = cwd . '/test.out'
|
||||||
|
:silent !mkdir Xfind
|
||||||
:cd Xfind
|
:cd Xfind
|
||||||
:set path=
|
:set path=
|
||||||
:find
|
:find
|
||||||
:w! ../test.out
|
:exec "w! " . test_out
|
||||||
:close
|
:close
|
||||||
:new
|
:new
|
||||||
:set path=.
|
:set path=.
|
||||||
:find
|
:find
|
||||||
:w >>../test.out
|
:exec "w >>" . test_out
|
||||||
:close
|
:close
|
||||||
:new
|
:new
|
||||||
:set path=.,,
|
:set path=.,,
|
||||||
:find
|
:find
|
||||||
:w >>../test.out
|
:exec "w >>" . test_out
|
||||||
:close
|
:close
|
||||||
:new
|
:new
|
||||||
:set path=./**
|
:set path=./**
|
||||||
:find
|
:find
|
||||||
:w >>../test.out
|
:exec "w >>" . test_out
|
||||||
:close
|
:close
|
||||||
:new
|
:new
|
||||||
:" We shouldn't find any file at this point, ../test.out must be empty.
|
:" We shouldn't find any file at this point, test.out must be empty.
|
||||||
:!mkdir in
|
:silent !mkdir in
|
||||||
:cd in
|
:cd in
|
||||||
:!mkdir path
|
:silent !mkdir path
|
||||||
:exec "cd " . cwd
|
:exec "cd " . cwd
|
||||||
:e Xfind/file.txt
|
:e Xfind/file.txt
|
||||||
SHoly Grail:w
|
SHoly Grail:w
|
||||||
@@ -57,40 +59,93 @@ SAnother Holy Grail:w
|
|||||||
SE.T.:w
|
SE.T.:w
|
||||||
:set path=Xfind/**
|
:set path=Xfind/**
|
||||||
:find file
|
:find file
|
||||||
:w >> test.out
|
:exec "w >>" . test_out
|
||||||
:find file
|
:find file
|
||||||
:w >>test.out
|
:exec "w >>" . test_out
|
||||||
:find file
|
:find file
|
||||||
:w >>test.out
|
:exec "w >>" . test_out
|
||||||
:" Rerun the previous three find completions, using fullpath in 'path'
|
:" Rerun the previous three find completions, using fullpath in 'path'
|
||||||
:exec "set path=" . cwd . "/Xfind/**"
|
:exec "set path=" . cwd . "/Xfind/**"
|
||||||
:find file
|
:find file
|
||||||
:w >> test.out
|
:exec "w >>" . test_out
|
||||||
:find file
|
:find file
|
||||||
:w >>test.out
|
:exec "w >>" . test_out
|
||||||
:find file
|
:find file
|
||||||
:w >>test.out
|
:exec "w >>" . test_out
|
||||||
:" Same steps again, using relative and fullpath items that point to the same
|
:" Same steps again, using relative and fullpath items that point to the same
|
||||||
:" recursive location.
|
:" recursive location.
|
||||||
:" This is to test that there are no duplicates in the completion list.
|
:" This is to test that there are no duplicates in the completion list.
|
||||||
:exec "set path+=Xfind/**"
|
:exec "set path+=Xfind/**"
|
||||||
:find file
|
:find file
|
||||||
:w >> test.out
|
:exec "w >>" . test_out
|
||||||
:find file
|
:find file
|
||||||
:w >>test.out
|
:exec "w >>" . test_out
|
||||||
:find file
|
:find file
|
||||||
:w >>test.out
|
:exec "w >>" . test_out
|
||||||
:find file
|
:find file
|
||||||
:" Test find completion for directory of current buffer, which at this point
|
:" Test find completion for directory of current buffer, which at this point
|
||||||
:" is Xfind/in/file.txt.
|
:" is Xfind/in/file.txt.
|
||||||
:set path=.
|
:set path=.
|
||||||
:find st
|
:find st
|
||||||
:w >> test.out
|
:exec "w >>" . test_out
|
||||||
:" Test find completion for empty path item ",," which is the current directory
|
:" Test find completion for empty path item ",," which is the current directory
|
||||||
:cd Xfind
|
:cd Xfind
|
||||||
:set path=,,
|
:set path=,,
|
||||||
:find f
|
:find f
|
||||||
:w >> ../test.out
|
:exec "w >>" . test_out
|
||||||
|
:" Test shortening of
|
||||||
|
:"
|
||||||
|
:" foo/x/bar/voyager.txt
|
||||||
|
:" foo/y/bar/voyager.txt
|
||||||
|
:"
|
||||||
|
:" When current directory is above foo/ they should be shortened to (in order
|
||||||
|
:" of appearance):
|
||||||
|
:"
|
||||||
|
:" x/bar/voyager.txt
|
||||||
|
:" y/bar/voyager.txt
|
||||||
|
:silent !mkdir foo
|
||||||
|
:cd foo
|
||||||
|
:silent !mkdir x
|
||||||
|
:silent !mkdir y
|
||||||
|
:cd x
|
||||||
|
:silent !mkdir bar
|
||||||
|
:cd ..
|
||||||
|
:cd y
|
||||||
|
:silent !mkdir bar
|
||||||
|
:cd ..
|
||||||
|
:cd ..
|
||||||
|
:" We should now be in the Xfind directory
|
||||||
|
:e foo/x/bar/voyager.txt
|
||||||
|
SVoyager 1:w
|
||||||
|
:e foo/y/bar/voyager.txt
|
||||||
|
SVoyager 2:w
|
||||||
|
:exec "set path=" . cwd . "/Xfind/**"
|
||||||
|
:find voyager
|
||||||
|
:exec "w >>" . test_out
|
||||||
|
:find voyager
|
||||||
|
:exec "w >>" . test_out
|
||||||
|
:"
|
||||||
|
:" When current directory is .../foo/y/bar they should be shortened to (in
|
||||||
|
:" order of appearance):
|
||||||
|
:"
|
||||||
|
:" ./voyager.txt
|
||||||
|
:" x/bar/voyager.txt
|
||||||
|
:cd foo
|
||||||
|
:cd y
|
||||||
|
:cd bar
|
||||||
|
:find voyager
|
||||||
|
:exec "w >> " . test_out
|
||||||
|
:find voyager
|
||||||
|
:exec "w >> " . test_out
|
||||||
|
:" Check the opposite too:
|
||||||
|
:cd ..
|
||||||
|
:cd ..
|
||||||
|
:cd x
|
||||||
|
:cd bar
|
||||||
|
:find voyager
|
||||||
|
:exec "w >> " . test_out
|
||||||
|
:find voyager
|
||||||
|
:exec "w >> " . test_out
|
||||||
:cd ..
|
:cd ..
|
||||||
:q
|
:q
|
||||||
:call DeleteDirectory("Xfind")
|
:call DeleteDirectory("Xfind")
|
||||||
|
@@ -9,3 +9,9 @@ Jimmy Hoffa
|
|||||||
E.T.
|
E.T.
|
||||||
Another Holy Grail
|
Another Holy Grail
|
||||||
Holy Grail
|
Holy Grail
|
||||||
|
Voyager 1
|
||||||
|
Voyager 2
|
||||||
|
Voyager 2
|
||||||
|
Voyager 1
|
||||||
|
Voyager 1
|
||||||
|
Voyager 2
|
||||||
|
Reference in New Issue
Block a user