# HG changeset patch # User Bram Moolenaar # Date 1280348950 -7200 # Node ID 7ce8b24450dcd70ad3c359085575b0cf6facaf4b # Parent 33148c37f3c9042e11218b250e441aec30ecb0e1 Improvements for ":find" completion. (Nazri Ramliy) diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -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 @@ 3) Combined up/downward search: 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: diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt --- a/runtime/doc/todo.txt +++ b/runtime/doc/todo.txt @@ -30,23 +30,21 @@ be worked on, but only if you sponsor Vi *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. +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"? + 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". - Before release 7.3: - Rename vim73 branch to default (hints: Xavier de Gaye, 2010 May 23) diff --git a/src/ex_getln.c b/src/ex_getln.c --- 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); diff --git a/src/misc1.c b/src/misc1.c --- a/src/misc1.c +++ b/src/misc1.c @@ -9239,6 +9239,8 @@ unix_expandpath(gap, path, wildoff, flag 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; - } - - return TRUE; + if (fnamecmp(maybe_unique, gettail(other_paths[j])) == 0) + return FALSE; /* match */ + } + + return TRUE; /* no match found */ } /* @@ -9331,6 +9325,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 * matches the pattern. Beware, this is at least O(n^2) wrt gap->ga_len. @@ -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); - - /* 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, gap, i)) - { - sort_again = 1; - mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p)); - break; - } - } - + 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; + + /* + * 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); + + if (short_name == NULL) + short_name = path; + if (is_unique(short_name, gap, i)) + { + 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(®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,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 */ - - files = globpath(path_option, pattern, 0); + 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); + if (files == NULL) return 0; /* Copy each path in files into gap */ s = e = files; - while (*s != '\0') - { - while (*e != '\n' && *e != '\0') + while (*s != NUL) + { + 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);