To: vim_dev@googlegroups.com Subject: Patch 8.2.4760 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4760 Problem: Using matchfuzzy() on a long list can take a while. Solution: Add a limit to the number of matches. (Yasuhiro Matsumoto, closes #10189) Files: runtime/doc/builtin.txt, src/search.c, src/testdir/test_matchfuzzy.vim *** ../vim-8.2.4759/runtime/doc/builtin.txt 2022-04-12 12:54:06.917010952 +0100 --- runtime/doc/builtin.txt 2022-04-16 12:32:02.928950392 +0100 *************** *** 5565,5571 **** If {list} is a list of dictionaries, then the optional {dict} argument supports the following additional items: ! key key of the item which is fuzzy matched against {str}. The value of this item should be a string. text_cb |Funcref| that will be called for every item --- 5583,5589 ---- If {list} is a list of dictionaries, then the optional {dict} argument supports the following additional items: ! key Key of the item which is fuzzy matched against {str}. The value of this item should be a string. text_cb |Funcref| that will be called for every item *************** *** 5573,5578 **** --- 5591,5598 ---- This should accept a dictionary item as the argument and return the text for that item to 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 matching is NOT supported. The maximum supported {str} length *************** *** 5585,5591 **** empty list is returned. If length of {str} is greater than 256, then returns an empty list. ! Refer to |fuzzy-match| for more information about fuzzy matching strings. Example: > --- 5605,5614 ---- empty list is returned. If length of {str} is greater than 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 matching strings. Example: > *** ../vim-8.2.4759/src/search.c 2022-04-10 18:09:03.075959743 +0100 --- src/search.c 2022-04-16 12:27:13.228168375 +0100 *************** *** 4648,4666 **** char_u *key, callback_T *item_cb, int retmatchpos, ! list_T *fmatchlist) { long len; fuzzyItem_T *ptrs; listitem_T *li; long i = 0; ! int found_match = FALSE; int_u matches[MAX_FUZZY_MATCHES]; len = list_len(items); if (len == 0) return; ptrs = ALLOC_CLEAR_MULT(fuzzyItem_T, len); if (ptrs == NULL) return; --- 4648,4668 ---- char_u *key, callback_T *item_cb, int retmatchpos, ! list_T *fmatchlist, ! long max_matches) { long len; fuzzyItem_T *ptrs; listitem_T *li; long i = 0; ! long found_match = 0; int_u matches[MAX_FUZZY_MATCHES]; len = list_len(items); if (len == 0) return; + // TODO: when using a limit use that instead of "len" ptrs = ALLOC_CLEAR_MULT(fuzzyItem_T, len); if (ptrs == NULL) return; *************** *** 4675,4680 **** --- 4677,4691 ---- ptrs[i].idx = i; ptrs[i].item = li; 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; rettv.v_type = VAR_UNKNOWN; if (li->li_tv.v_type == VAR_STRING) // list of strings *************** *** 4736,4748 **** } } ptrs[i].score = score; ! found_match = TRUE; } ++i; clear_tv(&rettv); } ! if (found_match) { list_T *l; --- 4747,4759 ---- } } ptrs[i].score = score; ! ++found_match; } ++i; clear_tv(&rettv); } ! if (found_match > 0) { list_T *l; *************** *** 4822,4827 **** --- 4833,4839 ---- char_u *key = NULL; int ret; int matchseq = FALSE; + long max_matches = 0; if (in_vim9script() && (check_for_list_arg(argvars, 0) == FAIL *************** *** 4879,4884 **** --- 4891,4906 ---- 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")) matchseq = TRUE; } *************** *** 4913,4919 **** } fuzzy_match_in_list(argvars[0].vval.v_list, tv_get_string(&argvars[1]), ! matchseq, key, &cb, retmatchpos, rettv->vval.v_list); done: free_callback(&cb); --- 4935,4941 ---- } fuzzy_match_in_list(argvars[0].vval.v_list, tv_get_string(&argvars[1]), ! matchseq, key, &cb, retmatchpos, rettv->vval.v_list, max_matches); done: free_callback(&cb); *** ../vim-8.2.4759/src/testdir/test_matchfuzzy.vim 2021-01-02 17:31:10.887220293 +0000 --- src/testdir/test_matchfuzzy.vim 2022-04-16 12:16:45.818897317 +0100 *************** *** 230,233 **** --- 230,245 ---- call assert_equal([['xффйд'], [[2, 3, 4]], [168]], matchfuzzypos(['xффйд'], 'фйд')) 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-8.2.4759/src/version.c 2022-04-16 12:03:34.176519007 +0100 --- src/version.c 2022-04-16 12:18:53.874671915 +0100 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 4760, /**/ -- The process for understanding customers primarily involves sitting around with other marketing people and talking about what you would to if you were dumb enough to be a customer. (Scott Adams - The Dilbert principle) /// 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 ///