Merge pull request #21851 from zeertzjq/vim-8.2.4482

vim-patch:8.2.{4482,4485}: fuzzy cmdline custom completion
This commit is contained in:
zeertzjq 2023-01-17 16:16:44 +08:00 committed by GitHub
commit fc692dfce1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 320 additions and 150 deletions

View File

@ -1432,9 +1432,11 @@ The function arguments are:
The function may use these for determining context. For the "custom" The function may use these for determining context. For the "custom"
argument, it is not necessary to filter candidates against the (implicit argument, it is not necessary to filter candidates against the (implicit
pattern in) ArgLead. Vim will filter the candidates with its regexp engine pattern in) ArgLead. Vim will filter the candidates with its regexp engine
after function return, and this is probably more efficient in most cases. For after function return, and this is probably more efficient in most cases. If
the "customlist" argument, Vim will not filter the returned completion 'wildoptions' contains "fuzzy", then the candidates will be filtered using
candidates and the user supplied function should filter the candidates. |fuzzy-matching|. For the "customlist" argument, Vim will not
filter the returned completion candidates and the user supplied function
should filter the candidates.
The following example lists user names to a Finger command > The following example lists user names to a Finger command >
:com -complete=custom,ListUsers -nargs=1 Finger !finger <args> :com -complete=custom,ListUsers -nargs=1 Finger !finger <args>

View File

@ -7126,7 +7126,7 @@ A jump table for the options with a short description can be found at |Q_op|.
global global
A list of words that change how |cmdline-completion| is done. A list of words that change how |cmdline-completion| is done.
The following values are supported: The following values are supported:
fuzzy Use fuzzy matching to find completion matches. When fuzzy Use |fuzzy-matching| to find completion matches. When
this value is specified, wildcard expansion will not this value is specified, wildcard expansion will not
be used for completion. The matches will be sorted by be used for completion. The matches will be sorted by
the "best match" rather than alphabetically sorted. the "best match" rather than alphabetically sorted.

View File

@ -105,18 +105,20 @@ static bool cmdline_fuzzy_completion_supported(const expand_T *const xp)
&& xp->xp_context != EXPAND_FILES_IN_PATH && xp->xp_context != EXPAND_FILES_IN_PATH
&& xp->xp_context != EXPAND_FILETYPE && xp->xp_context != EXPAND_FILETYPE
&& xp->xp_context != EXPAND_HELP && xp->xp_context != EXPAND_HELP
&& xp->xp_context != EXPAND_LUA
&& xp->xp_context != EXPAND_OLD_SETTING && xp->xp_context != EXPAND_OLD_SETTING
&& xp->xp_context != EXPAND_OWNSYNTAX && xp->xp_context != EXPAND_OWNSYNTAX
&& xp->xp_context != EXPAND_PACKADD && xp->xp_context != EXPAND_PACKADD
&& xp->xp_context != EXPAND_SHELLCMD && xp->xp_context != EXPAND_SHELLCMD
&& xp->xp_context != EXPAND_TAGS && xp->xp_context != EXPAND_TAGS
&& xp->xp_context != EXPAND_TAGS_LISTFILES && xp->xp_context != EXPAND_TAGS_LISTFILES
&& xp->xp_context != EXPAND_USER_DEFINED && xp->xp_context != EXPAND_USER_LIST
&& xp->xp_context != EXPAND_USER_LIST; && xp->xp_context != EXPAND_USER_LUA;
} }
/// Returns true if fuzzy completion for cmdline completion is enabled and /// Returns true if fuzzy completion for cmdline completion is enabled and
/// "fuzzystr" is not empty. /// "fuzzystr" is not empty. If search pattern is empty, then don't use fuzzy
/// matching.
bool cmdline_fuzzy_complete(const char *const fuzzystr) bool cmdline_fuzzy_complete(const char *const fuzzystr)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
{ {
@ -2585,16 +2587,10 @@ static int ExpandOther(char *pat, expand_T *xp, regmatch_T *rmp, char ***matches
// right function to do the expansion. // right function to do the expansion.
for (int i = 0; i < (int)ARRAY_SIZE(tab); i++) { for (int i = 0; i < (int)ARRAY_SIZE(tab); i++) {
if (xp->xp_context == tab[i].context) { if (xp->xp_context == tab[i].context) {
// Use fuzzy matching if 'wildoptions' has "fuzzy".
// If no search pattern is supplied, then don't use fuzzy
// matching and return all the found items.
const bool fuzzy = cmdline_fuzzy_complete(pat);
if (tab[i].ic) { if (tab[i].ic) {
rmp->rm_ic = true; rmp->rm_ic = true;
} }
ExpandGeneric(xp, rmp, matches, numMatches, tab[i].func, tab[i].escaped, ExpandGeneric(pat, xp, rmp, matches, numMatches, tab[i].func, tab[i].escaped);
fuzzy ? pat : NULL);
ret = OK; ret = OK;
break; break;
} }
@ -2735,7 +2731,7 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
} else if (xp->xp_context == EXPAND_MAPPINGS) { } else if (xp->xp_context == EXPAND_MAPPINGS) {
ret = ExpandMappings(pat, &regmatch, numMatches, matches); ret = ExpandMappings(pat, &regmatch, numMatches, matches);
} else if (xp->xp_context == EXPAND_USER_DEFINED) { } else if (xp->xp_context == EXPAND_USER_DEFINED) {
ret = ExpandUserDefined(xp, &regmatch, matches, numMatches); ret = ExpandUserDefined(pat, xp, &regmatch, matches, numMatches);
} else { } else {
ret = ExpandOther(pat, xp, &regmatch, matches, numMatches); ret = ExpandOther(pat, xp, &regmatch, matches, numMatches);
} }
@ -2754,17 +2750,16 @@ static int ExpandFromContext(expand_T *xp, char *pat, char ***matches, int *numM
/// obtain strings, one by one. The strings are matched against a regexp /// obtain strings, one by one. The strings are matched against a regexp
/// program. Matching strings are copied into an array, which is returned. /// program. Matching strings are copied into an array, which is returned.
/// ///
/// If "fuzzystr" is not NULL, then fuzzy matching is used. Otherwise,
/// regex matching is used.
///
/// @param func returns a string from the list /// @param func returns a string from the list
static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, char ***matches, int *numMatches, static void ExpandGeneric(const char *const pat, expand_T *xp, regmatch_T *regmatch,
CompleteListItemGetter func, int escaped, const char *const fuzzystr) char ***matches, int *numMatches, CompleteListItemGetter func,
int escaped)
{ {
int i; int i;
size_t count = 0; size_t count = 0;
char *str; char *str;
const bool fuzzy = fuzzystr != NULL;
const bool fuzzy = cmdline_fuzzy_complete(pat);
// count the number of matching names // count the number of matching names
for (i = 0;; i++) { for (i = 0;; i++) {
@ -2780,7 +2775,7 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, char ***matches, i
if (!fuzzy) { if (!fuzzy) {
match = vim_regexec(regmatch, str, (colnr_T)0); match = vim_regexec(regmatch, str, (colnr_T)0);
} else { } else {
match = fuzzy_match_str(str, fuzzystr) != 0; match = fuzzy_match_str(str, pat) != 0;
} }
if (match) { if (match) {
count++; count++;
@ -2814,9 +2809,10 @@ static void ExpandGeneric(expand_T *xp, regmatch_T *regmatch, char ***matches, i
if (!fuzzy) { if (!fuzzy) {
match = vim_regexec(regmatch, str, (colnr_T)0); match = vim_regexec(regmatch, str, (colnr_T)0);
} else { } else {
score = fuzzy_match_str(str, fuzzystr); score = fuzzy_match_str(str, pat);
match = (score != 0); match = (score != 0);
} }
if (!match) { if (!match) {
continue; continue;
} }
@ -3044,12 +3040,16 @@ static void *call_user_expand_func(user_expand_func_T user_expand_func, expand_T
return ret; return ret;
} }
/// Expand names with a function defined by the user. /// Expand names with a function defined by the user (EXPAND_USER_DEFINED and
static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char ***matches, int *numMatches) /// EXPAND_USER_LIST).
static int ExpandUserDefined(const char *const pat, expand_T *xp, regmatch_T *regmatch,
char ***matches, int *numMatches)
{ {
char *e; char *e;
garray_T ga; garray_T ga;
const bool fuzzy = cmdline_fuzzy_complete(pat);
*matches = NULL; *matches = NULL;
*numMatches = 0; *numMatches = 0;
char *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp); char *const retstr = call_user_expand_func((user_expand_func_T)call_func_retstr, xp);
@ -3058,7 +3058,13 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char ***matches
return FAIL; return FAIL;
} }
ga_init(&ga, (int)sizeof(char *), 3); if (!fuzzy) {
ga_init(&ga, (int)sizeof(char *), 3);
} else {
ga_init(&ga, (int)sizeof(fuzmatch_str_T), 3);
}
int count = 0;
for (char *s = retstr; *s != NUL; s = e) { for (char *s = retstr; *s != NUL; s = e) {
e = vim_strchr(s, '\n'); e = vim_strchr(s, '\n');
if (e == NULL) { if (e == NULL) {
@ -3067,10 +3073,32 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char ***matches
const char keep = *e; const char keep = *e;
*e = NUL; *e = NUL;
const bool skip = xp->xp_pattern[0] && vim_regexec(regmatch, s, (colnr_T)0) == 0; bool match;
int score = 0;
if (xp->xp_pattern[0] || fuzzy) {
if (!fuzzy) {
match = vim_regexec(regmatch, s, (colnr_T)0);
} else {
score = fuzzy_match_str(s, pat);
match = (score != 0);
}
} else {
match = true; // match everything
}
*e = keep; *e = keep;
if (!skip) {
GA_APPEND(char *, &ga, xstrnsave(s, (size_t)(e - s))); if (match) {
if (!fuzzy) {
GA_APPEND(char *, &ga, xstrnsave(s, (size_t)(e - s)));
} else {
GA_APPEND(fuzmatch_str_T, &ga, ((fuzmatch_str_T){
.idx = count,
.str = xstrnsave(s, (size_t)(e - s)),
.score = score,
}));
}
count++;
} }
if (*e != NUL) { if (*e != NUL) {
@ -3078,8 +3106,14 @@ static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char ***matches
} }
} }
xfree(retstr); xfree(retstr);
*matches = ga.ga_data;
*numMatches = ga.ga_len; if (!fuzzy) {
*matches = ga.ga_data;
*numMatches = ga.ga_len;
} else {
fuzzymatches_to_strmatches(ga.ga_data, matches, count, false);
*numMatches = count;
}
return OK; return OK;
} }

View File

@ -2670,9 +2670,8 @@ func Test_cmdline_complete_dlist()
call assert_equal("\"dlist 10 /pat/ | chistory", @:) call assert_equal("\"dlist 10 /pat/ | chistory", @:)
endfunc endfunc
" Test for 'fuzzy' in 'wildoptions' (fuzzy completion) " argument list (only for :argdel) fuzzy completion
func Test_wildoptions_fuzzy() func Test_fuzzy_completion_arglist()
" argument list (only for :argdel)
argadd change.py count.py charge.py argadd change.py count.py charge.py
set wildoptions& set wildoptions&
call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx') call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx')
@ -2681,8 +2680,11 @@ func Test_wildoptions_fuzzy()
call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx') call feedkeys(":argdel cge\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal('"argdel change.py charge.py', @:) call assert_equal('"argdel change.py charge.py', @:)
%argdelete %argdelete
set wildoptions&
endfunc
" autocmd group name fuzzy completion " autocmd group name fuzzy completion
func Test_fuzzy_completion_autocmd()
set wildoptions& set wildoptions&
augroup MyFuzzyGroup augroup MyFuzzyGroup
augroup END augroup END
@ -2696,8 +2698,11 @@ func Test_wildoptions_fuzzy()
call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":augroup My*p\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"augroup My*p', @:) call assert_equal('"augroup My*p', @:)
augroup! MyFuzzyGroup augroup! MyFuzzyGroup
set wildoptions&
endfunc
" buffer name fuzzy completion " buffer name fuzzy completion
func Test_fuzzy_completion_bufname()
set wildoptions& set wildoptions&
edit SomeFile.txt edit SomeFile.txt
enew enew
@ -2711,24 +2716,29 @@ func Test_wildoptions_fuzzy()
call feedkeys(":b S*File.txt\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":b S*File.txt\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"b S*File.txt', @:) call assert_equal('"b S*File.txt', @:)
%bw! %bw!
set wildoptions&
endfunc
" buffer name (full path) fuzzy completion " buffer name (full path) fuzzy completion
if has('unix') func Test_fuzzy_completion_bufname_fullpath()
set wildoptions& CheckUnix
call mkdir('Xcmd/Xstate/Xfile.js', 'p') set wildoptions&
edit Xcmd/Xstate/Xfile.js call mkdir('Xcmd/Xstate/Xfile.js', 'p')
cd Xcmd/Xstate edit Xcmd/Xstate/Xfile.js
enew cd Xcmd/Xstate
call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx') enew
call assert_equal('"b CmdStateFile', @:) call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
set wildoptions=fuzzy call assert_equal('"b CmdStateFile', @:)
call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions=fuzzy
call assert_match('Xcmd/Xstate/Xfile.js$', @:) call feedkeys(":b CmdStateFile\<Tab>\<C-B>\"\<CR>", 'tx')
cd - call assert_match('Xcmd/Xstate/Xfile.js$', @:)
call delete('Xcmd', 'rf') cd -
endif call delete('Xcmd', 'rf')
set wildoptions&
endfunc
" :behave suboptions fuzzy completion " :behave suboptions fuzzy completion
func Test_fuzzy_completion_behave()
set wildoptions& set wildoptions&
call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":behave xm\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"behave xm', @:) call assert_equal('"behave xm', @:)
@ -2743,10 +2753,15 @@ func Test_wildoptions_fuzzy()
call feedkeys(":behave win\<C-D>\<F4>\<C-B>\"\<CR>", 'tx') call feedkeys(":behave win\<C-D>\<F4>\<C-B>\"\<CR>", 'tx')
call assert_equal('mswin', g:Sline) call assert_equal('mswin', g:Sline)
call assert_equal('"behave win', @:) call assert_equal('"behave win', @:)
set wildoptions&
endfunc
" colorscheme name fuzzy completion - NOT supported " " colorscheme name fuzzy completion - NOT supported
" func Test_fuzzy_completion_colorscheme()
" endfunc
" built-in command name fuzzy completion " built-in command name fuzzy completion
func Test_fuzzy_completion_cmdname()
set wildoptions& set wildoptions&
call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":sbwin\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sbwin', @:) call assert_equal('"sbwin', @:)
@ -2757,24 +2772,31 @@ func Test_wildoptions_fuzzy()
call assert_equal('"sbrewind', @:) call assert_equal('"sbrewind', @:)
call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":sbr*d\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sbr*d', @:) call assert_equal('"sbr*d', @:)
set wildoptions&
endfunc
" compiler name fuzzy completion - NOT supported " " compiler name fuzzy completion - NOT supported
" func Test_fuzzy_completion_compiler()
" endfunc
" :cscope suboptions fuzzy completion " :cscope suboptions fuzzy completion
if has('cscope') func Test_fuzzy_completion_cscope()
set wildoptions& CheckFeature cscope
call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions&
call assert_equal('"cscope ret', @:) call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx') call assert_equal('"cscope ret', @:)
call assert_equal('"cscope reset', @:) call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
set wildoptions=fuzzy call assert_equal('"cscope reset', @:)
call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions=fuzzy
call assert_equal('"cscope reset', @:) call feedkeys(":cscope ret\<Tab>\<C-B>\"\<CR>", 'tx')
call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx') call assert_equal('"cscope reset', @:)
call assert_equal('"cscope re*t', @:) call feedkeys(":cscope re*t\<Tab>\<C-B>\"\<CR>", 'tx')
endif call assert_equal('"cscope re*t', @:)
set wildoptions&
endfunc
" :diffget/:diffput buffer name fuzzy completion " :diffget/:diffput buffer name fuzzy completion
func Test_fuzzy_completion_diff()
new SomeBuffer new SomeBuffer
diffthis diffthis
new OtherBuffer new OtherBuffer
@ -2790,26 +2812,37 @@ func Test_wildoptions_fuzzy()
call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":diffput sbuf\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"diffput SomeBuffer', @:) call assert_equal('"diffput SomeBuffer', @:)
%bw! %bw!
set wildoptions&
endfunc
" directory name fuzzy completion - NOT supported " " directory name fuzzy completion - NOT supported
" func Test_fuzzy_completion_dirname()
" endfunc
" environment variable name fuzzy completion " environment variable name fuzzy completion
func Test_fuzzy_completion_env()
set wildoptions& set wildoptions&
call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"echo $VUT', @:) call assert_equal('"echo $VUT', @:)
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":echo $VUT\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"echo $VIMRUNTIME', @:) call assert_equal('"echo $VIMRUNTIME', @:)
set wildoptions&
endfunc
" autocmd event fuzzy completion " autocmd event fuzzy completion
func Test_fuzzy_completion_autocmd_event()
set wildoptions& set wildoptions&
call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"autocmd BWout', @:) call assert_equal('"autocmd BWout', @:)
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":autocmd BWout\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"autocmd BufWipeout', @:) call assert_equal('"autocmd BufWipeout', @:)
set wildoptions&
endfunc
" vim expression fuzzy completion " vim expression fuzzy completion
func Test_fuzzy_completion_expr()
let g:PerPlaceCount = 10 let g:PerPlaceCount = 10
set wildoptions& set wildoptions&
call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx')
@ -2817,32 +2850,49 @@ func Test_wildoptions_fuzzy()
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":let c = ppc\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"let c = PerPlaceCount', @:) call assert_equal('"let c = PerPlaceCount', @:)
" file name fuzzy completion - NOT supported
" files in path fuzzy completion - NOT supported
" filetype name fuzzy completion - NOT supported
" user defined function name completion
set wildoptions& set wildoptions&
call feedkeys(":call Test_w_fuz\<Tab>\<C-B>\"\<CR>", 'tx') endfunc
call assert_equal('"call Test_w_fuz', @:)
set wildoptions=fuzzy
call feedkeys(":call Test_w_fuz\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call Test_wildoptions_fuzzy()', @:)
" user defined command name completion " " file name fuzzy completion - NOT supported
" func Test_fuzzy_completion_filename()
" endfunc
" " files in path fuzzy completion - NOT supported
" func Test_fuzzy_completion_filesinpath()
" endfunc
" " filetype name fuzzy completion - NOT supported
" func Test_fuzzy_completion_filetype()
" endfunc
" user defined function name completion
func Test_fuzzy_completion_userdefined_func()
set wildoptions&
call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call Test_f_u_f', @:)
set wildoptions=fuzzy
call feedkeys(":call Test_f_u_f\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"call Test_fuzzy_completion_userdefined_func()', @:)
set wildoptions&
endfunc
" user defined command name completion
func Test_fuzzy_completion_userdefined_cmd()
set wildoptions& set wildoptions&
call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"MsFeat', @:) call assert_equal('"MsFeat', @:)
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":MsFeat\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"MissingFeature', @:) call assert_equal('"MissingFeature', @:)
set wildoptions&
endfunc
" :help tag fuzzy completion - NOT supported " " :help tag fuzzy completion - NOT supported
" func Test_fuzzy_completion_helptag()
" endfunc
" highlight group name fuzzy completion " highlight group name fuzzy completion
func Test_fuzzy_completion_hlgroup()
set wildoptions& set wildoptions&
call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":highlight SKey\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"highlight SKey', @:) call assert_equal('"highlight SKey', @:)
@ -2853,8 +2903,11 @@ func Test_wildoptions_fuzzy()
call assert_equal('"highlight SpecialKey', @:) call assert_equal('"highlight SpecialKey', @:)
call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":highlight Sp*Key\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"highlight Sp*Key', @:) call assert_equal('"highlight Sp*Key', @:)
set wildoptions&
endfunc
" :history suboptions fuzzy completion " :history suboptions fuzzy completion
func Test_fuzzy_completion_history()
set wildoptions& set wildoptions&
call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":history dg\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"history dg', @:) call assert_equal('"history dg', @:)
@ -2865,26 +2918,34 @@ func Test_wildoptions_fuzzy()
call assert_equal('"history debug', @:) call assert_equal('"history debug', @:)
call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":history se*h\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"history se*h', @:) call assert_equal('"history se*h', @:)
set wildoptions&
endfunc
" :language locale name fuzzy completion " :language locale name fuzzy completion
if has('unix') func Test_fuzzy_completion_lang()
set wildoptions& CheckUnix
call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions&
call assert_equal('"lang psx', @:) call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
set wildoptions=fuzzy call assert_equal('"lang psx', @:)
call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions=fuzzy
call assert_equal('"lang POSIX', @:) call feedkeys(":lang psx\<Tab>\<C-B>\"\<CR>", 'tx')
endif call assert_equal('"lang POSIX', @:)
set wildoptions&
endfunc
" :mapclear buffer argument fuzzy completion " :mapclear buffer argument fuzzy completion
func Test_fuzzy_completion_mapclear()
set wildoptions& set wildoptions&
call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"mapclear buf', @:) call assert_equal('"mapclear buf', @:)
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"mapclear <buffer>', @:) call assert_equal('"mapclear <buffer>', @:)
set wildoptions&
endfunc
" map name fuzzy completion " map name fuzzy completion
func Test_fuzzy_completion_mapname()
" test regex completion works " test regex completion works
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":cnoremap <ex\<Tab> <esc> \<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":cnoremap <ex\<Tab> <esc> \<Tab>\<C-B>\"\<CR>", 'tx')
@ -2919,8 +2980,11 @@ func Test_wildoptions_fuzzy()
nunmap <Plug>fendoff nunmap <Plug>fendoff
nunmap <Plug>state nunmap <Plug>state
nunmap <Plug>FendingOff nunmap <Plug>FendingOff
set wildoptions&
endfunc
" abbreviation fuzzy completion " abbreviation fuzzy completion
func Test_fuzzy_completion_abbr()
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":iabbr wait\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":iabbr wait\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"iabbr <nowait>", @:) call assert_equal("\"iabbr <nowait>", @:)
@ -2930,26 +2994,34 @@ func Test_wildoptions_fuzzy()
call feedkeys(":iabbr a1z\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":iabbr a1z\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"iabbr a1z\t", @:) call assert_equal("\"iabbr a1z\t", @:)
iunabbrev WaitForCompletion iunabbrev WaitForCompletion
set wildoptions&
endfunc
" menu name fuzzy completion " menu name fuzzy completion
if has('gui_running') func Test_fuzzy_completion_menu()
set wildoptions& CheckGui
call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions&
call assert_equal('"menu pup', @:) call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
set wildoptions=fuzzy call assert_equal('"menu pup', @:)
call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions=fuzzy
call assert_equal('"menu PopUp.', @:) call feedkeys(":menu pup\<Tab>\<C-B>\"\<CR>", 'tx')
endif call assert_equal('"menu PopUp.', @:)
set wildoptions&
endfunc
" :messages suboptions fuzzy completion " :messages suboptions fuzzy completion
func Test_fuzzy_completion_messages()
set wildoptions& set wildoptions&
call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"messages clr', @:) call assert_equal('"messages clr', @:)
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":messages clr\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"messages clear', @:) call assert_equal('"messages clear', @:)
set wildoptions&
endfunc
" :set option name fuzzy completion " :set option name fuzzy completion
func Test_fuzzy_completion_option()
set wildoptions& set wildoptions&
call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":set brkopt\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set brkopt', @:) call assert_equal('"set brkopt', @:)
@ -2962,67 +3034,94 @@ func Test_wildoptions_fuzzy()
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":set fixeol\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set fixendofline', @:) call assert_equal('"set fixendofline', @:)
set wildoptions&
endfunc
" :set <term_option> " :set <term_option>
" Nvim does not support term options func Test_fuzzy_completion_term_option()
" set wildoptions& throw 'Skipped: Nvim does not support term options'
" call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions&
" call assert_equal('"set t_EC', @:) call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx')
" call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx') call assert_equal('"set t_EC', @:)
" call assert_equal('"set <t_EC>', @:) call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx')
" set wildoptions=fuzzy call assert_equal('"set <t_EC>', @:)
" call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions=fuzzy
" call assert_equal('"set t_EC', @:) call feedkeys(":set t_E\<Tab>\<C-B>\"\<CR>", 'tx')
" call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx') call assert_equal('"set t_EC', @:)
" call assert_equal('"set <t_EC>', @:) call feedkeys(":set <t_E\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"set <t_EC>', @:)
set wildoptions&
endfunc
" :packadd directory name fuzzy completion - NOT supported " " :packadd directory name fuzzy completion - NOT supported
" func Test_fuzzy_completion_packadd()
" endfunc
" shell command name fuzzy completion - NOT supported " " shell command name fuzzy completion - NOT supported
" func Test_fuzzy_completion_shellcmd()
" endfunc
" :sign suboptions fuzzy completion " :sign suboptions fuzzy completion
func Test_fuzzy_completion_sign()
set wildoptions& set wildoptions&
call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign ufe', @:) call assert_equal('"sign ufe', @:)
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":sign ufe\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"sign undefine', @:) call assert_equal('"sign undefine', @:)
set wildoptions&
endfunc
" :syntax suboptions fuzzy completion " :syntax suboptions fuzzy completion
func Test_fuzzy_completion_syntax_cmd()
set wildoptions& set wildoptions&
call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntax kwd', @:) call assert_equal('"syntax kwd', @:)
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":syntax kwd\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntax keyword', @:) call assert_equal('"syntax keyword', @:)
set wildoptions&
endfunc
" syntax group name fuzzy completion " syntax group name fuzzy completion
func Test_fuzzy_completion_syntax_group()
set wildoptions& set wildoptions&
call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"syntax list mpar', @:) call assert_equal('"syntax list mpar', @:)
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":syntax list mpar\<Tab>\<C-B>\"\<CR>", 'tx')
" Fuzzy match favours NvimParenthesis over MatchParen " Fuzzy match prefers NvimParenthesis over MatchParen
" call assert_equal('"syntax list MatchParen', @:) " call assert_equal('"syntax list MatchParen', @:)
call assert_equal('"syntax list NvimParenthesis', @:) call assert_equal('"syntax list NvimParenthesis', @:)
set wildoptions&
endfunc
" :syntime suboptions fuzzy completion " :syntime suboptions fuzzy completion
if has('profile') func Test_fuzzy_completion_syntime()
set wildoptions& CheckFeature profile
call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions&
call assert_equal('"syntime clr', @:) call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
set wildoptions=fuzzy call assert_equal('"syntime clr', @:)
call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx') set wildoptions=fuzzy
call assert_equal('"syntime clear', @:) call feedkeys(":syntime clr\<Tab>\<C-B>\"\<CR>", 'tx')
endif call assert_equal('"syntime clear', @:)
set wildoptions&
endfunc
" tag name fuzzy completion - NOT supported " " tag name fuzzy completion - NOT supported
" func Test_fuzzy_completion_tagname()
" endfunc
" tag name and file fuzzy completion - NOT supported " " tag name and file fuzzy completion - NOT supported
" func Test_fuzzy_completion_tagfile()
" endfunc
" user names fuzzy completion - how to test this functionality? " " user names fuzzy completion - how to test this functionality?
" func Test_fuzzy_completion_username()
" endfunc
" user defined variable name fuzzy completion " user defined variable name fuzzy completion
func Test_fuzzy_completion_userdefined_var()
let g:SomeVariable=10 let g:SomeVariable=10
set wildoptions& set wildoptions&
call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx')
@ -3030,8 +3129,11 @@ func Test_wildoptions_fuzzy()
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":let SVar\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"let SomeVariable', @:) call assert_equal('"let SomeVariable', @:)
set wildoptions&
endfunc
" Test for sorting the results by the best match " Test for sorting the results by the best match
func Test_fuzzy_completion_cmd_sort_results()
%bw! %bw!
command T123format : command T123format :
command T123goformat : command T123goformat :
@ -3049,9 +3151,11 @@ func Test_wildoptions_fuzzy()
delcommand T123state delcommand T123state
delcommand T123FendingOff delcommand T123FendingOff
%bw %bw
set wildoptions&
endfunc
" Test for fuzzy completion of a command with lower case letters and a " Test for fuzzy completion of a command with lower case letters and a number
" number func Test_fuzzy_completion_cmd_alnum()
command Foo2Bar : command Foo2Bar :
set wildoptions=fuzzy set wildoptions=fuzzy
call feedkeys(":foo2\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":foo2\<Tab>\<C-B>\"\<CR>", 'tx')
@ -3061,8 +3165,11 @@ func Test_wildoptions_fuzzy()
call feedkeys(":bar\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":bar\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"Foo2Bar', @:) call assert_equal('"Foo2Bar', @:)
delcommand Foo2Bar delcommand Foo2Bar
set wildoptions&
endfunc
" Test for command completion for a command starting with 'k' " Test for command completion for a command starting with 'k'
func Test_fuzzy_completion_cmd_k()
command KillKillKill : command KillKillKill :
set wildoptions& set wildoptions&
call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
@ -3071,9 +3178,33 @@ func Test_wildoptions_fuzzy()
call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx') call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"KillKillKill', @:) call assert_equal('"KillKillKill', @:)
delcom KillKillKill delcom KillKillKill
set wildoptions& set wildoptions&
%bw! endfunc
" Test for fuzzy completion for user defined custom completion function
func Test_fuzzy_completion_custom_func()
func Tcompl(a, c, p)
return "format\ngoformat\nTestFOrmat\nfendoff\nstate"
endfunc
command -nargs=* -complete=custom,Tcompl Fuzzy :
set wildoptions&
call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy format", @:)
call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy xy", @:)
call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy ttt", @:)
set wildoptions=fuzzy
call feedkeys(":Fuzzy \<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy format goformat TestFOrmat fendoff state", @:)
call feedkeys(":Fuzzy fo\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy format TestFOrmat goformat fendoff", @:)
call feedkeys(":Fuzzy xy\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy xy", @:)
call feedkeys(":Fuzzy ttt\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"Fuzzy TestFOrmat", @:)
delcom Fuzzy
set wildoptions&
endfunc endfunc
" Test for :breakadd argument completion " Test for :breakadd argument completion

View File

@ -935,6 +935,9 @@ describe('completion', function()
eq({'api'}, funcs.getcompletion('vim.ap', 'lua')) eq({'api'}, funcs.getcompletion('vim.ap', 'lua'))
eq({'tbl_filter'}, funcs.getcompletion('vim.tbl_fil', 'lua')) eq({'tbl_filter'}, funcs.getcompletion('vim.tbl_fil', 'lua'))
eq({'vim'}, funcs.getcompletion('print(vi', 'lua')) eq({'vim'}, funcs.getcompletion('print(vi', 'lua'))
-- fuzzy completion is not supported, so the result should be the same
command('set wildoptions+=fuzzy')
eq({'vim'}, funcs.getcompletion('vi', 'lua'))
end) end)
end) end)