diff options
author | Bram Moolenaar <Bram@vim.org> | 2010-08-12 21:50:51 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2010-08-12 21:50:51 +0200 |
commit | 0be992e3476ff9df8b7d565042432970f56d7b7e (patch) | |
tree | c043d06bbf15669c9c9b1bcb297dcfd87b948a4f | |
parent | d7b734a49364df78c2d246efa1bb6cd1e7595474 (diff) | |
download | vim-0be992e3476ff9df8b7d565042432970f56d7b7e.zip |
Improvements for :find completion.
-rw-r--r-- | runtime/doc/todo.txt | 4 | ||||
-rw-r--r-- | src/misc1.c | 173 | ||||
-rw-r--r-- | src/testdir/test73.in | 95 | ||||
-rw-r--r-- | src/testdir/test73.ok | 6 |
4 files changed, 182 insertions, 96 deletions
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt index 94dcfdede..642f52fc1 100644 --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -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 @@ -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. +Have a close look at :find completion, anything that could be wrong? + Test 73 fails on MS-Windows when compiled with DJGPP. :find completion with 'path' set to "./**" results in full path for "./subdir/file", should shorten to start with "./". diff --git a/src/misc1.c b/src/misc1.c index 400ecf158..432d36cbe 100644 --- a/src/misc1.c +++ b/src/misc1.c @@ -9263,6 +9263,7 @@ is_unique(maybe_unique, gap, i) int candidate_len; int other_path_len; char_u **other_paths = (char_u **)gap->ga_data; + char_u *rival; 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) 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 */ } @@ -9301,8 +9303,6 @@ expand_path_option(curdir, gap) char_u *buf; char_u *p; - ga_init2(gap, (int)sizeof(char_u *), 1); - if ((buf = alloc((int)MAXPATHL)) == NULL) return; @@ -9357,7 +9357,7 @@ expand_path_option(curdir, gap) * * path: /foo/bar/baz * fname: /foo/bar/baz/quux.txt - * returns: ^this + * returns: ^this */ static char_u * get_path_cutoff(fname, gap) @@ -9413,15 +9413,21 @@ uniquefy_paths(gap, pattern) int i; int len; char_u **fnames = (char_u **)gap->ga_data; - int sort_again = 0; + int sort_again = FALSE; char_u *pat; char_u *file_pattern; char_u *curdir = NULL; regmatch_T regmatch; garray_T path_ga; + char_u **in_curdir = NULL; + char_u *short_name; sort_strings(fnames, gap->ga_len); 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 @@ -9447,17 +9453,21 @@ uniquefy_paths(gap, pattern) return; if ((curdir = alloc((int)(MAXPATHL))) == NULL) - return; + goto theend; mch_dirname(curdir, MAXPATHL); 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++) { char_u *path = fnames[i]; int is_in_curdir; char_u *dir_end = gettail(path); - char_u *short_name; + char_u *pathsep_p; + char_u *path_cutoff; len = (int)STRLEN(path); while (dir_end > path && @@ -9468,78 +9478,30 @@ uniquefy_paths(gap, pattern) #endif ) 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; - /* - * 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) - { - 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; - } + in_curdir[i] = vim_strsave(path); + else + in_curdir[i] = NULL; - rel_path = alloc((int)(STRLEN(short_name) - + STRLEN(PATHSEPSTR) + 2)); - if (rel_path == NULL) - goto theend; + /* Shorten the filename while maintaining its uniqueness */ + path_cutoff = get_path_cutoff(path, &path_ga); - /* FIXME Is "." a portable way of denoting the current directory? */ - STRCPY(rel_path, "."); - add_pathsep(rel_path); - STRCAT(rel_path, short_name); + /* we start at the end of the path */ + pathsep_p = path + len - 1; - if (len < (int)STRLEN(rel_path)) + while (find_previous_pathsep(path, &pathsep_p)) + if (vim_regexec(®match, pathsep_p + 1, (colnr_T)0) + && is_unique(pathsep_p + 1, gap, i) + && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) { - vim_free(fnames[i]); - fnames[i] = alloc((int)(STRLEN(rel_path) + 1)); - if (fnames[i] == NULL) - { - vim_free(rel_path); - goto theend; - } + sort_again = TRUE; + mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p)); + break; } - 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 */ - pathsep_p = path + len - 1; - - while (find_previous_pathsep(path, &pathsep_p)) - if (vim_regexec(®match, pathsep_p + 1, (colnr_T)0) - && is_unique(pathsep_p + 1, gap, i) - && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) - { - sort_again = 1; - mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p)); - break; - } - } - if (mch_isFullName(path)) { /* @@ -9548,11 +9510,11 @@ uniquefy_paths(gap, pattern) * 1. It is under the current directory. * 2. The result is actually shorter than the original. * - * Before curdir After - * /foo/bar/file.txt /foo/bar ./file.txt - * c:\foo\bar\file.txt c:\foo\bar .\file.txt - * /file.txt / /file.txt - * c:\file.txt c:\ .\file.txt + * Before curdir After + * /foo/bar/file.txt /foo/bar ./file.txt + * c:\foo\bar\file.txt c:\foo\bar .\file.txt + * /file.txt / /file.txt + * c:\file.txt c:\ .\file.txt */ short_name = shorten_fname(path, curdir); if (short_name != NULL && short_name > path + 1) @@ -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: 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); vim_free(regmatch.regprog); @@ -9598,6 +9620,7 @@ expand_in_path(gap, pattern, flags) return 0; mch_dirname(curdir, MAXPATHL); + ga_init2(&path_ga, (int)sizeof(char_u *), 1); expand_path_option(curdir, &path_ga); vim_free(curdir); if (path_ga.ga_len == 0) diff --git a/src/testdir/test73.in b/src/testdir/test73.in index cb2604e68..41865908f 100644 --- a/src/testdir/test73.in +++ b/src/testdir/test73.in @@ -6,7 +6,8 @@ STARTTEST :" delete the Xfind directory during cleanup :" :" This will cause a few errors, do it silently. -:set nocp viminfo+=nviminfo visualbell +:set visualbell +:set nocp viminfo+=nviminfo :" :function! DeleteDirectory(dir) : if has("win16") || has("win32") || has("win64") || has("dos16") || has("dos32") @@ -20,32 +21,33 @@ STARTTEST :call DeleteDirectory("Xfind") :new :let cwd=getcwd() -:!mkdir Xfind +:let test_out = cwd . '/test.out' +:silent !mkdir Xfind :cd Xfind :set path= :find -:w! ../test.out +:exec "w! " . test_out :close :new :set path=. :find -:w >>../test.out +:exec "w >>" . test_out :close :new :set path=.,, :find -:w >>../test.out +:exec "w >>" . test_out :close :new :set path=./** :find -:w >>../test.out +:exec "w >>" . test_out :close :new -:" We shouldn't find any file at this point, ../test.out must be empty. -:!mkdir in +:" We shouldn't find any file at this point, test.out must be empty. +:silent !mkdir in :cd in -:!mkdir path +:silent !mkdir path :exec "cd " . cwd :e Xfind/file.txt SHoly Grail:w @@ -57,40 +59,93 @@ SAnother Holy Grail:w SE.T.:w :set path=Xfind/** :find file -:w >> test.out +:exec "w >>" . test_out :find file -:w >>test.out +:exec "w >>" . test_out :find file -:w >>test.out +:exec "w >>" . test_out :" Rerun the previous three find completions, using fullpath in 'path' :exec "set path=" . cwd . "/Xfind/**" :find file -:w >> test.out +:exec "w >>" . test_out :find file -:w >>test.out +:exec "w >>" . test_out :find file -:w >>test.out +:exec "w >>" . test_out :" Same steps again, using relative and fullpath items that point to the same :" recursive location. :" This is to test that there are no duplicates in the completion list. :exec "set path+=Xfind/**" :find file -:w >> test.out +:exec "w >>" . test_out :find file -:w >>test.out +:exec "w >>" . test_out :find file -:w >>test.out +:exec "w >>" . test_out :find file :" Test find completion for directory of current buffer, which at this point :" is Xfind/in/file.txt. :set path=. :find st -:w >> test.out +:exec "w >>" . test_out :" Test find completion for empty path item ",," which is the current directory :cd Xfind :set path=,, :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 .. :q :call DeleteDirectory("Xfind") diff --git a/src/testdir/test73.ok b/src/testdir/test73.ok index cd787f23a..a54e5f447 100644 --- a/src/testdir/test73.ok +++ b/src/testdir/test73.ok @@ -9,3 +9,9 @@ Jimmy Hoffa E.T. Another Holy Grail Holy Grail +Voyager 1 +Voyager 2 +Voyager 2 +Voyager 1 +Voyager 1 +Voyager 2 |