To: vim_dev@googlegroups.com Subject: Patch 8.2.4479 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4479 Problem: No fuzzy completieon for maps and abbreviations. Solution: Fuzzy complete maps and abbreviations. (Yegappan Lakshmanan, closes #9856) Files: src/cmdexpand.c, src/map.c, src/proto/map.pro, src/search.c, src/testdir/test_cmdline.vim *** ../vim-8.2.4478/src/cmdexpand.c 2022-02-26 16:05:05.030403209 +0000 --- src/cmdexpand.c 2022-02-27 12:01:28.427935734 +0000 *************** *** 56,62 **** && 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 --- 56,61 ---- *************** *** 1216,1225 **** // 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 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' ! if (*cmd == 'k' && cmd[1] != 'e') { eap->cmdidx = CMD_k; p = cmd + 1; --- 1215,1226 ---- // 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". 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 (!fuzzy && (*cmd == 'k' && cmd[1] != 'e')) { eap->cmdidx = CMD_k; p = cmd + 1; *************** *** 2596,2602 **** || xp->xp_context == EXPAND_BOOL_SETTINGS) ret = ExpandSettings(xp, ®match, pat, numMatches, matches); else if (xp->xp_context == EXPAND_MAPPINGS) ! ret = ExpandMappings(®match, numMatches, matches); # if defined(FEAT_EVAL) else if (xp->xp_context == EXPAND_USER_DEFINED) ret = ExpandUserDefined(xp, ®match, matches, numMatches); --- 2597,2603 ---- || xp->xp_context == EXPAND_BOOL_SETTINGS) ret = ExpandSettings(xp, ®match, pat, numMatches, matches); else if (xp->xp_context == EXPAND_MAPPINGS) ! ret = ExpandMappings(pat, ®match, numMatches, matches); # if defined(FEAT_EVAL) else if (xp->xp_context == EXPAND_USER_DEFINED) ret = ExpandUserDefined(xp, ®match, matches, numMatches); *************** *** 2712,2718 **** fuzmatch = ALLOC_MULT(fuzmatch_str_T, count); else *matches = ALLOC_MULT(char_u *, count); ! if ((fuzzy && (fuzmatch == NULL)) || (*matches == NULL)) { *numMatches = 0; *matches = NULL; --- 2713,2720 ---- fuzmatch = ALLOC_MULT(fuzmatch_str_T, count); else *matches = ALLOC_MULT(char_u *, count); ! if ((!fuzzy && (*matches == NULL)) ! || (fuzzy && (fuzmatch == NULL))) { *numMatches = 0; *matches = NULL; *** ../vim-8.2.4478/src/map.c 2022-02-16 18:27:32.583437344 +0000 --- src/map.c 2022-02-27 12:01:28.427935734 +0000 *************** *** 1257,1265 **** */ int ExpandMappings( regmatch_T *regmatch, ! int *num_file, ! char_u ***file) { mapblock_T *mp; int hash; --- 1257,1266 ---- */ int ExpandMappings( + char_u *pat, regmatch_T *regmatch, ! int *numMatches, ! char_u ***matches) { mapblock_T *mp; int hash; *************** *** 1267,1277 **** int round; char_u *p; int i; validate_maphash(); ! *num_file = 0; // return values in case of FAIL ! *file = NULL; // round == 1: Count the matches. // round == 2: Build the array to keep the matches. --- 1268,1284 ---- 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(); ! *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,1284 **** --- 1286,1292 ---- { count = 0; + // First search in map modifier arguments for (i = 0; i < 7; ++i) { if (i == 0) *************** *** 1300,1312 **** else continue; ! if (vim_regexec(regmatch, p, (colnr_T)0)) { ! if (round == 1) ! ++count; else ! (*file)[count++] = vim_strsave(p); } } for (hash = 0; hash < 256; ++hash) --- 1308,1336 ---- else continue; ! 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 (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) *************** *** 1326,1339 **** if (mp->m_mode & expand_mapmodes) { p = translate_mapping(mp->m_keys); ! if (p != NULL && vim_regexec(regmatch, p, (colnr_T)0)) { ! if (round == 1) ! ++count; else { ! (*file)[count++] = p; ! p = NULL; } } vim_free(p); --- 1350,1380 ---- if (mp->m_mode & expand_mapmodes) { p = translate_mapping(mp->m_keys); ! if (p != NULL) { ! if (!fuzzy) ! match = vim_regexec(regmatch, p, (colnr_T)0); else { ! 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,1357 **** if (round == 1) { ! *file = ALLOC_MULT(char_u *, count); ! if (*file == NULL) ! return FAIL; } } // for (round) if (count > 1) { char_u **ptr1; --- 1387,1411 ---- if (round == 1) { ! 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,1368 **** char_u **ptr3; // Sort the matches ! sort_strings(*file, count); // Remove multiple entries ! ptr1 = *file; ptr2 = ptr1 + 1; ptr3 = ptr1 + count; --- 1413,1424 ---- char_u **ptr3; // Sort the matches ! // Fuzzy matching already sorts the matches ! if (!fuzzy) ! sort_strings(*matches, count); // Remove multiple entries ! ptr1 = *matches; ptr2 = ptr1 + 1; ptr3 = ptr1 + count; *************** *** 1378,1384 **** } } ! *num_file = count; return (count == 0 ? FAIL : OK); } --- 1434,1440 ---- } } ! *numMatches = count; return (count == 0 ? FAIL : OK); } *** ../vim-8.2.4478/src/proto/map.pro 2022-01-11 11:58:14.920745981 +0000 --- src/proto/map.pro 2022-02-27 12:01:28.431935722 +0000 *************** *** 8,14 **** 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 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); --- 8,14 ---- 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(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); *** ../vim-8.2.4478/src/search.c 2022-02-25 15:24:21.049157319 +0000 --- src/search.c 2022-02-27 12:01:28.431935722 +0000 *************** *** 5006,5012 **** if (str == NULL || pat == NULL) return 0; ! fuzzy_match(str, pat, FALSE, &score, matchpos, sizeof(matchpos) / sizeof(matchpos[0])); return score; --- 5006,5012 ---- if (str == NULL || pat == NULL) return 0; ! fuzzy_match(str, pat, TRUE, &score, matchpos, sizeof(matchpos) / sizeof(matchpos[0])); return score; *** ../vim-8.2.4478/src/testdir/test_cmdline.vim 2022-02-26 16:05:05.030403209 +0000 --- src/testdir/test_cmdline.vim 2022-02-27 12:01:28.431935722 +0000 *************** *** 2658,2668 **** call feedkeys(":mapclear buf\\\"\", 'tx') call assert_equal('"mapclear ', @:) ! " map name fuzzy completion - NOT supported " test regex completion works set wildoptions=fuzzy call feedkeys(":cnoremap \\\"\", 'tx') call assert_equal("\"cnoremap \", @:) " menu name fuzzy completion if has('gui_running') --- 2658,2709 ---- call feedkeys(":mapclear buf\\\"\", 'tx') call assert_equal('"mapclear ', @:) ! " map name fuzzy completion " test regex completion works set wildoptions=fuzzy call feedkeys(":cnoremap \\\"\", 'tx') call assert_equal("\"cnoremap \", @:) + nmap MyLongMap :p + call feedkeys(":nmap MLM\\\"\", 'tx') + call assert_equal("\"nmap MyLongMap", @:) + call feedkeys(":nmap MLM \\\"\", 'tx') + call assert_equal("\"nmap MLM \t", @:) + call feedkeys(":nmap one two \\\"\", 'tx') + call assert_equal("\"nmap one two \t", @:) + " duplicate entries should be removed + vmap MyLongMap :# + call feedkeys(":nmap MLM\\\"\", 'tx') + call assert_equal("\"nmap MyLongMap", @:) + nunmap MyLongMap + vunmap MyLongMap + call feedkeys(":nmap ABC\\\"\", 'tx') + call assert_equal("\"nmap ABC\t", @:) + " results should be sorted by best match + nmap format : + nmap goformat : + nmap TestFOrmat : + nmap fendoff : + nmap state : + nmap FendingOff : + call feedkeys(":nmap fo\\\"\", 'tx') + call assert_equal("\"nmap format TestFOrmat FendingOff goformat fendoff", @:) + nunmap format + nunmap goformat + nunmap TestFOrmat + nunmap fendoff + nunmap state + nunmap FendingOff + + " abbreviation fuzzy completion + set wildoptions=fuzzy + call feedkeys(":iabbr wait\\\"\", 'tx') + call assert_equal("\"iabbr ", @:) + iabbr WaitForCompletion WFC + call feedkeys(":iabbr fcl\\\"\", 'tx') + call assert_equal("\"iabbr WaitForCompletion", @:) + call feedkeys(":iabbr a1z\\\"\", 'tx') + call assert_equal("\"iabbr a1z\t", @:) + iunabbrev WaitForCompletion " menu name fuzzy completion if has('gui_running') *************** *** 2792,2797 **** --- 2833,2848 ---- call assert_equal('"Foo2Bar', @:) delcommand Foo2Bar + " Test for command completion for a command starting with 'k' + command KillKillKill : + set wildoptions& + call feedkeys(":killkill\\\"\", 'tx') + call assert_equal("\"killkill\", @:) + set wildoptions=fuzzy + call feedkeys(":killkill\\\"\", 'tx') + call assert_equal('"KillKillKill', @:) + delcom KillKillKill + set wildoptions& %bw! endfunc *** ../vim-8.2.4478/src/version.c 2022-02-26 16:05:05.034403199 +0000 --- src/version.c 2022-02-27 12:04:06.599471869 +0000 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 4479, /**/ -- hundred-and-one symptoms of being an internet addict: 114. You are counting items, you go "0,1,2,3,4,5,6,7,8,9,A,B,C,D...". /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///