Mercurial > vim
comparison src/cmdexpand.c @ 27875:ae38d2e81fca v8.2.4463
patch 8.2.4463: completion only uses strict matching
Commit: https://github.com/vim/vim/commit/38b85cb4d7216705058708bacbc25ab90cd61595
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Thu Feb 24 13:28:41 2022 +0000
patch 8.2.4463: completion only uses strict matching
Problem: Completion only uses strict matching.
Solution: Add the "fuzzy" item for 'wildoptions'. (Yegappan Lakshmanan,
closes #9803)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Thu, 24 Feb 2022 14:30:05 +0100 |
parents | 010fa62d6fe2 |
children | 76e2115dddb8 |
comparison
equal
deleted
inserted
replaced
27874:f4a227222e7a | 27875:ae38d2e81fca |
---|---|
16 static int cmd_showtail; // Only show path tail in lists ? | 16 static int cmd_showtail; // Only show path tail in lists ? |
17 | 17 |
18 static void set_expand_context(expand_T *xp); | 18 static void set_expand_context(expand_T *xp); |
19 static int ExpandGeneric(expand_T *xp, regmatch_T *regmatch, | 19 static int ExpandGeneric(expand_T *xp, regmatch_T *regmatch, |
20 char_u ***matches, int *numMatches, | 20 char_u ***matches, int *numMatches, |
21 char_u *((*func)(expand_T *, int)), int escaped); | 21 char_u *((*func)(expand_T *, int)), int escaped, |
22 char_u *fuzzystr); | |
22 static int ExpandFromContext(expand_T *xp, char_u *, char_u ***, int *, int); | 23 static int ExpandFromContext(expand_T *xp, char_u *, char_u ***, int *, int); |
23 static int expand_showtail(expand_T *xp); | 24 static int expand_showtail(expand_T *xp); |
24 static int expand_shellcmd(char_u *filepat, char_u ***matches, int *numMatches, int flagsarg); | 25 static int expand_shellcmd(char_u *filepat, char_u ***matches, int *numMatches, int flagsarg); |
25 #if defined(FEAT_EVAL) | 26 #if defined(FEAT_EVAL) |
26 static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char_u ***matches, int *numMatches); | 27 static int ExpandUserDefined(expand_T *xp, regmatch_T *regmatch, char_u ***matches, int *numMatches); |
36 static int compl_startcol; | 37 static int compl_startcol; |
37 static int compl_selected; | 38 static int compl_selected; |
38 #endif | 39 #endif |
39 | 40 |
40 #define SHOW_FILE_TEXT(m) (showtail ? sm_gettail(matches[m]) : matches[m]) | 41 #define SHOW_FILE_TEXT(m) (showtail ? sm_gettail(matches[m]) : matches[m]) |
42 | |
43 /* | |
44 * Returns TRUE if fuzzy completion is supported for a given cmdline completion | |
45 * context. | |
46 */ | |
47 static int | |
48 cmdline_fuzzy_completion_supported(expand_T *xp) | |
49 { | |
50 return (vim_strchr(p_wop, WOP_FUZZY) != NULL | |
51 && xp->xp_context != EXPAND_BOOL_SETTINGS | |
52 && xp->xp_context != EXPAND_COLORS | |
53 && xp->xp_context != EXPAND_COMPILER | |
54 && xp->xp_context != EXPAND_DIRECTORIES | |
55 && xp->xp_context != EXPAND_FILES | |
56 && xp->xp_context != EXPAND_FILES_IN_PATH | |
57 && xp->xp_context != EXPAND_FILETYPE | |
58 && xp->xp_context != EXPAND_HELP | |
59 && xp->xp_context != EXPAND_MAPPINGS | |
60 && xp->xp_context != EXPAND_OLD_SETTING | |
61 && xp->xp_context != EXPAND_OWNSYNTAX | |
62 && xp->xp_context != EXPAND_PACKADD | |
63 && xp->xp_context != EXPAND_SHELLCMD | |
64 && xp->xp_context != EXPAND_TAGS | |
65 && xp->xp_context != EXPAND_TAGS_LISTFILES | |
66 && xp->xp_context != EXPAND_USER_DEFINED | |
67 && xp->xp_context != EXPAND_USER_LIST); | |
68 } | |
69 | |
70 /* | |
71 * Returns TRUE if fuzzy completion for cmdline completion is enabled and | |
72 * 'fuzzystr' is not empty. | |
73 */ | |
74 int | |
75 cmdline_fuzzy_complete(char_u *fuzzystr) | |
76 { | |
77 return vim_strchr(p_wop, WOP_FUZZY) != NULL && *fuzzystr != NUL; | |
78 } | |
41 | 79 |
42 /* | 80 /* |
43 * sort function for the completion matches. | 81 * sort function for the completion matches. |
44 * <SNR> functions should be sorted to the end. | 82 * <SNR> functions should be sorted to the end. |
45 */ | 83 */ |
193 // Get next/previous match for a previous expanded pattern. | 231 // Get next/previous match for a previous expanded pattern. |
194 p2 = ExpandOne(xp, NULL, NULL, 0, type); | 232 p2 = ExpandOne(xp, NULL, NULL, 0, type); |
195 } | 233 } |
196 else | 234 else |
197 { | 235 { |
236 if (cmdline_fuzzy_completion_supported(xp)) | |
237 // If fuzzy matching, don't modify the search string | |
238 p1 = vim_strsave(xp->xp_pattern); | |
239 else | |
240 p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); | |
241 | |
198 // Translate string into pattern and expand it. | 242 // Translate string into pattern and expand it. |
199 if ((p1 = addstar(xp->xp_pattern, xp->xp_pattern_len, | 243 if (p1 == NULL) |
200 xp->xp_context)) == NULL) | |
201 p2 = NULL; | 244 p2 = NULL; |
202 else | 245 else |
203 { | 246 { |
204 int use_options = options | | 247 int use_options = options | |
205 WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT; | 248 WILD_HOME_REPLACE|WILD_ADD_SLASH|WILD_SILENT; |
2186 return EXPAND_NOTHING; | 2229 return EXPAND_NOTHING; |
2187 } | 2230 } |
2188 | 2231 |
2189 // add star to file name, or convert to regexp if not exp. files. | 2232 // add star to file name, or convert to regexp if not exp. files. |
2190 xp->xp_pattern_len = (int)(str + col - xp->xp_pattern); | 2233 xp->xp_pattern_len = (int)(str + col - xp->xp_pattern); |
2191 file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); | 2234 if (cmdline_fuzzy_completion_supported(xp)) |
2192 if (file_str == NULL) | 2235 // If fuzzy matching, don't modify the search string |
2193 return EXPAND_UNSUCCESSFUL; | 2236 file_str = vim_strsave(xp->xp_pattern); |
2237 else | |
2238 { | |
2239 file_str = addstar(xp->xp_pattern, xp->xp_pattern_len, xp->xp_context); | |
2240 if (file_str == NULL) | |
2241 return EXPAND_UNSUCCESSFUL; | |
2242 } | |
2194 | 2243 |
2195 if (p_wic) | 2244 if (p_wic) |
2196 options += WILD_ICASE; | 2245 options += WILD_ICASE; |
2197 | 2246 |
2198 // find all files that match the description | 2247 // find all files that match the description |
2315 /* | 2364 /* |
2316 * Do the expansion based on xp->xp_context and 'rmp'. | 2365 * Do the expansion based on xp->xp_context and 'rmp'. |
2317 */ | 2366 */ |
2318 static int | 2367 static int |
2319 ExpandOther( | 2368 ExpandOther( |
2369 char_u *pat, | |
2320 expand_T *xp, | 2370 expand_T *xp, |
2321 regmatch_T *rmp, | 2371 regmatch_T *rmp, |
2322 char_u ***matches, | 2372 char_u ***matches, |
2323 int *numMatches) | 2373 int *numMatches) |
2324 { | 2374 { |
2384 // right function to do the expansion. | 2434 // right function to do the expansion. |
2385 for (i = 0; i < (int)ARRAY_LENGTH(tab); ++i) | 2435 for (i = 0; i < (int)ARRAY_LENGTH(tab); ++i) |
2386 { | 2436 { |
2387 if (xp->xp_context == tab[i].context) | 2437 if (xp->xp_context == tab[i].context) |
2388 { | 2438 { |
2439 // Use fuzzy matching if 'wildoptions' has 'fuzzy'. | |
2440 // If no search pattern is supplied, then don't use fuzzy | |
2441 // matching and return all the found items. | |
2442 int fuzzy = cmdline_fuzzy_complete(pat); | |
2443 | |
2389 if (tab[i].ic) | 2444 if (tab[i].ic) |
2390 rmp->rm_ic = TRUE; | 2445 rmp->rm_ic = TRUE; |
2391 ret = ExpandGeneric(xp, rmp, matches, numMatches, | 2446 ret = ExpandGeneric(xp, rmp, matches, numMatches, |
2392 tab[i].func, tab[i].escaped); | 2447 tab[i].func, tab[i].escaped, |
2448 fuzzy ? pat : NULL); | |
2393 break; | 2449 break; |
2394 } | 2450 } |
2395 } | 2451 } |
2396 | 2452 |
2397 return ret; | 2453 return ret; |
2528 // set ignore-case according to p_ic, p_scs and pat | 2584 // set ignore-case according to p_ic, p_scs and pat |
2529 regmatch.rm_ic = ignorecase(pat); | 2585 regmatch.rm_ic = ignorecase(pat); |
2530 | 2586 |
2531 if (xp->xp_context == EXPAND_SETTINGS | 2587 if (xp->xp_context == EXPAND_SETTINGS |
2532 || xp->xp_context == EXPAND_BOOL_SETTINGS) | 2588 || xp->xp_context == EXPAND_BOOL_SETTINGS) |
2533 ret = ExpandSettings(xp, ®match, numMatches, matches); | 2589 ret = ExpandSettings(xp, ®match, pat, numMatches, matches); |
2534 else if (xp->xp_context == EXPAND_MAPPINGS) | 2590 else if (xp->xp_context == EXPAND_MAPPINGS) |
2535 ret = ExpandMappings(®match, numMatches, matches); | 2591 ret = ExpandMappings(®match, numMatches, matches); |
2536 # if defined(FEAT_EVAL) | 2592 # if defined(FEAT_EVAL) |
2537 else if (xp->xp_context == EXPAND_USER_DEFINED) | 2593 else if (xp->xp_context == EXPAND_USER_DEFINED) |
2538 ret = ExpandUserDefined(xp, ®match, matches, numMatches); | 2594 ret = ExpandUserDefined(xp, ®match, matches, numMatches); |
2539 # endif | 2595 # endif |
2540 else | 2596 else |
2541 ret = ExpandOther(xp, ®match, matches, numMatches); | 2597 ret = ExpandOther(pat, xp, ®match, matches, numMatches); |
2542 | 2598 |
2543 vim_regfree(regmatch.regprog); | 2599 vim_regfree(regmatch.regprog); |
2544 vim_free(tofree); | 2600 vim_free(tofree); |
2545 | 2601 |
2546 return ret; | 2602 return ret; |
2550 * Expand a list of names. | 2606 * Expand a list of names. |
2551 * | 2607 * |
2552 * Generic function for command line completion. It calls a function to | 2608 * Generic function for command line completion. It calls a function to |
2553 * obtain strings, one by one. The strings are matched against a regexp | 2609 * obtain strings, one by one. The strings are matched against a regexp |
2554 * program. Matching strings are copied into an array, which is returned. | 2610 * program. Matching strings are copied into an array, which is returned. |
2611 * | |
2612 * If 'fuzzy' is TRUE, then fuzzy matching is used. Otherwise, regex matching | |
2613 * is used. | |
2555 * | 2614 * |
2556 * Returns OK when no problems encountered, FAIL for error (out of memory). | 2615 * Returns OK when no problems encountered, FAIL for error (out of memory). |
2557 */ | 2616 */ |
2558 static int | 2617 static int |
2559 ExpandGeneric( | 2618 ExpandGeneric( |
2561 regmatch_T *regmatch, | 2620 regmatch_T *regmatch, |
2562 char_u ***matches, | 2621 char_u ***matches, |
2563 int *numMatches, | 2622 int *numMatches, |
2564 char_u *((*func)(expand_T *, int)), | 2623 char_u *((*func)(expand_T *, int)), |
2565 // returns a string from the list | 2624 // returns a string from the list |
2566 int escaped) | 2625 int escaped, |
2626 char_u *fuzzystr) | |
2567 { | 2627 { |
2568 int i; | 2628 int i; |
2569 int count = 0; | 2629 int count = 0; |
2570 int round; | 2630 int round; |
2571 char_u *str; | 2631 char_u *str; |
2632 fuzmatch_str_T *fuzmatch = NULL; | |
2633 int score = 0; | |
2634 int fuzzy = (fuzzystr != NULL); | |
2635 int funcsort = FALSE; | |
2572 | 2636 |
2573 // do this loop twice: | 2637 // do this loop twice: |
2574 // round == 0: count the number of matching names | 2638 // round == 0: count the number of matching names |
2575 // round == 1: copy the matching names into allocated memory | 2639 // round == 1: copy the matching names into allocated memory |
2576 for (round = 0; round <= 1; ++round) | 2640 for (round = 0; round <= 1; ++round) |
2581 if (str == NULL) // end of list | 2645 if (str == NULL) // end of list |
2582 break; | 2646 break; |
2583 if (*str == NUL) // skip empty strings | 2647 if (*str == NUL) // skip empty strings |
2584 continue; | 2648 continue; |
2585 | 2649 |
2586 if (vim_regexec(regmatch, str, (colnr_T)0)) | 2650 if (vim_regexec(regmatch, str, (colnr_T)0) || |
2651 (fuzzy && ((score = fuzzy_match_str(str, fuzzystr)) != 0))) | |
2587 { | 2652 { |
2588 if (round) | 2653 if (round) |
2589 { | 2654 { |
2590 if (escaped) | 2655 if (escaped) |
2591 str = vim_strsave_escaped(str, (char_u *)" \t\\."); | 2656 str = vim_strsave_escaped(str, (char_u *)" \t\\."); |
2592 else | 2657 else |
2593 str = vim_strsave(str); | 2658 str = vim_strsave(str); |
2594 if (str == NULL) | 2659 if (str == NULL) |
2595 { | 2660 { |
2596 FreeWild(count, *matches); | 2661 FreeWild(count, *matches); |
2662 if (fuzzy) | |
2663 fuzmatch_str_free(fuzmatch, count); | |
2597 *numMatches = 0; | 2664 *numMatches = 0; |
2598 *matches = NULL; | 2665 *matches = NULL; |
2599 return FAIL; | 2666 return FAIL; |
2600 } | 2667 } |
2601 (*matches)[count] = str; | 2668 if (fuzzy) |
2669 { | |
2670 fuzmatch[count].idx = count; | |
2671 fuzmatch[count].str = str; | |
2672 fuzmatch[count].score = score; | |
2673 } | |
2674 else | |
2675 (*matches)[count] = str; | |
2602 # ifdef FEAT_MENU | 2676 # ifdef FEAT_MENU |
2603 if (func == get_menu_names && str != NULL) | 2677 if (func == get_menu_names && str != NULL) |
2604 { | 2678 { |
2605 // test for separator added by get_menu_names() | 2679 // test for separator added by get_menu_names() |
2606 str += STRLEN(str) - 1; | 2680 str += STRLEN(str) - 1; |
2614 } | 2688 } |
2615 if (round == 0) | 2689 if (round == 0) |
2616 { | 2690 { |
2617 if (count == 0) | 2691 if (count == 0) |
2618 return OK; | 2692 return OK; |
2619 *matches = ALLOC_MULT(char_u *, count); | 2693 if (fuzzy) |
2620 if (*matches == NULL) | 2694 fuzmatch = ALLOC_MULT(fuzmatch_str_T, count); |
2695 else | |
2696 *matches = ALLOC_MULT(char_u *, count); | |
2697 if ((fuzzy && (fuzmatch == NULL)) || (*matches == NULL)) | |
2621 { | 2698 { |
2622 *numMatches = 0; | 2699 *numMatches = 0; |
2623 *matches = NULL; | 2700 *matches = NULL; |
2624 return FAIL; | 2701 return FAIL; |
2625 } | 2702 } |
2633 { | 2710 { |
2634 if (xp->xp_context == EXPAND_EXPRESSION | 2711 if (xp->xp_context == EXPAND_EXPRESSION |
2635 || xp->xp_context == EXPAND_FUNCTIONS | 2712 || xp->xp_context == EXPAND_FUNCTIONS |
2636 || xp->xp_context == EXPAND_USER_FUNC | 2713 || xp->xp_context == EXPAND_USER_FUNC |
2637 || xp->xp_context == EXPAND_DISASSEMBLE) | 2714 || xp->xp_context == EXPAND_DISASSEMBLE) |
2715 { | |
2638 // <SNR> functions should be sorted to the end. | 2716 // <SNR> functions should be sorted to the end. |
2639 qsort((void *)*matches, (size_t)*numMatches, sizeof(char_u *), | 2717 funcsort = TRUE; |
2718 if (!fuzzy) | |
2719 qsort((void *)*matches, (size_t)*numMatches, sizeof(char_u *), | |
2640 sort_func_compare); | 2720 sort_func_compare); |
2721 } | |
2641 else | 2722 else |
2642 sort_strings(*matches, *numMatches); | 2723 { |
2724 if (!fuzzy) | |
2725 sort_strings(*matches, *numMatches); | |
2726 } | |
2643 } | 2727 } |
2644 | 2728 |
2645 #if defined(FEAT_SYN_HL) | 2729 #if defined(FEAT_SYN_HL) |
2646 // Reset the variables used for special highlight names expansion, so that | 2730 // Reset the variables used for special highlight names expansion, so that |
2647 // they don't show up when getting normal highlight names by ID. | 2731 // they don't show up when getting normal highlight names by ID. |
2648 reset_expand_highlight(); | 2732 reset_expand_highlight(); |
2649 #endif | 2733 #endif |
2734 | |
2735 if (fuzzy && fuzzymatches_to_strmatches(fuzmatch, matches, count, | |
2736 funcsort) == FAIL) | |
2737 return FAIL; | |
2738 | |
2650 return OK; | 2739 return OK; |
2651 } | 2740 } |
2652 | 2741 |
2653 /* | 2742 /* |
2654 * Expand shell command matches in one directory of $PATH. | 2743 * Expand shell command matches in one directory of $PATH. |