forked from aniani/vim
patch 8.2.4760: using matchfuzzy() on a long list can take a while
Problem: Using matchfuzzy() on a long list can take a while. Solution: Add a limit to the number of matches. (Yasuhiro Matsumoto, closes #10189)
This commit is contained in:
committed by
Bram Moolenaar
parent
693ccd1160
commit
9029a6e993
@@ -5581,7 +5581,7 @@ matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()*
|
|||||||
|
|
||||||
If {list} is a list of dictionaries, then the optional {dict}
|
If {list} is a list of dictionaries, then the optional {dict}
|
||||||
argument supports the following additional items:
|
argument supports the following additional items:
|
||||||
key key of the item which is fuzzy matched against
|
key Key of the item which is fuzzy matched against
|
||||||
{str}. The value of this item should be a
|
{str}. The value of this item should be a
|
||||||
string.
|
string.
|
||||||
text_cb |Funcref| that will be called for every item
|
text_cb |Funcref| that will be called for every item
|
||||||
@@ -5589,6 +5589,8 @@ matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()*
|
|||||||
This should accept a dictionary item as the
|
This should accept a dictionary item as the
|
||||||
argument and return the text for that item to
|
argument and return the text for that item to
|
||||||
use for fuzzy matching.
|
use for fuzzy matching.
|
||||||
|
limit Maximum number of matches in {list} to be
|
||||||
|
returned. Zero means no limit.
|
||||||
|
|
||||||
{str} is treated as a literal string and regular expression
|
{str} is treated as a literal string and regular expression
|
||||||
matching is NOT supported. The maximum supported {str} length
|
matching is NOT supported. The maximum supported {str} length
|
||||||
@@ -5601,6 +5603,9 @@ matchfuzzy({list}, {str} [, {dict}]) *matchfuzzy()*
|
|||||||
empty list is returned. If length of {str} is greater than
|
empty list is returned. If length of {str} is greater than
|
||||||
256, then returns an empty list.
|
256, then returns an empty list.
|
||||||
|
|
||||||
|
When {limit} is given, matchfuzzy() will find up to this
|
||||||
|
number of matches in {list} and return them in sorted order.
|
||||||
|
|
||||||
Refer to |fuzzy-matching| for more information about fuzzy
|
Refer to |fuzzy-matching| for more information about fuzzy
|
||||||
matching strings.
|
matching strings.
|
||||||
|
|
||||||
|
32
src/search.c
32
src/search.c
@@ -4648,19 +4648,21 @@ fuzzy_match_in_list(
|
|||||||
char_u *key,
|
char_u *key,
|
||||||
callback_T *item_cb,
|
callback_T *item_cb,
|
||||||
int retmatchpos,
|
int retmatchpos,
|
||||||
list_T *fmatchlist)
|
list_T *fmatchlist,
|
||||||
|
long max_matches)
|
||||||
{
|
{
|
||||||
long len;
|
long len;
|
||||||
fuzzyItem_T *ptrs;
|
fuzzyItem_T *ptrs;
|
||||||
listitem_T *li;
|
listitem_T *li;
|
||||||
long i = 0;
|
long i = 0;
|
||||||
int found_match = FALSE;
|
long found_match = 0;
|
||||||
int_u matches[MAX_FUZZY_MATCHES];
|
int_u matches[MAX_FUZZY_MATCHES];
|
||||||
|
|
||||||
len = list_len(items);
|
len = list_len(items);
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// TODO: when using a limit use that instead of "len"
|
||||||
ptrs = ALLOC_CLEAR_MULT(fuzzyItem_T, len);
|
ptrs = ALLOC_CLEAR_MULT(fuzzyItem_T, len);
|
||||||
if (ptrs == NULL)
|
if (ptrs == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -4675,6 +4677,15 @@ fuzzy_match_in_list(
|
|||||||
ptrs[i].idx = i;
|
ptrs[i].idx = i;
|
||||||
ptrs[i].item = li;
|
ptrs[i].item = li;
|
||||||
ptrs[i].score = SCORE_NONE;
|
ptrs[i].score = SCORE_NONE;
|
||||||
|
|
||||||
|
// TODO: instead of putting all items in ptrs[] should only add
|
||||||
|
// matching items there.
|
||||||
|
if (max_matches > 0 && found_match >= max_matches)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
itemstr = NULL;
|
itemstr = NULL;
|
||||||
rettv.v_type = VAR_UNKNOWN;
|
rettv.v_type = VAR_UNKNOWN;
|
||||||
if (li->li_tv.v_type == VAR_STRING) // list of strings
|
if (li->li_tv.v_type == VAR_STRING) // list of strings
|
||||||
@@ -4736,13 +4747,13 @@ fuzzy_match_in_list(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ptrs[i].score = score;
|
ptrs[i].score = score;
|
||||||
found_match = TRUE;
|
++found_match;
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
clear_tv(&rettv);
|
clear_tv(&rettv);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_match)
|
if (found_match > 0)
|
||||||
{
|
{
|
||||||
list_T *l;
|
list_T *l;
|
||||||
|
|
||||||
@@ -4822,6 +4833,7 @@ do_fuzzymatch(typval_T *argvars, typval_T *rettv, int retmatchpos)
|
|||||||
char_u *key = NULL;
|
char_u *key = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
int matchseq = FALSE;
|
int matchseq = FALSE;
|
||||||
|
long max_matches = 0;
|
||||||
|
|
||||||
if (in_vim9script()
|
if (in_vim9script()
|
||||||
&& (check_for_list_arg(argvars, 0) == FAIL
|
&& (check_for_list_arg(argvars, 0) == FAIL
|
||||||
@@ -4879,6 +4891,16 @@ do_fuzzymatch(typval_T *argvars, typval_T *rettv, int retmatchpos)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if ((di = dict_find(d, (char_u *)"limit", -1)) != NULL)
|
||||||
|
{
|
||||||
|
if (di->di_tv.v_type != VAR_NUMBER)
|
||||||
|
{
|
||||||
|
semsg(_(e_invalid_argument_str), tv_get_string(&di->di_tv));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
max_matches = (long)tv_get_number_chk(&di->di_tv, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (dict_has_key(d, "matchseq"))
|
if (dict_has_key(d, "matchseq"))
|
||||||
matchseq = TRUE;
|
matchseq = TRUE;
|
||||||
}
|
}
|
||||||
@@ -4913,7 +4935,7 @@ do_fuzzymatch(typval_T *argvars, typval_T *rettv, int retmatchpos)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fuzzy_match_in_list(argvars[0].vval.v_list, tv_get_string(&argvars[1]),
|
fuzzy_match_in_list(argvars[0].vval.v_list, tv_get_string(&argvars[1]),
|
||||||
matchseq, key, &cb, retmatchpos, rettv->vval.v_list);
|
matchseq, key, &cb, retmatchpos, rettv->vval.v_list, max_matches);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
free_callback(&cb);
|
free_callback(&cb);
|
||||||
|
@@ -230,4 +230,16 @@ func Test_matchfuzzypos_mbyte()
|
|||||||
call assert_equal([['xффйд'], [[2, 3, 4]], [168]], matchfuzzypos(['xффйд'], 'фйд'))
|
call assert_equal([['xффйд'], [[2, 3, 4]], [168]], matchfuzzypos(['xффйд'], 'фйд'))
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test for matchfuzzy() with limit
|
||||||
|
func Test_matchfuzzy_limit()
|
||||||
|
let x = ['1', '2', '3', '2']
|
||||||
|
call assert_equal(['2', '2'], x->matchfuzzy('2'))
|
||||||
|
call assert_equal(['2', '2'], x->matchfuzzy('2', #{}))
|
||||||
|
call assert_equal(['2', '2'], x->matchfuzzy('2', #{limit: 0}))
|
||||||
|
call assert_equal(['2'], x->matchfuzzy('2', #{limit: 1}))
|
||||||
|
call assert_equal(['2', '2'], x->matchfuzzy('2', #{limit: 2}))
|
||||||
|
call assert_equal(['2', '2'], x->matchfuzzy('2', #{limit: 3}))
|
||||||
|
call assert_fails("call matchfuzzy(x, '2', #{limit: '2'})", 'E475:')
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -746,6 +746,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 */
|
||||||
|
/**/
|
||||||
|
4760,
|
||||||
/**/
|
/**/
|
||||||
4759,
|
4759,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user