On Sat, Jul 24, 2010 at 8:59 AM, Nazri Ramliy <[email protected]> wrote:
> I'll look into this again sometime next week.
It's done.
Please have a look at the patches - 0001 is the major one (have a look at the
two FIXMEs), while 0002 and 0003 are the minor fixes and documentation update
on the limitation of the completion when 'path' has upward search (;) and
directory limiter (/usr/**N) notations.
I'm sorry that I don't have access to a windows machine at the moment to
investigate the bug reports that people are reporting [1].
If anyone want to give a shot at fixing the bug the following information might
be useful:
The completion for find/sfind/tabfind is first handled by
misc1.c:expand_in_path() - it does the following:
1. Expand relative path entries in your 'path' setting into a list of
their equivalent full path directories:
"." is expanded to the directory of the current file
",," (empty) is expanded to the current directory
foo is expanded to /current/directory/foo
The non-relative entries are left intact.
2. Joins the full path names in the previous step (with ",") and calls
globpath().
3. The matching list of full path file names are filtered through
misc1.c:uniquefy_paths() to shorten the filename while still keeping
them unique. If that is not possible then the fullname is used
instead.
If you would like to help making the completion works for the upward search (;)
and directory limiter notations (/usr/**N) the place to modify is the function
misc1.c:expand_path_option().
nazri.
[1] http://article.gmane.org/gmane.editors.vim.devel/27384
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
From 20b33f7376ce4852a1506757bb32b2db2fe095af Mon Sep 17 00:00:00 2001
From: nazri <[email protected]>
Date: Mon, 26 Jul 2010 12:57:33 +0800
Subject: [PATCH 1/3] find/sfind/tabfind completion: disambiguate completion list
Keep the full path if the unique file name could not be found with the
:find command.
---
src/misc1.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 220 insertions(+), 16 deletions(-)
diff --git a/src/misc1.c b/src/misc1.c
index 9371760..ed5025a 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -9298,7 +9298,7 @@ is_unique(maybe_unique, gap, i)
if (other_path_len < candidate_len)
continue; /* it's different */
- rival = other_paths[j] + other_path_len - candidate_len;
+ rival = gettail(other_paths[j]);
if (fnamecmp(maybe_unique, rival) == 0)
return FALSE;
@@ -9331,6 +9331,106 @@ 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 garray_T
+expand_path_option(curdir)
+ char_u *curdir;
+{
+ char_u *path_option = *curbuf->b_p_path == NUL
+ ? p_path : curbuf->b_p_path;
+ garray_T ga;
+ char_u *buf;
+
+ ga_init2(&ga, (int)sizeof(char_u *), 1);
+
+ if ((buf = alloc((int)(MAXPATHL))) == NULL)
+ return ga;
+
+ while (*path_option != NUL)
+ {
+ copy_option_part(&path_option, buf, MAXPATHL, " ,");
+
+ if (STRCMP(buf, ".") == 0) /* relative to current buffer */
+ {
+ char_u *p;
+ if (curbuf->b_ffname == NULL)
+ continue;
+
+ STRCPY(buf, curbuf->b_ffname);
+ p = gettail(buf);
+ *p = '\0';
+ }
+ else if (buf[0] == '\0') /* 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(&ga, buf, EW_NOTFOUND|EW_DIR|EW_FILE);
+ }
+
+ vim_free(buf);
+
+ return ga;
+}
+
+/*
+ * 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 *cutoff = NULL;
+
+ path_part = (char_u **) gap->ga_data;
+ for (i = 0; i < gap->ga_len; i++)
+ {
+ int c = 0;
+ while (fname[c] == path_part[i][c] && fname[c] != '\0' &&
+ path_part[i][c] != '\0')
+ c++;
+ if (c > maxlen)
+ {
+ maxlen = c;
+ cutoff = &fname[c];
+ }
+ }
+
+ /* Skip to the file or directory name */
+ while (cutoff != NULL && vim_ispathsep(*cutoff) && *cutoff != '\0')
+ 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
* matches the pattern. Beware, this is at least O(n^2) wrt gap->ga_len.
@@ -9342,13 +9442,14 @@ uniquefy_paths(gap, pattern)
{
int i;
int len;
- char_u *pathsep_p;
- char_u *path;
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,6 +9461,8 @@ 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';
STRCAT(file_pattern, pattern);
@@ -9374,25 +9477,96 @@ uniquefy_paths(gap, pattern)
if (regmatch.regprog == NULL)
return;
+ if ((curdir = alloc((int)(MAXPATHL))) == NULL)
+ return;
+ mch_dirname(curdir, MAXPATHL);
+ len_curdir = STRLEN(curdir);
+
+ path_ga = expand_path_option(curdir);
+
for (i = 0; i < gap->ga_len; i++)
{
- path = fnames[i];
+ char_u *path = fnames[i];
+ int is_in_curdir;
len = (int)STRLEN(path);
- /* we start at the end of the path */
- pathsep_p = path + len - 1;
+ char_u *dir_end = gettail(path);
+ while (!vim_ispathsep(*dir_end))
+ mb_ptr_back(path, dir_end);
+ /* We cheat a little */
+ *dir_end = '\0';
+ is_in_curdir = ! STRCMP(curdir, path);
+ *dir_end = PATHSEP;
+
+ /*
+ * If the file is in the current directory,
+ * and it is not unique,
+ * reduce it to ./{filename}
+ * FIXME ^ Is this portable?
+ */
- while (find_previous_pathsep(path, &pathsep_p))
- if (vim_regexec(®match, pathsep_p + 1, (colnr_T)0)
- && is_unique(pathsep_p, gap, i))
+ 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))
{
- 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 < STRLEN(rel_path))
+ {
+ vim_free(fnames[i]);
+ fnames[i] = alloc((int)(STRLEN(rel_path) + 1));
+ if (fnames[i] == NULL)
+ 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(®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;
+ }
+ }
+
}
+theend:
+ vim_free(curdir);
+ ga_clear_strings(&path_ga);
vim_free(regmatch.regprog);
+
if (sort_again)
{
sort_strings(fnames, gap->ga_len);
@@ -9412,13 +9586,43 @@ 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);
+
+ path_ga = expand_path_option(curdir);
+ 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;
--
1.7.2
From 0b6aefe9dd97809692f72fcf540718866768b19d Mon Sep 17 00:00:00 2001
From: nazri <[email protected]>
Date: Fri, 23 Jul 2010 16:44:57 +0800
Subject: [PATCH 2/3] Skip url path when doing completion for find/sfind/tabfind
---
src/ex_getln.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/src/ex_getln.c b/src/ex_getln.c
index 7b7874a..883e3af 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -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);
--
1.7.2
From e07273adb12733f547c5a91b9f2d9e18aac446b4 Mon Sep 17 00:00:00 2001
From: nazri <[email protected]>
Date: Fri, 23 Jul 2010 16:17:09 +0800
Subject: [PATCH 3/3] Add note on limitation of find/sfind/tabfind completion
---
runtime/doc/editing.txt | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 73a8ea4..b5d6d95 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1625,7 +1625,10 @@ There are three different types of searching:
< This searches: >
/u/user_x/work/release/**
/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' settings that contain url or use the limiter
+ (/usr/**2) and upward search (;) notations. >
vim:tw=78:ts=8:ft=help:norl:
--
1.7.2