forked from aniani/vim
		
	Improvements for :find completion.
This commit is contained in:
		| @@ -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 | 		  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. | '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. | Test 73 fails on MS-Windows when compiled with DJGPP. | ||||||
| :find completion with 'path' set to "./**" results in full path for | :find completion with 'path' set to "./**" results in full path for | ||||||
| "./subdir/file", should shorten to start with "./". | "./subdir/file", should shorten to start with "./". | ||||||
|   | |||||||
							
								
								
									
										143
									
								
								src/misc1.c
									
									
									
									
									
								
							
							
						
						
									
										143
									
								
								src/misc1.c
									
									
									
									
									
								
							| @@ -9263,6 +9263,7 @@ is_unique(maybe_unique, gap, i) | |||||||
|     int	    candidate_len; |     int	    candidate_len; | ||||||
|     int	    other_path_len; |     int	    other_path_len; | ||||||
|     char_u  **other_paths = (char_u **)gap->ga_data; |     char_u  **other_paths = (char_u **)gap->ga_data; | ||||||
|  |     char_u  *rival; | ||||||
|  |  | ||||||
|     for (j = 0; j < gap->ga_len && !got_int; j++) |     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) | 	if (other_path_len < candidate_len) | ||||||
| 	    continue;  /* it's different */ | 	    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 */ | 	    return FALSE;  /* match */ | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -9301,8 +9303,6 @@ expand_path_option(curdir, gap) | |||||||
|     char_u	*buf; |     char_u	*buf; | ||||||
|     char_u	*p; |     char_u	*p; | ||||||
|  |  | ||||||
|     ga_init2(gap, (int)sizeof(char_u *), 1); |  | ||||||
|  |  | ||||||
|     if ((buf = alloc((int)MAXPATHL)) == NULL) |     if ((buf = alloc((int)MAXPATHL)) == NULL) | ||||||
| 	return; | 	return; | ||||||
|  |  | ||||||
| @@ -9413,15 +9413,21 @@ uniquefy_paths(gap, pattern) | |||||||
|     int		i; |     int		i; | ||||||
|     int		len; |     int		len; | ||||||
|     char_u	**fnames = (char_u **)gap->ga_data; |     char_u	**fnames = (char_u **)gap->ga_data; | ||||||
|     int		sort_again = 0; |     int		sort_again = FALSE; | ||||||
|     char_u	*pat; |     char_u	*pat; | ||||||
|     char_u      *file_pattern; |     char_u      *file_pattern; | ||||||
|     char_u	*curdir = NULL; |     char_u	*curdir = NULL; | ||||||
|     regmatch_T	regmatch; |     regmatch_T	regmatch; | ||||||
|     garray_T	path_ga; |     garray_T	path_ga; | ||||||
|  |     char_u	**in_curdir = NULL; | ||||||
|  |     char_u	*short_name; | ||||||
|  |  | ||||||
|     sort_strings(fnames, gap->ga_len); |     sort_strings(fnames, gap->ga_len); | ||||||
|     remove_duplicates(gap); |     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 |      * We need to prepend a '*' at the beginning of file_pattern so that the | ||||||
| @@ -9447,17 +9453,21 @@ uniquefy_paths(gap, pattern) | |||||||
| 	return; | 	return; | ||||||
|  |  | ||||||
|     if ((curdir = alloc((int)(MAXPATHL))) == NULL) |     if ((curdir = alloc((int)(MAXPATHL))) == NULL) | ||||||
| 	return; | 	goto theend; | ||||||
|     mch_dirname(curdir, MAXPATHL); |     mch_dirname(curdir, MAXPATHL); | ||||||
|  |  | ||||||
|     expand_path_option(curdir, &path_ga); |     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++) |     for (i = 0; i < gap->ga_len; i++) | ||||||
|     { |     { | ||||||
| 	char_u	    *path = fnames[i]; | 	char_u	    *path = fnames[i]; | ||||||
| 	int	    is_in_curdir; | 	int	    is_in_curdir; | ||||||
| 	char_u	    *dir_end = gettail(path); | 	char_u	    *dir_end = gettail(path); | ||||||
| 	char_u	    *short_name; | 	char_u	    *pathsep_p; | ||||||
|  | 	char_u	    *path_cutoff; | ||||||
|  |  | ||||||
| 	len = (int)STRLEN(path); | 	len = (int)STRLEN(path); | ||||||
| 	while (dir_end > path && | 	while (dir_end > path && | ||||||
| @@ -9468,63 +9478,16 @@ uniquefy_paths(gap, pattern) | |||||||
| #endif | #endif | ||||||
| 		) | 		) | ||||||
| 	    mb_ptr_back(path, dir_end); | 	    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; | 					     && 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) | 	if (is_in_curdir) | ||||||
| 	{ | 	    in_curdir[i] = vim_strsave(path); | ||||||
| 	    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; |  | ||||||
| 	    } |  | ||||||
|  |  | ||||||
| 	    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 | 	else | ||||||
| 	{ | 	    in_curdir[i] = NULL; | ||||||
|  |  | ||||||
| 	/* Shorten the filename while maintaining its uniqueness */ | 	/* Shorten the filename while maintaining its uniqueness */ | ||||||
| 	    char_u *pathsep_p; | 	path_cutoff = get_path_cutoff(path, &path_ga); | ||||||
| 	    char_u *path_cutoff = get_path_cutoff(path, &path_ga); |  | ||||||
|  |  | ||||||
| 	/* we start at the end of the path */ | 	/* we start at the end of the path */ | ||||||
| 	pathsep_p = path + len - 1; | 	pathsep_p = path + len - 1; | ||||||
| @@ -9534,11 +9497,10 @@ uniquefy_paths(gap, pattern) | |||||||
| 		    && is_unique(pathsep_p + 1, gap, i) | 		    && is_unique(pathsep_p + 1, gap, i) | ||||||
| 		    && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) | 		    && path_cutoff != NULL && pathsep_p + 1 >= path_cutoff) | ||||||
| 	    { | 	    { | ||||||
| 		    sort_again = 1; | 		sort_again = TRUE; | ||||||
| 		mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p)); | 		mch_memmove(path, pathsep_p + 1, STRLEN(pathsep_p)); | ||||||
| 		break; | 		break; | ||||||
| 	    } | 	    } | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if (mch_isFullName(path)) | 	if (mch_isFullName(path)) | ||||||
| 	{ | 	{ | ||||||
| @@ -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: | theend: | ||||||
|     vim_free(curdir); |     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); |     ga_clear_strings(&path_ga); | ||||||
|     vim_free(regmatch.regprog); |     vim_free(regmatch.regprog); | ||||||
|  |  | ||||||
| @@ -9598,6 +9620,7 @@ expand_in_path(gap, pattern, flags) | |||||||
| 	return 0; | 	return 0; | ||||||
|     mch_dirname(curdir, MAXPATHL); |     mch_dirname(curdir, MAXPATHL); | ||||||
|  |  | ||||||
|  |     ga_init2(&path_ga, (int)sizeof(char_u *), 1); | ||||||
|     expand_path_option(curdir, &path_ga); |     expand_path_option(curdir, &path_ga); | ||||||
|     vim_free(curdir); |     vim_free(curdir); | ||||||
|     if (path_ga.ga_len == 0) |     if (path_ga.ga_len == 0) | ||||||
|   | |||||||
| @@ -6,7 +6,8 @@ STARTTEST | |||||||
| :" delete the Xfind directory during cleanup | :" delete the Xfind directory during cleanup | ||||||
| :" | :" | ||||||
| :" This will cause a few errors, do it silently. | :" This will cause a few errors, do it silently. | ||||||
| :set nocp viminfo+=nviminfo visualbell | :set visualbell | ||||||
|  | :set nocp viminfo+=nviminfo | ||||||
| :" | :" | ||||||
| :function! DeleteDirectory(dir) | :function! DeleteDirectory(dir) | ||||||
| : if has("win16") || has("win32") || has("win64") || has("dos16") || has("dos32") | : if has("win16") || has("win32") || has("win64") || has("dos16") || has("dos32") | ||||||
| @@ -20,32 +21,33 @@ STARTTEST | |||||||
| :call DeleteDirectory("Xfind") | :call DeleteDirectory("Xfind") | ||||||
| :new | :new | ||||||
| :let cwd=getcwd() | :let cwd=getcwd() | ||||||
| :!mkdir Xfind | :let test_out = cwd . '/test.out' | ||||||
|  | :silent !mkdir Xfind | ||||||
| :cd Xfind | :cd Xfind | ||||||
| :set path= | :set path= | ||||||
| :find 	 | :find 	 | ||||||
| :w! ../test.out | :exec "w! " . test_out | ||||||
| :close | :close | ||||||
| :new | :new | ||||||
| :set path=. | :set path=. | ||||||
| :find 	 | :find 	 | ||||||
| :w >>../test.out | :exec "w >>" . test_out | ||||||
| :close | :close | ||||||
| :new | :new | ||||||
| :set path=.,, | :set path=.,, | ||||||
| :find 	 | :find 	 | ||||||
| :w >>../test.out | :exec "w >>" . test_out | ||||||
| :close | :close | ||||||
| :new | :new | ||||||
| :set path=./** | :set path=./** | ||||||
| :find 	 | :find 	 | ||||||
| :w >>../test.out | :exec "w >>" . test_out | ||||||
| :close | :close | ||||||
| :new | :new | ||||||
| :" We shouldn't find any file at this point, ../test.out must be empty. | :" We shouldn't find any file at this point, test.out must be empty. | ||||||
| :!mkdir in | :silent !mkdir in | ||||||
| :cd in | :cd in | ||||||
| :!mkdir path | :silent !mkdir path | ||||||
| :exec "cd " . cwd | :exec "cd " . cwd | ||||||
| :e Xfind/file.txt | :e Xfind/file.txt | ||||||
| SHoly Grail:w | SHoly Grail:w | ||||||
| @@ -57,40 +59,93 @@ SAnother Holy Grail:w | |||||||
| SE.T.:w | SE.T.:w | ||||||
| :set path=Xfind/** | :set path=Xfind/** | ||||||
| :find file	 | :find file	 | ||||||
| :w >> test.out | :exec "w >>" . test_out | ||||||
| :find file		 | :find file		 | ||||||
| :w >>test.out | :exec "w >>" . test_out | ||||||
| :find file			 | :find file			 | ||||||
| :w >>test.out | :exec "w >>" . test_out | ||||||
| :" Rerun the previous three find completions, using fullpath in 'path' | :" Rerun the previous three find completions, using fullpath in 'path' | ||||||
| :exec "set path=" . cwd . "/Xfind/**" | :exec "set path=" . cwd . "/Xfind/**" | ||||||
| :find file	 | :find file	 | ||||||
| :w >> test.out | :exec "w >>" .  test_out | ||||||
| :find file		 | :find file		 | ||||||
| :w >>test.out | :exec "w >>" . test_out | ||||||
| :find file			 | :find file			 | ||||||
| :w >>test.out | :exec "w >>" . test_out | ||||||
| :" Same steps again, using relative and fullpath items that point to the same | :" Same steps again, using relative and fullpath items that point to the same | ||||||
| :" recursive location. | :" recursive location. | ||||||
| :" This is to test that there are no duplicates in the completion list. | :" This is to test that there are no duplicates in the completion list. | ||||||
| :exec "set path+=Xfind/**" | :exec "set path+=Xfind/**" | ||||||
| :find file	 | :find file	 | ||||||
| :w >> test.out | :exec "w >>" .  test_out | ||||||
| :find file		 | :find file		 | ||||||
| :w >>test.out | :exec "w >>" . test_out | ||||||
| :find file			 | :find file			 | ||||||
| :w >>test.out | :exec "w >>" . test_out | ||||||
| :find file		 | :find file		 | ||||||
| :" Test find completion for directory of current buffer, which at this point | :" Test find completion for directory of current buffer, which at this point | ||||||
| :" is Xfind/in/file.txt. | :" is Xfind/in/file.txt. | ||||||
| :set path=. | :set path=. | ||||||
| :find st	 | :find st	 | ||||||
| :w >> test.out | :exec "w >>" .  test_out | ||||||
| :" Test find completion for empty path item ",," which is the current directory | :" Test find completion for empty path item ",," which is the current directory | ||||||
| :cd Xfind | :cd Xfind | ||||||
| :set path=,, | :set path=,, | ||||||
| :find f		 | :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:w | ||||||
|  | :e foo/y/bar/voyager.txt | ||||||
|  | SVoyager 2: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 .. | :cd .. | ||||||
| :q | :q | ||||||
| :call DeleteDirectory("Xfind") | :call DeleteDirectory("Xfind") | ||||||
|   | |||||||
| @@ -9,3 +9,9 @@ Jimmy Hoffa | |||||||
| E.T. | E.T. | ||||||
| Another Holy Grail | Another Holy Grail | ||||||
| Holy Grail | Holy Grail | ||||||
|  | Voyager 1 | ||||||
|  | Voyager 2 | ||||||
|  | Voyager 2 | ||||||
|  | Voyager 1 | ||||||
|  | Voyager 1 | ||||||
|  | Voyager 2 | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user