0
0
mirror of https://github.com/vim/vim.git synced 2025-07-25 10:54:51 -04:00

patch 8.2.4479: no fuzzy completieon for maps and abbreviations

Problem:    No fuzzy completieon for maps and abbreviations.
Solution:   Fuzzy complete maps and abbreviations. (Yegappan Lakshmanan,
            closes #9856)
This commit is contained in:
Yegappan Lakshmanan 2022-02-27 12:07:30 +00:00 committed by Bram Moolenaar
parent 00333cb3b3
commit 6caeda2fce
6 changed files with 140 additions and 29 deletions

View File

@ -56,7 +56,6 @@ cmdline_fuzzy_completion_supported(expand_T *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_MAPPINGS
&& 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
@ -1216,10 +1215,12 @@ set_cmd_index(char_u *cmd, exarg_T *eap, expand_T *xp, int *complp)
// Isolate the command and search for it in the command table. // Isolate the command and search for it in the command table.
// Exceptions: // Exceptions:
// - the 'k' command can directly be followed by any character, but // - the 'k' command can directly be followed by any character, but do
// do accept "keepmarks", "keepalt" and "keepjumps". // accept "keepmarks", "keepalt" and "keepjumps". As fuzzy matching can
// find matches anywhere in the command name, do this only for command
// expansion based on regular expression and not for fuzzy matching.
// - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' // - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r'
if (*cmd == 'k' && cmd[1] != 'e') if (!fuzzy && (*cmd == 'k' && cmd[1] != 'e'))
{ {
eap->cmdidx = CMD_k; eap->cmdidx = CMD_k;
p = cmd + 1; p = cmd + 1;
@ -2596,7 +2597,7 @@ ExpandFromContext(
|| xp->xp_context == EXPAND_BOOL_SETTINGS) || xp->xp_context == EXPAND_BOOL_SETTINGS)
ret = ExpandSettings(xp, &regmatch, pat, numMatches, matches); ret = ExpandSettings(xp, &regmatch, pat, numMatches, matches);
else if (xp->xp_context == EXPAND_MAPPINGS) else if (xp->xp_context == EXPAND_MAPPINGS)
ret = ExpandMappings(&regmatch, numMatches, matches); ret = ExpandMappings(pat, &regmatch, numMatches, matches);
# if defined(FEAT_EVAL) # if defined(FEAT_EVAL)
else if (xp->xp_context == EXPAND_USER_DEFINED) else if (xp->xp_context == EXPAND_USER_DEFINED)
ret = ExpandUserDefined(xp, &regmatch, matches, numMatches); ret = ExpandUserDefined(xp, &regmatch, matches, numMatches);
@ -2712,7 +2713,8 @@ ExpandGeneric(
fuzmatch = ALLOC_MULT(fuzmatch_str_T, count); fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
else else
*matches = ALLOC_MULT(char_u *, count); *matches = ALLOC_MULT(char_u *, count);
if ((fuzzy && (fuzmatch == NULL)) || (*matches == NULL)) if ((!fuzzy && (*matches == NULL))
|| (fuzzy && (fuzmatch == NULL)))
{ {
*numMatches = 0; *numMatches = 0;
*matches = NULL; *matches = NULL;

View File

@ -1257,9 +1257,10 @@ set_context_in_map_cmd(
*/ */
int int
ExpandMappings( ExpandMappings(
char_u *pat,
regmatch_T *regmatch, regmatch_T *regmatch,
int *num_file, int *numMatches,
char_u ***file) char_u ***matches)
{ {
mapblock_T *mp; mapblock_T *mp;
int hash; int hash;
@ -1267,11 +1268,17 @@ ExpandMappings(
int round; int round;
char_u *p; char_u *p;
int i; int i;
int fuzzy;
int match;
int score;
fuzmatch_str_T *fuzmatch = NULL;
fuzzy = cmdline_fuzzy_complete(pat);
validate_maphash(); validate_maphash();
*num_file = 0; // return values in case of FAIL *numMatches = 0; // return values in case of FAIL
*file = NULL; *matches = NULL;
// round == 1: Count the matches. // round == 1: Count the matches.
// round == 2: Build the array to keep the matches. // round == 2: Build the array to keep the matches.
@ -1279,6 +1286,7 @@ ExpandMappings(
{ {
count = 0; count = 0;
// First search in map modifier arguments
for (i = 0; i < 7; ++i) for (i = 0; i < 7; ++i)
{ {
if (i == 0) if (i == 0)
@ -1300,13 +1308,29 @@ ExpandMappings(
else else
continue; continue;
if (vim_regexec(regmatch, p, (colnr_T)0)) if (!fuzzy)
match = vim_regexec(regmatch, p, (colnr_T)0);
else
{ {
if (round == 1) score = fuzzy_match_str(p, pat);
++count; match = (score != 0);
else
(*file)[count++] = vim_strsave(p);
} }
if (!match)
continue;
if (round == 2)
{
if (fuzzy)
{
fuzmatch[count].idx = count;
fuzmatch[count].str = vim_strsave(p);
fuzmatch[count].score = score;
}
else
(*matches)[count] = vim_strsave(p);
}
++count;
} }
for (hash = 0; hash < 256; ++hash) for (hash = 0; hash < 256; ++hash)
@ -1326,14 +1350,31 @@ ExpandMappings(
if (mp->m_mode & expand_mapmodes) if (mp->m_mode & expand_mapmodes)
{ {
p = translate_mapping(mp->m_keys); p = translate_mapping(mp->m_keys);
if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) if (p != NULL)
{ {
if (round == 1) if (!fuzzy)
++count; match = vim_regexec(regmatch, p, (colnr_T)0);
else else
{ {
(*file)[count++] = p; score = fuzzy_match_str(p, pat);
p = NULL; match = (score != 0);
}
if (match)
{
if (round == 2)
{
if (fuzzy)
{
fuzmatch[count].idx = count;
fuzmatch[count].str = p;
fuzmatch[count].score = score;
}
else
(*matches)[count] = p;
p = NULL;
}
++count;
} }
} }
vim_free(p); vim_free(p);
@ -1346,12 +1387,25 @@ ExpandMappings(
if (round == 1) if (round == 1)
{ {
*file = ALLOC_MULT(char_u *, count); if (fuzzy)
if (*file == NULL) {
return FAIL; fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
if (fuzmatch == NULL)
return FAIL;
}
else
{
*matches = ALLOC_MULT(char_u *, count);
if (*matches == NULL)
return FAIL;
}
} }
} // for (round) } // for (round)
if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
FALSE) == FAIL)
return FAIL;
if (count > 1) if (count > 1)
{ {
char_u **ptr1; char_u **ptr1;
@ -1359,10 +1413,12 @@ ExpandMappings(
char_u **ptr3; char_u **ptr3;
// Sort the matches // Sort the matches
sort_strings(*file, count); // Fuzzy matching already sorts the matches
if (!fuzzy)
sort_strings(*matches, count);
// Remove multiple entries // Remove multiple entries
ptr1 = *file; ptr1 = *matches;
ptr2 = ptr1 + 1; ptr2 = ptr1 + 1;
ptr3 = ptr1 + count; ptr3 = ptr1 + count;
@ -1378,7 +1434,7 @@ ExpandMappings(
} }
} }
*num_file = count; *numMatches = count;
return (count == 0 ? FAIL : OK); return (count == 0 ? FAIL : OK);
} }

View File

@ -8,7 +8,7 @@ int mode_str2flags(char_u *modechars);
int map_to_exists(char_u *str, char_u *modechars, int abbr); int map_to_exists(char_u *str, char_u *modechars, int abbr);
int map_to_exists_mode(char_u *rhs, int mode, int abbr); int map_to_exists_mode(char_u *rhs, int mode, int abbr);
char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit, int isabbrev, int isunmap, cmdidx_T cmdidx); char_u *set_context_in_map_cmd(expand_T *xp, char_u *cmd, char_u *arg, int forceit, int isabbrev, int isunmap, cmdidx_T cmdidx);
int ExpandMappings(regmatch_T *regmatch, int *num_file, char_u ***file); int ExpandMappings(char_u *pat, regmatch_T *regmatch, int *num_file, char_u ***file);
int check_abbr(int c, char_u *ptr, int col, int mincol); int check_abbr(int c, char_u *ptr, int col, int mincol);
char_u *eval_map_expr(mapblock_T *mp, int c); char_u *eval_map_expr(mapblock_T *mp, int c);
char_u *vim_strsave_escape_csi(char_u *p); char_u *vim_strsave_escape_csi(char_u *p);

View File

@ -5006,7 +5006,7 @@ fuzzy_match_str(char_u *str, char_u *pat)
if (str == NULL || pat == NULL) if (str == NULL || pat == NULL)
return 0; return 0;
fuzzy_match(str, pat, FALSE, &score, matchpos, fuzzy_match(str, pat, TRUE, &score, matchpos,
sizeof(matchpos) / sizeof(matchpos[0])); sizeof(matchpos) / sizeof(matchpos[0]));
return score; return score;

View File

@ -2658,11 +2658,52 @@ func Test_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>', @:)
" map name fuzzy completion - NOT supported " map name fuzzy completion
" 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')
call assert_equal("\"cnoremap <expr> <esc> \<Tab>", @:) call assert_equal("\"cnoremap <expr> <esc> \<Tab>", @:)
nmap <plug>MyLongMap :p<CR>
call feedkeys(":nmap MLM\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"nmap <Plug>MyLongMap", @:)
call feedkeys(":nmap MLM \<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"nmap MLM \t", @:)
call feedkeys(":nmap <F2> one two \<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"nmap <F2> one two \t", @:)
" duplicate entries should be removed
vmap <plug>MyLongMap :<C-U>#<CR>
call feedkeys(":nmap MLM\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"nmap <Plug>MyLongMap", @:)
nunmap <plug>MyLongMap
vunmap <plug>MyLongMap
call feedkeys(":nmap ABC\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"nmap ABC\t", @:)
" results should be sorted by best match
nmap <Plug>format :
nmap <Plug>goformat :
nmap <Plug>TestFOrmat :
nmap <Plug>fendoff :
nmap <Plug>state :
nmap <Plug>FendingOff :
call feedkeys(":nmap <Plug>fo\<C-A>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"nmap <Plug>format <Plug>TestFOrmat <Plug>FendingOff <Plug>goformat <Plug>fendoff", @:)
nunmap <Plug>format
nunmap <Plug>goformat
nunmap <Plug>TestFOrmat
nunmap <Plug>fendoff
nunmap <Plug>state
nunmap <Plug>FendingOff
" abbreviation fuzzy completion
set wildoptions=fuzzy
call feedkeys(":iabbr wait\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"iabbr <nowait>", @:)
iabbr WaitForCompletion WFC
call feedkeys(":iabbr fcl\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"iabbr WaitForCompletion", @:)
call feedkeys(":iabbr a1z\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"iabbr a1z\t", @:)
iunabbrev WaitForCompletion
" menu name fuzzy completion " menu name fuzzy completion
if has('gui_running') if has('gui_running')
@ -2792,6 +2833,16 @@ func Test_wildoptions_fuzzy()
call assert_equal('"Foo2Bar', @:) call assert_equal('"Foo2Bar', @:)
delcommand Foo2Bar delcommand Foo2Bar
" Test for command completion for a command starting with 'k'
command KillKillKill :
set wildoptions&
call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal("\"killkill\<Tab>", @:)
set wildoptions=fuzzy
call feedkeys(":killkill\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"KillKillKill', @:)
delcom KillKillKill
set wildoptions& set wildoptions&
%bw! %bw!
endfunc endfunc

View File

@ -754,6 +754,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
4479,
/**/ /**/
4478, 4478,
/**/ /**/