]> granicus.if.org Git - vim/commitdiff
Improvements for :find completion.
authorBram Moolenaar <Bram@vim.org>
Thu, 12 Aug 2010 19:50:51 +0000 (21:50 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 12 Aug 2010 19:50:51 +0000 (21:50 +0200)
runtime/doc/todo.txt
src/misc1.c
src/testdir/test73.in
src/testdir/test73.ok

index 94dcfdede046d085c71908fc2323a37f24c16f6a..642f52fc1e94c2defa400f0d1f5b04b9e684b2d7 100644 (file)
@@ -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 "./".
index 400ecf158d0af4b6f15693b1503f137319512877..432d36cbec37fbd01e6f1b30122abef55f694366 100644 (file)
@@ -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(&regmatch, 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(&regmatch, 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)
index cb2604e681726dadedc3ea539ed0fc6505cee3e4..41865908fb96356d09520c8ba5503db75d38b3fc 100644 (file)
@@ -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\e:w
@@ -57,40 +59,93 @@ SAnother Holy Grail\e:w
 SE.T.\e: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\e:w
+:e foo/y/bar/voyager.txt
+SVoyager 2\e: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")
index cd787f23a354b4f37b379b5a4772490a6e2fc14d..a54e5f447dd52898adef7a6286e1b0be053108b4 100644 (file)
@@ -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