]> granicus.if.org Git - vim/commitdiff
Improvements for ":find" completion. (Nazri Ramliy)
authorBram Moolenaar <Bram@vim.org>
Wed, 28 Jul 2010 20:29:10 +0000 (22:29 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 28 Jul 2010 20:29:10 +0000 (22:29 +0200)
runtime/doc/editing.txt
runtime/doc/todo.txt
src/ex_getln.c
src/misc1.c

index 73a8ea49da23a6bed97f4d392d5050848a755169..6ae67a556f3a0d7f3aebc4006cbf629ddc14bd7f 100644 (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
@@ -1622,10 +1622,13 @@ There are three different types of searching:
 
    In the above example you might want to set path to: >
        :set path=**,/u/user_x/**
-<   This searches: >
-       /u/user_x/work/release/**
-       /u/user_x/**
-<   This searches the same directories, but in a different order.
-
+<  This searches:
+       /u/user_x/work/release/** ~
+       /u/user_x/** ~
+   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:
index 469fc4317a1ec8d284527e23d476e09c32eb4d77..743eaf73628bc6ec0c19d76530dc57596b980fb3 100644 (file)
@@ -30,22 +30,20 @@ be worked on, but only if you sponsor Vim development.  See |sponsor|.
                                                        *known-bugs*
 -------------------- Known bugs and current work -----------------------
 
-Patch for :find completion. (Nazri Ramliy, 2010 Jul 27, and leak fix)
-And patch for Windows, Jul 28.
-And fix for patch, Jul 28.
+Patch for :filetype completion. (Dominique Pelle, Jul 28)
 
 Windows 7: "Open with..." menu starts Vim without a file.
 
 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
 
 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:
 - Rename vim73 branch to default (hints: Xavier de Gaye, 2010 May 23)
index 7b7874ad4fdca1092135b4fa1721f3d78542bde1..dfd163dfe084b4d87f7fdb359ffc01f8af0ae65d 100644 (file)
@@ -5033,6 +5033,12 @@ globpath(path, file, expand_options)
     {
        /* Copy one item of the path to buf[] and concatenate the file name. */
        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)
        {
            add_pathsep(buf);
index 9371760a4761ffa1ee93daf0be6ded0bca72bf2f..c6ac00157b8984179ca75728768cda82ef2b75da 100644 (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 is_unique __ARGS((char_u *maybe_unique, garray_T *gap, int i));
 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 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
- * is the end portion of ((char_u **)gap->ga_data)[i].
+ * Returns TRUE if "maybe_unique" is unique wrt other_paths in gap.
+ * "maybe_unique" is the end portion of ((char_u **)gap->ga_data)[i].
  */
     static int
 is_unique(maybe_unique, gap, i)
@@ -9279,32 +9281,24 @@ is_unique(maybe_unique, gap, i)
     int            j;
     int            candidate_len;
     int            other_path_len;
-    char_u  *rival;
-    char_u  **other_paths;
-
-    other_paths = (gap->ga_data != NULL) ? (char_u **)gap->ga_data
-                                                             : (char_u **)"";
+    char_u  **other_paths = (char_u **)gap->ga_data;
 
     for (j = 0; j < gap->ga_len && !got_int; j++)
     {
        ui_breakcheck();
-       /* don't compare it with itself */
        if (j == i)
-           continue;
+           continue;  /* don't compare it with itself */
 
        candidate_len = (int)STRLEN(maybe_unique);
        other_path_len = (int)STRLEN(other_paths[j]);
-
        if (other_path_len < candidate_len)
            continue;  /* it's different */
 
-       rival = other_paths[j] + other_path_len - candidate_len;
-
-       if (fnamecmp(maybe_unique, rival) == 0)
-           return FALSE;
+       if (fnamecmp(maybe_unique, gettail(other_paths[j])) == 0)
+           return FALSE;  /* match */
     }
 
-    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
  * they are unique with respect to each other while conserving the part that
@@ -9342,13 +9431,14 @@ uniquefy_paths(gap, pattern)
 {
     int                i;
     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;
     char_u     *pat;
     char_u      *file_pattern;
+    char_u     *curdir = NULL;
+    int                len_curdir = 0;
     regmatch_T regmatch;
+    garray_T   path_ga;
 
     sort_strings(fnames, gap->ga_len);
     remove_duplicates(gap);
@@ -9360,8 +9450,10 @@ uniquefy_paths(gap, pattern)
      */
     len = (int)STRLEN(pattern);
     file_pattern = alloc(len + 2);
+    if (file_pattern == NULL)
+       return;
     file_pattern[0] = '*';
-    file_pattern[1] = '\0';
+    file_pattern[1] = NUL;
     STRCAT(file_pattern, pattern);
     pat = file_pat_to_reg_pat(file_pattern, NULL, NULL, TRUE);
     vim_free(file_pattern);
@@ -9374,25 +9466,95 @@ uniquefy_paths(gap, pattern)
     if (regmatch.regprog == NULL)
        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++)
     {
-       path = fnames[i];
+       char_u      *path = fnames[i];
+       int         is_in_curdir;
+       char_u      *dir_end = gettail(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;
 
-       /* we start at the end of the path */
-       pathsep_p = path + len - 1;
+       /*
+        * 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);
 
-       while (find_previous_pathsep(path, &pathsep_p))
-           if (vim_regexec(&regmatch, pathsep_p + 1, (colnr_T)0)
-                                             && is_unique(pathsep_p, gap, i))
+           if (short_name == NULL)
+               short_name = path;
+           if (is_unique(short_name, gap, i))
            {
-               sort_again = 1;
-               mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
-               break;
+               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 */
+           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;
+               }
+       }
     }
 
+theend:
+    vim_free(curdir);
+    ga_clear_strings(&path_ga);
     vim_free(regmatch.regprog);
+
     if (sort_again)
     {
        sort_strings(fnames, gap->ga_len);
@@ -9412,23 +9574,53 @@ expand_in_path(gap, pattern, flags)
     int                flags;          /* EW_* flags */
 {
     int                c = 0;
-    char_u     *path_option = *curbuf->b_p_path == NUL
-                                                 ? p_path : curbuf->b_p_path;
-    char_u     *files;
+    char_u     *files = NULL;
     char_u     *s;     /* start */
     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)
        return 0;
 
     /* Copy each path in files into gap */
     s = e = files;
-    while (*s != '\0')
+    while (*s != NUL)
     {
-       while (*e != '\n' && *e != '\0')
+       while (*e != '\n' && *e != NUL)
            e++;
-       if (*e == '\0')
+       if (*e == NUL)
        {
            addfile(gap, s, flags);
            break;
@@ -9436,7 +9628,7 @@ expand_in_path(gap, pattern, flags)
        else
        {
            /* *e is '\n' */
-           *e = '\0';
+           *e = NUL;
            addfile(gap, s, flags);
            e++;
            s = e;
@@ -9817,7 +10009,7 @@ get_cmd_output(cmd, infile, flags)
        buffer = NULL;
     }
     else
-       buffer[len] = '\0';     /* make sure the buffer is terminated */
+       buffer[len] = NUL;      /* make sure the buffer is terminated */
 
 done:
     vim_free(tempname);