Mercurial > vim
comparison src/search.c @ 28481:3eac1299015a v8.2.4765
patch 8.2.4765: function matchfuzzy() sorts too many items
Commit: https://github.com/vim/vim/commit/047a7019b293918343998ccbdfabd48c771f5eef
Author: Yegappan Lakshmanan <yegappan@yahoo.com>
Date: Sat Apr 16 20:42:40 2022 +0100
patch 8.2.4765: function matchfuzzy() sorts too many items
Problem: Function matchfuzzy() sorts too many items.
Solution: Only put matches in the array. (Yegappan Lakshmanan,
closes #10208)
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Sat, 16 Apr 2022 21:45:02 +0200 |
parents | 2ade724b3f45 |
children | d770568e6c98 |
comparison
equal
deleted
inserted
replaced
28480:a08f13ce2bd0 | 28481:3eac1299015a |
---|---|
4640 * If 'retmatchpos' is TRUE, then return a list of positions where 'str' | 4640 * If 'retmatchpos' is TRUE, then return a list of positions where 'str' |
4641 * matches for each item. | 4641 * matches for each item. |
4642 */ | 4642 */ |
4643 static void | 4643 static void |
4644 fuzzy_match_in_list( | 4644 fuzzy_match_in_list( |
4645 list_T *items, | 4645 list_T *l, |
4646 char_u *str, | 4646 char_u *str, |
4647 int matchseq, | 4647 int matchseq, |
4648 char_u *key, | 4648 char_u *key, |
4649 callback_T *item_cb, | 4649 callback_T *item_cb, |
4650 int retmatchpos, | 4650 int retmatchpos, |
4651 list_T *fmatchlist, | 4651 list_T *fmatchlist, |
4652 long max_matches) | 4652 long max_matches) |
4653 { | 4653 { |
4654 long len; | 4654 long len; |
4655 fuzzyItem_T *ptrs; | 4655 fuzzyItem_T *items; |
4656 listitem_T *li; | 4656 listitem_T *li; |
4657 long i = 0; | 4657 long i = 0; |
4658 long found_match = 0; | 4658 long match_count = 0; |
4659 int_u matches[MAX_FUZZY_MATCHES]; | 4659 int_u matches[MAX_FUZZY_MATCHES]; |
4660 | 4660 |
4661 len = list_len(items); | 4661 len = list_len(l); |
4662 if (len == 0) | 4662 if (len == 0) |
4663 return; | 4663 return; |
4664 | 4664 if (max_matches > 0 && len > max_matches) |
4665 // TODO: when using a limit use that instead of "len" | 4665 len = max_matches; |
4666 ptrs = ALLOC_CLEAR_MULT(fuzzyItem_T, len); | 4666 |
4667 if (ptrs == NULL) | 4667 items = ALLOC_CLEAR_MULT(fuzzyItem_T, len); |
4668 if (items == NULL) | |
4668 return; | 4669 return; |
4669 | 4670 |
4670 // For all the string items in items, get the fuzzy matching score | 4671 // For all the string items in items, get the fuzzy matching score |
4671 FOR_ALL_LIST_ITEMS(items, li) | 4672 FOR_ALL_LIST_ITEMS(l, li) |
4672 { | 4673 { |
4673 int score; | 4674 int score; |
4674 char_u *itemstr; | 4675 char_u *itemstr; |
4675 typval_T rettv; | 4676 typval_T rettv; |
4676 | 4677 |
4677 ptrs[i].idx = i; | 4678 if (max_matches > 0 && match_count >= max_matches) |
4678 ptrs[i].item = li; | 4679 break; |
4679 ptrs[i].score = SCORE_NONE; | |
4680 | |
4681 // TODO: instead of putting all items in ptrs[] should only add | |
4682 // matching items there. | |
4683 if (max_matches > 0 && found_match >= max_matches) | |
4684 { | |
4685 i++; | |
4686 continue; | |
4687 } | |
4688 | 4680 |
4689 itemstr = NULL; | 4681 itemstr = NULL; |
4690 rettv.v_type = VAR_UNKNOWN; | 4682 rettv.v_type = VAR_UNKNOWN; |
4691 if (li->li_tv.v_type == VAR_STRING) // list of strings | 4683 if (li->li_tv.v_type == VAR_STRING) // list of strings |
4692 itemstr = li->li_tv.vval.v_string; | 4684 itemstr = li->li_tv.vval.v_string; |
4693 else if (li->li_tv.v_type == VAR_DICT | 4685 else if (li->li_tv.v_type == VAR_DICT |
4694 && (key != NULL || item_cb->cb_name != NULL)) | 4686 && (key != NULL || item_cb->cb_name != NULL)) |
4695 { | 4687 { |
4696 // For a dict, either use the specified key to lookup the string or | 4688 // For a dict, either use the specified key to lookup the string or |
4697 // use the specified callback function to get the string. | 4689 // use the specified callback function to get the string. |
4698 if (key != NULL) | 4690 if (key != NULL) |
4699 itemstr = dict_get_string(li->li_tv.vval.v_dict, key, FALSE); | 4691 itemstr = dict_get_string(li->li_tv.vval.v_dict, key, FALSE); |
4715 } | 4707 } |
4716 } | 4708 } |
4717 | 4709 |
4718 if (itemstr != NULL | 4710 if (itemstr != NULL |
4719 && fuzzy_match(itemstr, str, matchseq, &score, matches, | 4711 && fuzzy_match(itemstr, str, matchseq, &score, matches, |
4720 sizeof(matches) / sizeof(matches[0]))) | 4712 MAX_FUZZY_MATCHES)) |
4721 { | 4713 { |
4714 items[match_count].idx = match_count; | |
4715 items[match_count].item = li; | |
4716 items[match_count].score = score; | |
4717 | |
4722 // Copy the list of matching positions in itemstr to a list, if | 4718 // Copy the list of matching positions in itemstr to a list, if |
4723 // 'retmatchpos' is set. | 4719 // 'retmatchpos' is set. |
4724 if (retmatchpos) | 4720 if (retmatchpos) |
4725 { | 4721 { |
4726 int j = 0; | 4722 int j = 0; |
4727 char_u *p; | 4723 char_u *p; |
4728 | 4724 |
4729 ptrs[i].lmatchpos = list_alloc(); | 4725 items[match_count].lmatchpos = list_alloc(); |
4730 if (ptrs[i].lmatchpos == NULL) | 4726 if (items[match_count].lmatchpos == NULL) |
4731 goto done; | 4727 goto done; |
4732 | 4728 |
4733 p = str; | 4729 p = str; |
4734 while (*p != NUL) | 4730 while (*p != NUL) |
4735 { | 4731 { |
4736 if (!VIM_ISWHITE(PTR2CHAR(p))) | 4732 if (!VIM_ISWHITE(PTR2CHAR(p))) |
4737 { | 4733 { |
4738 if (list_append_number(ptrs[i].lmatchpos, | 4734 if (list_append_number(items[match_count].lmatchpos, |
4739 matches[j]) == FAIL) | 4735 matches[j]) == FAIL) |
4740 goto done; | 4736 goto done; |
4741 j++; | 4737 j++; |
4742 } | 4738 } |
4743 if (has_mbyte) | 4739 if (has_mbyte) |
4744 MB_PTR_ADV(p); | 4740 MB_PTR_ADV(p); |
4745 else | 4741 else |
4746 ++p; | 4742 ++p; |
4747 } | 4743 } |
4748 } | 4744 } |
4749 ptrs[i].score = score; | 4745 ++match_count; |
4750 ++found_match; | 4746 } |
4751 } | |
4752 ++i; | |
4753 clear_tv(&rettv); | 4747 clear_tv(&rettv); |
4754 } | 4748 } |
4755 | 4749 |
4756 if (found_match > 0) | 4750 if (match_count > 0) |
4757 { | 4751 { |
4758 list_T *l; | 4752 list_T *retlist; |
4759 | 4753 |
4760 // Sort the list by the descending order of the match score | 4754 // Sort the list by the descending order of the match score |
4761 qsort((void *)ptrs, (size_t)len, sizeof(fuzzyItem_T), | 4755 qsort((void *)items, (size_t)match_count, sizeof(fuzzyItem_T), |
4762 fuzzy_match_item_compare); | 4756 fuzzy_match_item_compare); |
4763 | 4757 |
4764 // For matchfuzzy(), return a list of matched strings. | 4758 // For matchfuzzy(), return a list of matched strings. |
4765 // ['str1', 'str2', 'str3'] | 4759 // ['str1', 'str2', 'str3'] |
4766 // For matchfuzzypos(), return a list with three items. | 4760 // For matchfuzzypos(), return a list with three items. |
4771 if (retmatchpos) | 4765 if (retmatchpos) |
4772 { | 4766 { |
4773 li = list_find(fmatchlist, 0); | 4767 li = list_find(fmatchlist, 0); |
4774 if (li == NULL || li->li_tv.vval.v_list == NULL) | 4768 if (li == NULL || li->li_tv.vval.v_list == NULL) |
4775 goto done; | 4769 goto done; |
4776 l = li->li_tv.vval.v_list; | 4770 retlist = li->li_tv.vval.v_list; |
4777 } | 4771 } |
4778 else | 4772 else |
4779 l = fmatchlist; | 4773 retlist = fmatchlist; |
4780 | 4774 |
4781 // Copy the matching strings with a valid score to the return list | 4775 // Copy the matching strings with a valid score to the return list |
4782 for (i = 0; i < len; i++) | 4776 for (i = 0; i < match_count; i++) |
4783 { | 4777 { |
4784 if (ptrs[i].score == SCORE_NONE) | 4778 if (items[i].score == SCORE_NONE) |
4785 break; | 4779 break; |
4786 list_append_tv(l, &ptrs[i].item->li_tv); | 4780 list_append_tv(retlist, &items[i].item->li_tv); |
4787 } | 4781 } |
4788 | 4782 |
4789 // next copy the list of matching positions | 4783 // next copy the list of matching positions |
4790 if (retmatchpos) | 4784 if (retmatchpos) |
4791 { | 4785 { |
4792 li = list_find(fmatchlist, -2); | 4786 li = list_find(fmatchlist, -2); |
4793 if (li == NULL || li->li_tv.vval.v_list == NULL) | 4787 if (li == NULL || li->li_tv.vval.v_list == NULL) |
4794 goto done; | 4788 goto done; |
4795 l = li->li_tv.vval.v_list; | 4789 retlist = li->li_tv.vval.v_list; |
4796 | 4790 |
4797 for (i = 0; i < len; i++) | 4791 for (i = 0; i < match_count; i++) |
4798 { | 4792 { |
4799 if (ptrs[i].score == SCORE_NONE) | 4793 if (items[i].score == SCORE_NONE) |
4800 break; | 4794 break; |
4801 if (ptrs[i].lmatchpos != NULL | 4795 if (items[i].lmatchpos != NULL |
4802 && list_append_list(l, ptrs[i].lmatchpos) == FAIL) | 4796 && list_append_list(retlist, items[i].lmatchpos) |
4797 == FAIL) | |
4803 goto done; | 4798 goto done; |
4804 } | 4799 } |
4805 | 4800 |
4806 // copy the matching scores | 4801 // copy the matching scores |
4807 li = list_find(fmatchlist, -1); | 4802 li = list_find(fmatchlist, -1); |
4808 if (li == NULL || li->li_tv.vval.v_list == NULL) | 4803 if (li == NULL || li->li_tv.vval.v_list == NULL) |
4809 goto done; | 4804 goto done; |
4810 l = li->li_tv.vval.v_list; | 4805 retlist = li->li_tv.vval.v_list; |
4811 for (i = 0; i < len; i++) | 4806 for (i = 0; i < match_count; i++) |
4812 { | 4807 { |
4813 if (ptrs[i].score == SCORE_NONE) | 4808 if (items[i].score == SCORE_NONE) |
4814 break; | 4809 break; |
4815 if (list_append_number(l, ptrs[i].score) == FAIL) | 4810 if (list_append_number(retlist, items[i].score) == FAIL) |
4816 goto done; | 4811 goto done; |
4817 } | 4812 } |
4818 } | 4813 } |
4819 } | 4814 } |
4820 | 4815 |
4821 done: | 4816 done: |
4822 vim_free(ptrs); | 4817 vim_free(items); |
4823 } | 4818 } |
4824 | 4819 |
4825 /* | 4820 /* |
4826 * Do fuzzy matching. Returns the list of matched strings in 'rettv'. | 4821 * Do fuzzy matching. Returns the list of matched strings in 'rettv'. |
4827 * If 'retmatchpos' is TRUE, also returns the matching character positions. | 4822 * If 'retmatchpos' is TRUE, also returns the matching character positions. |