On Sat, Feb 21, 2009 at 10:38 PM, Dominique Pelle
<dominique.pe...@gmail.com> wrote:
> I'm trying your patch on Linux x86 (from Vim-7.2.108).
> I notice something broken.
>
> I do:
>
>  $ mkdir foobar/
>  $ vim -u NONE
>  set nocompatible
>  set wildmode=longest,list
>  set wildmenu
>  set path=.
>
> If I type:
>
>   :find foo<tab>
>
> I would expect to complete up to foobar/  (it does
> that without patch) but after patch it does not complete
> the directory name anymore.

Thanks for trying it out and reporting the problem.

It happens during the 'uniquefying' process. To be specific it's the
find_previous_pathsep function. The foobar/ name gets uniquefied as an
empty string due the ending slash.

During fixing this I (carefully) read :he 'path' and noticed that the
completion should also be applied to :tabfind, and it should not be
applied when the path is a fullpath or starts with a dot.

Attached patch correct the mentioned problem(s).

nazri

--~--~---------~--~----~------------~-------~--~----~
You received this message from the "vim_dev" maillist.
For more information, visit http://www.vim.org/maillist.php
-~----------~----~----~----~------~----~------~--~---

Index: ex_docmd.c
===================================================================
--- ex_docmd.c	(revision 1365)
+++ ex_docmd.c	(working copy)
@@ -3422,6 +3422,11 @@
  */
     switch (ea.cmdidx)
     {
+	case CMD_find:
+	case CMD_sfind:
+	case CMD_tabfind:
+	    xp->xp_context = EXPAND_FILES_IN_PATH;
+	    break;
 	case CMD_cd:
 	case CMD_chdir:
 	case CMD_lcd:
Index: ex_getln.c
===================================================================
--- ex_getln.c	(revision 1365)
+++ ex_getln.c	(working copy)
@@ -4063,6 +4063,7 @@
     char_u	*tail;
 
     if (context != EXPAND_FILES
+	    && context != EXPAND_FILES_IN_PATH
 	    && context != EXPAND_SHELLCMD
 	    && context != EXPAND_DIRECTORIES)
     {
@@ -4377,7 +4378,9 @@
     if (options & WILD_SILENT)
 	flags |= EW_SILENT;
 
-    if (xp->xp_context == EXPAND_FILES || xp->xp_context == EXPAND_DIRECTORIES)
+    if (xp->xp_context == EXPAND_FILES
+	    || xp->xp_context == EXPAND_DIRECTORIES
+	    || xp->xp_context == EXPAND_FILES_IN_PATH)
     {
 	/*
 	 * Expand file or directory names.
@@ -4407,6 +4410,8 @@
 
 	if (xp->xp_context == EXPAND_FILES)
 	    flags |= EW_FILE;
+	else if (xp->xp_context == EXPAND_FILES_IN_PATH)
+	    flags |= (EW_FILE | EW_PATH);
 	else
 	    flags = (flags | EW_DIR) & ~EW_FILE;
 	ret = expand_wildcards(1, &pat, num_file, file, flags);
Index: misc1.c
===================================================================
--- misc1.c	(revision 1365)
+++ misc1.c	(working copy)
@@ -9097,7 +9097,254 @@
 }
 #endif
 
+#if defined(FEAT_SEARCHPATH)
+/* 
+ * Expand the files matching pattern, starting from the given path, save
+ * the matches in their equivalent fullpath.
+ */
+    static int
+expand_to_fullpath(path, gap, pattern, flags)
+    char_u	*path;
+    garray_T	*gap;
+    char_u	*pattern;
+    int		flags;		/* EW_* flags */
+{
+    int	    i;
+    int	    c;
+    int	    old_len;
+    int	    new_len;
+    char_u  **files;
+    char_u  *fullpath;
+
+    old_len = gap->ga_len;
+    c = mch_expandpath(gap, pattern, flags);
+
+    files = (gap->ga_data != NULL) ? (char_u **)gap->ga_data : (char_u **)"";
+    new_len = gap->ga_len;
+
+    for(i = old_len; i < new_len; i++)
+    {
+	fullpath = concat_fnames(path, files[i], TRUE);
+	vim_free(files[i]);
+	files[i] = fullpath;
+    }
+    return c;
+}
+
 /*
+ * Moves psep to the previous path separator in path, starting from the
+ * end of path. Returns FAIL is psep ends up at the beginning of path.
+ */
+    static int
+find_previous_pathsep(path, psep)
+    char_u *path;
+    char_u **psep;
+{
+    /* 
+     * As we're looking for the previous path separator, skip the current
+     * separator.
+     */ 
+    if (vim_ispathsep(**psep))
+	(*psep)--;
+
+    while (*psep >= path && !vim_ispathsep(**psep))
+	(*psep)--;
+
+    if (*psep != path && vim_ispathsep(**psep))
+	return OK;
+
+    return FAIL;
+}
+
+/*
+ * 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)
+    char_u	*maybe_unique;
+    garray_T	*gap;
+    int		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 **)"";
+
+    for (j = 0; j < gap->ga_len && !got_int; j++)
+    {
+	/* Don't compare it with itself */
+	if(j == i)
+	    continue;
+
+	candidate_len = STRLEN(maybe_unique);
+	other_path_len = STRLEN(other_paths[j]);
+
+	if(other_path_len < candidate_len)
+	    /* It's different, */
+	    continue;
+
+	rival = other_paths[j] + other_path_len - candidate_len;
+
+	if (fnamecmp(maybe_unique, rival) == 0)
+	    return FALSE;
+    }
+
+    return TRUE;
+}
+
+/*
+ * Sorts, removes duplicates and modifies all the fullpath names in gap so that
+ * they are unique with respect to each other. Beware, this is at least O(n^2)
+ * wrt gap->ga_len.
+ */
+    static void
+uniquefy_paths(gap)
+    garray_T *gap;
+{
+    int	    i;
+    int	    path_len;
+    char_u  *pathsep_p;
+    char_u  *path;
+    char_u  **fnames = (char_u **) gap->ga_data;
+
+    int j;
+    int sort_again = 0;
+
+    /* Remove duplicate entries */
+    sort_strings(fnames, gap->ga_len);
+    for (i = 0; i < gap->ga_len - 1; i++)
+	if (fnamecmp(fnames[i], fnames[i+1]) == 0)
+	{
+	    vim_free(fnames[i]);
+	    for (j = i+1; j < gap->ga_len; j++)
+		fnames[j-1] = fnames[j];
+	    gap->ga_len--;
+	    i--;
+	}
+
+    for (i = 0; i < gap->ga_len; i++)
+    {
+	path = fnames[i];
+	path_len = STRLEN(path);
+
+	/* We start at the end of the path */
+	pathsep_p = path + path_len - 1;
+
+	while (find_previous_pathsep(path, &pathsep_p))
+	    if (is_unique(pathsep_p, gap, i))
+	    {
+		sort_again = 1;
+		mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p));
+		break;
+	    }
+    }
+
+    if (sort_again)
+	sort_strings(fnames, gap->ga_len);
+}
+
+/* 
+ * Calls mch_expandpath for each 'path' values for the given pattern and stores
+ * the result in gap. Returns the total number of match.
+ */
+    static int
+expand_in_path(gap, pattern, flags)
+    garray_T	*gap;
+    char_u	*pattern;
+    int		flags;		/* EW_* flags */
+{
+    /*
+     * For each expandable 'path' option values we get the list of all
+     * directories and expand the file names in each the directories.
+     */
+    int	    c = 0;
+    char_u  *cwd = NULL;
+    char_u  *cwd_orig = NULL;
+    char_u  *path_opt;
+    char_u  *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path;
+
+    if ((cwd_orig = alloc((int)(MAXPATHL))) == NULL ||
+	    (cwd = alloc((int)(MAXPATHL))) == NULL ||
+	    (path_opt = alloc((int)(MAXPATHL))) == NULL)
+	return 0; /* FIXME Give emsg instead? */
+
+    if (getcwd((char *)cwd_orig, MAXPATHL) == NULL)
+	/* FIXME The directory may have been deleted, is it ok to ignore it? */
+	;
+
+    /* 
+     * Search for matching files in each 'path' options.
+     * TODO Detect circular paths (symbolic links to path)
+     */
+    for(;;)
+    {
+	int		i;
+	int		dir_count;
+	garray_T	ga_dirs;
+
+	path_opt[0] = 0;
+	copy_option_part(&path_option, path_opt, MAXPATHL, " ;,");
+
+	STRCPY(cwd, cwd_orig);
+
+	if (mch_isFullName(path_opt))
+	    STRCPY(cwd, path_opt);
+	else
+	{
+	    char_u *fullpath;
+
+	    fullpath = concat_fnames(cwd_orig, path_opt, TRUE);
+	    if (fullpath == NULL)
+		continue; /* FIXME Give emsg too? */
+
+	    STRNCPY(cwd, fullpath, MAXPATHL);
+	    vim_free(fullpath);
+	}
+
+	ga_init2(&ga_dirs, (int)sizeof(char_u *), 30);
+	dir_count = mch_expandpath(&ga_dirs, cwd, EW_DIR|EW_SILENT);
+
+	if (dir_count == 0)
+	{
+	    if (mch_chdir(cwd) == 0)
+		c += expand_to_fullpath(cwd, gap, pattern, flags);
+	}
+	else 
+	{
+	    /* Add files from each expanded path. */
+	    int	    i;
+	    char_u  **tmpdirs;
+	    tmpdirs = (ga_dirs.ga_data != NULL) ? (char_u **)ga_dirs.ga_data 
+							      : (char_u **)"";
+	    for (i = 0; i < dir_count && !got_int ; i++)
+	    {
+		/* FIXME Skip symbolic links to avoid cycle */
+		if (mch_chdir(tmpdirs[i]) == 0)
+		    c += expand_to_fullpath(tmpdirs[i], gap, pattern, flags);
+	    }
+	}
+	ga_clear_strings(&ga_dirs);
+
+	if (path_option == NULL || *path_option == NUL)
+	    break;
+    }
+
+    if (mch_chdir(cwd_orig) != 0)
+	/*  FIXME Is it safe to ignore this? */ ;
+
+    vim_free(path_opt);
+    vim_free(cwd);
+    vim_free(cwd_orig);
+
+    return c;
+}
+#endif
+
+/*
  * Generic wildcard expansion code.
  *
  * Characters in "pat" that should not be expanded must be preceded with a
@@ -9205,7 +9452,14 @@
 	     * when EW_NOTFOUND is given.
 	     */
 	    if (mch_has_exp_wildcard(p))
-		add_pat = mch_expandpath(&ga, p, flags);
+	    {
+#if defined(FEAT_SEARCHPATH)
+		if (*p != '.' && !vim_ispathsep(*p) && flags & EW_PATH)
+		    add_pat = expand_in_path(&ga, p, flags);
+		else
+#endif
+		    add_pat = mch_expandpath(&ga, p, flags);
+	    }
 	}
 
 	if (add_pat == -1 || (add_pat == 0 && (flags & EW_NOTFOUND)))
@@ -9228,6 +9482,9 @@
 	    vim_free(p);
     }
 
+    if (flags & EW_PATH)
+	uniquefy_paths(&ga);
+
     *num_file = ga.ga_len;
     *file = (ga.ga_data != NULL) ? (char_u **)ga.ga_data : (char_u **)"";
 
Index: vim.h
===================================================================
--- vim.h	(revision 1365)
+++ vim.h	(working copy)
@@ -708,6 +708,7 @@
 #define EXPAND_USER_DEFINED	30
 #define EXPAND_USER_LIST	31
 #define EXPAND_SHELLCMD		32
+#define EXPAND_FILES_IN_PATH    33
 
 /* Values for exmode_active (0 is no exmode) */
 #define EXMODE_NORMAL		1
@@ -739,6 +740,7 @@
 #define EW_KEEPALL	0x10	/* keep all matches */
 #define EW_SILENT	0x20	/* don't print "1 returned" from shell */
 #define EW_EXEC		0x40	/* executable files */
+#define EW_PATH		0x80	/* search in 'path' too */
 /* Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND
  * is used when executing commands and EW_SILENT for interactive expanding. */
 

Raspunde prin e-mail lui