summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2022-02-27 12:07:30 +0000
committerBram Moolenaar <Bram@vim.org>2022-02-27 12:07:30 +0000
commit6caeda2fce4bccac2dd43ca9fee1d32ee96b708d (patch)
tree2a3de1990e27aa46b59806f74228347f59ceff65
parent00333cb3b341499df8729b9345f0bbad968cda0b (diff)
patch 8.2.4479: no fuzzy completieon for maps and abbreviationsv8.2.4479
Problem: No fuzzy completieon for maps and abbreviations. Solution: Fuzzy complete maps and abbreviations. (Yegappan Lakshmanan, closes #9856)
-rw-r--r--src/cmdexpand.c14
-rw-r--r--src/map.c94
-rw-r--r--src/proto/map.pro2
-rw-r--r--src/search.c2
-rw-r--r--src/testdir/test_cmdline.vim53
-rw-r--r--src/version.c2
6 files changed, 139 insertions, 28 deletions
diff --git a/src/cmdexpand.c b/src/cmdexpand.c
index 003f6daf1e..84dc643424 100644
--- a/src/cmdexpand.c
+++ b/src/cmdexpand.c
@@ -56,7 +56,6 @@ cmdline_fuzzy_completion_supported(expand_T *xp)
&& xp->xp_context != EXPAND_FILES_IN_PATH
&& xp->xp_context != EXPAND_FILETYPE
&& xp->xp_context != EXPAND_HELP
- && xp->xp_context != EXPAND_MAPPINGS
&& xp->xp_context != EXPAND_OLD_SETTING
&& xp->xp_context != EXPAND_OWNSYNTAX
&& 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.
// Exceptions:
- // - the 'k' command can directly be followed by any character, but
- // do accept "keepmarks", "keepalt" and "keepjumps".
+ // - the 'k' command can directly be followed by any character, but do
+ // 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'
- if (*cmd == 'k' && cmd[1] != 'e')
+ if (!fuzzy && (*cmd == 'k' && cmd[1] != 'e'))
{
eap->cmdidx = CMD_k;
p = cmd + 1;
@@ -2596,7 +2597,7 @@ ExpandFromContext(
|| xp->xp_context == EXPAND_BOOL_SETTINGS)
ret = ExpandSettings(xp, &regmatch, pat, numMatches, matches);
else if (xp->xp_context == EXPAND_MAPPINGS)
- ret = ExpandMappings(&regmatch, numMatches, matches);
+ ret = ExpandMappings(pat, &regmatch, numMatches, matches);
# if defined(FEAT_EVAL)
else if (xp->xp_context == EXPAND_USER_DEFINED)
ret = ExpandUserDefined(xp, &regmatch, matches, numMatches);
@@ -2712,7 +2713,8 @@ ExpandGeneric(
fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
else
*matches = ALLOC_MULT(char_u *, count);
- if ((fuzzy && (fuzmatch == NULL)) || (*matches == NULL))
+ if ((!fuzzy && (*matches == NULL))
+ || (fuzzy && (fuzmatch == NULL)))
{
*numMatches = 0;
*matches = NULL;
diff --git a/src/map.c b/src/map.c
index b681d2ff2b..594c934d23 100644
--- a/src/map.c
+++ b/src/map.c
@@ -1257,9 +1257,10 @@ set_context_in_map_cmd(
*/
int
ExpandMappings(
+ char_u *pat,
regmatch_T *regmatch,
- int *num_file,
- char_u ***file)
+ int *numMatches,
+ char_u ***matches)
{
mapblock_T *mp;
int hash;
@@ -1267,11 +1268,17 @@ ExpandMappings(
int round;
char_u *p;
int i;
+ int fuzzy;
+ int match;
+ int score;
+ fuzmatch_str_T *fuzmatch = NULL;
+
+ fuzzy = cmdline_fuzzy_complete(pat);
validate_maphash();
- *num_file = 0; // return values in case of FAIL
- *file = NULL;
+ *numMatches = 0; // return values in case of FAIL
+ *matches = NULL;
// round == 1: Count the matches.
// round == 2: Build the array to keep the matches.
@@ -1279,6 +1286,7 @@ ExpandMappings(
{
count = 0;
+ // First search in map modifier arguments
for (i = 0; i < 7; ++i)
{
if (i == 0)
@@ -1300,13 +1308,29 @@ ExpandMappings(
else
continue;
- if (vim_regexec(regmatch, p, (colnr_T)0))
+ if (!fuzzy)
+ match = vim_regexec(regmatch, p, (colnr_T)0);
+ else
+ {
+ score = fuzzy_match_str(p, pat);
+ match = (score != 0);
+ }
+
+ if (!match)
+ continue;
+
+ if (round == 2)
{
- if (round == 1)
- ++count;
+ if (fuzzy)
+ {
+ fuzmatch[count].idx = count;
+ fuzmatch[count].str = vim_strsave(p);
+ fuzmatch[count].score = score;
+ }
else
- (*file)[count++] = vim_strsave(p);
+ (*matches)[count] = vim_strsave(p);
}
+ ++count;
}
for (hash = 0; hash < 256; ++hash)
@@ -1326,14 +1350,31 @@ ExpandMappings(
if (mp->m_mode & expand_mapmodes)
{
p = translate_mapping(mp->m_keys);
- if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0))
+ if (p != NULL)
{
- if (round == 1)
- ++count;
+ if (!fuzzy)
+ match = vim_regexec(regmatch, p, (colnr_T)0);
else
{
- (*file)[count++] = p;
- p = NULL;
+ score = fuzzy_match_str(p, pat);
+ 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);
@@ -1346,12 +1387,25 @@ ExpandMappings(
if (round == 1)
{
- *file = ALLOC_MULT(char_u *, count);
- if (*file == NULL)
- return FAIL;
+ if (fuzzy)
+ {
+ 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)
+ if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count,
+ FALSE) == FAIL)
+ return FAIL;
+
if (count > 1)
{
char_u **ptr1;
@@ -1359,10 +1413,12 @@ ExpandMappings(
char_u **ptr3;
// Sort the matches
- sort_strings(*file, count);
+ // Fuzzy matching already sorts the matches
+ if (!fuzzy)
+ sort_strings(*matches, count);
// Remove multiple entries
- ptr1 = *file;
+ ptr1 = *matches;
ptr2 = ptr1 + 1;
ptr3 = ptr1 + count;
@@ -1378,7 +1434,7 @@ ExpandMappings(
}
}
- *num_file = count;
+ *numMatches = count;
return (count == 0 ? FAIL : OK);
}
diff --git a/src/proto/map.pro b/src/proto/map.pro
index 42ebd4b613..8b8bc06246 100644
--- a/src/proto/map.pro
+++ b/src/proto/map.pro
@@ -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_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);
-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);
char_u *eval_map_expr(mapblock_T *mp, int c);
char_u *vim_strsave_escape_csi(char_u *p);
diff --git a/src/search.c b/src/search.c
index 063058d326..98241a471c 100644
--- a/src/search.c
+++ b/src/search.c
@@ -5006,7 +5006,7 @@ fuzzy_match_str(char_u *str, char_u *pat)
if (str == NULL || pat == NULL)
return 0;
- fuzzy_match(str, pat, FALSE, &score, matchpos,
+ fuzzy_match(str, pat, TRUE, &score, matchpos,
sizeof(matchpos) / sizeof(matchpos[0]));
return score;
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 2fc19c6fb4..d7e46d9898 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -2658,11 +2658,52 @@ func Test_wildoptions_fuzzy()
call feedkeys(":mapclear buf\<Tab>\<C-B>\"\<CR>", 'tx')
call assert_equal('"mapclear <buffer>', @:)
- " map name fuzzy completion - NOT supported
+ " map name fuzzy completion
" test regex completion works
set wildoptions=fuzzy
call feedkeys(":cnoremap <ex\<Tab> <esc> \<Tab>\<C-B>\"\<CR>", 'tx')
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
if has('gui_running')
@@ -2792,6 +2833,16 @@ func Test_wildoptions_fuzzy()
call assert_equal('"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&
%bw!
endfunc
diff --git a/src/version.c b/src/version.c
index c77f76134c..a8c0bdc553 100644
--- a/src/version.c
+++ b/src/version.c
@@ -755,6 +755,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 4479,
+/**/
4478,
/**/
4477,