Skip to content

feat: add completefuzzycollect - #16032

Closed
glepnir wants to merge 1 commit into
vim:masterfrom
glepnir:fuzzycollect
Closed

glepnir wants to merge 1 commit into
vim:masterfrom
glepnir:fuzzycollect

Conversation

@glepnir

@glepnir glepnir commented Nov 11, 2024

Copy link
Copy Markdown
Member

fuzzy in completeopt means to fuzzy filter each cp_str only if our compl_match doubly linked list is not empty. For some default completion modes use the new option completefuzzycollect in ins-completion to control this. This way there will be no violation of the original behavior.

Fix #15296
Fix #15295
Fix #15294

@glepnir
glepnir marked this pull request as draft November 11, 2024 09:22
Comment thread src/testdir/test_ins_complete.vim Outdated
Comment thread src/Makefile Outdated
@roccomao

Copy link
Copy Markdown
Contributor

In order to be compatible with various devices, especially old versions of Vim: I hope that the new features will not affect the user experience of my original settings, because the higher consistency is generally more comfortable to use. I just compiled your PR, it works well and meets my expectations. Now I can add set completeopt+=fuzzy directly to the newer version Vim without affecting previous usage habits. I ran this test with all my current configuration and plugins in place and saw no unexpected results now. Therefore, the fuzzy option of completeopt now perfectly matches my original description in the issue #15295 and #15296.


About #15294, I don't need fuzzy collection very much personally, I just need the fuzzy filter to work perfectly with longest. Now fuzzy filter and fuzzy collect are separated, so let's test the completefuzzycollect option.

To be honest, it is not easy to make longest and completefuzzycollect work at the same time and meet different needs. I can't decide how to balance them. But I personally prefer an effect similar to noinsert of completeopt. To consider a minimal demo:

  1. vim --clean
  2. set completeopt+=longest,fuzzy
  3. set completefuzzycollect+=k
  4. input : hello helio think
    1. If we enter he then press <C-n>, it will complete to hel and a candidate list hello helio will appear. This is OK.
    2. If we enter hi then press <C-n>, the hi will be deleted and a candidate list helio think will appear. I do NOT want the hi to be deleted, so I set extra option set completeopt+=noinsert.
    3. Now we enter hi then press <C-n> again, the hi will NOT be deleted and a candidate list helio think will appear. This is OK.
    4. Then repeat first step, enter he then press <C-n>, but now it will NOT autocomplete to hel.

So my personal idea is to implement a effect similar to noinsert by default. When longest completion is not possible, do NOT use any other characters to change the leading character that has been entered, just pop up the candidate menu.

Another issue, run vim --clean, then set completeopt+=longest and set completefuzzycollect+=w will cause the candidate list to disappear. Input line: test line a, test line b, then input te in a new line and press <C-x><C-l>, then someone of the two lines will be completed but NO candidate lists appear.

Of course, after the fuzzy filter and fuzzy collect are separated, we now have more choices, such as if !empty(&completefuzzycollect) | set completeopt-=longest | endif. In conclusion, Nice patch, thanks a lot! 👍

Comment thread runtime/doc/options.txt Outdated
@glepnir

glepnir commented Nov 13, 2024

Copy link
Copy Markdown
Member Author

Thanks for the detailed reply. I will fix the wholeline bug later. I will take a look at longest.

Comment thread runtime/doc/options.txt Outdated
@glepnir
glepnir force-pushed the fuzzycollect branch 7 times, most recently from 417401d to d2a8a5d Compare November 15, 2024 14:11
@glepnir
glepnir force-pushed the fuzzycollect branch 13 times, most recently from 79fd1f1 to 66f5bc9 Compare November 17, 2024 06:11
@roccomao

Copy link
Copy Markdown
Contributor

See your new commit, did you revert your last commit? To be honest, I think you can consider how to balance it later.

fixed and you can get think now in this case hello helio think helpful with h<C-n>k

As a summary, let's categorize the achievements before this submission about this reply.

Firstly, Most importantly, fuzzy filter and fuzzy collect are separated, which gives us too many choices.

For me personally, I just need set completeopt=xxx,longest,fuzzy to run stably, now it's OK.

  • set completeopt=xxx,longest,fuzzy without set completefuzzycollect, OK

Then, We have been discussing and testing set completefuzzycollect=k with longest.

  1. set completefuzzycollect=k with set completeopt=xxx,longest ( no fuzzy ), OK

  2. set completefuzzycollect=k with set completeopt=xxx,fuzzy ( no longest ), OK of course

  3. set completefuzzycollect=k with set completeopt=xxx,longest,fuzzy :

    This will only slightly lose some fuzzy filter feature at some rare points, but this is NOT a bug, it is just a side effect of our choice of set completefuzzycollect=k and longest, because longest will automatically expand our input. At this point, we can still select candidates through <Up>, <Down> or <C-p> / <C-n> and use fuzzy feature to filter candidates with leading characters which longest has completed. This is all based on your understanding of longest and what longest does. If in the rare case that you are still not satisfied with this behavior, you can also choose:

    if !empty(&completefuzzycollect)
        set completeopt-=longest
    endif

    or ( you know clearly that you don't use the fuzzy filtering )

    if !empty(&completefuzzycollect)
        set completeopt-=fuzzy
    endif

    Note that again, about this third point, is NOT a bug. I don't think there is any need for excessive optimization at this time.

In conclusion, I will only set set completeopt=xxx,longest,fuzzy personally, I don't care about the option completefuzzycollect very much. Actually, I removed fuzzy from my completeopt option since patch 9.1.0598 . So I just hope to be able to include this patch in the release version as soon as possible. As for the small details of the third point mentioned above, people who really need it may provide some other suggestions later, and it will not be too late to optimize it. What do you think ?


Example is that if there only exist a word hello, when enable longest and set completefuzzycollect=k, then we enter h and press <C-n>, the hello should be auto completed.

Now this bug comes back 😄

BTW, this bug still exists in the latest commit.

@glepnir
glepnir force-pushed the fuzzycollect branch 2 times, most recently from b299d0f to 7f32f01 Compare February 26, 2025 12:45
Comment thread src/insexpand.c Outdated
Comment thread src/insexpand.c Outdated
@glepnir

glepnir commented Feb 28, 2025

Copy link
Copy Markdown
Member Author

@roccomao The current behavior is that subsequent input will not be searched again. This means that if you type h for hello helio think`, you will get hel. If you type k again, you will not get think.

@roccomao

Copy link
Copy Markdown
Contributor

The current behavior is that subsequent input will not be searched again. This means that if you type h for hello helio think`, you will get hel. If you type k again, you will not get think.

@glepnir First of all, I think this is acceptable at present. I seem to have a long comment before to explain why. I remember that the purpose of pointing this out at first seemed to be just to propose a possible requirement.

Thanks for your work, I may do some simple testing again later to give you feedback.

@glepnir

glepnir commented Feb 28, 2025

Copy link
Copy Markdown
Member Author

Thank you for your kind help ❤️

@roccomao

Copy link
Copy Markdown
Contributor

@glepnir LGTM 👍

And after revert this, As you said before, now the problem of comment[1] and comment[2] is gone too.

@glepnir

glepnir commented Mar 1, 2025

Copy link
Copy Markdown
Member Author

@zeertzjq @chrisbra PTAL when you're available and let me know how you feel about the current behavior

Comment thread src/proto/search.pro Outdated
Comment thread runtime/doc/options.txt Outdated
Comment thread runtime/doc/options.txt Outdated
each enabling fuzzy collection for a specific completion mode:
k keyword completion in 'complete' and current file
l whole lines
f file names

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use the values "keyword", "lines", "files" instead? That way it is more intuitive.
Also I have to wonder, what about the other completion modes? Will that be done later? Or is not affected?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I have to wonder, what about the other completion modes? Will that be done later? Or is not affected?

not be affected. because they are all separated. If there are bugs, it will not affect daily use. If someone needs a certain mode to be included, then implement it here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use the values "keyword", "lines", "files" instead? That way it is more intuitive.

okay

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not affected means what? Other completion methods will be supporting "fuzzy collection" or not? Please clarify in the doc.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the documentation has already explained that only keyword filename wholeline is supported. Those outside this range are not supported.

Comment thread src/insexpand.c
Comment thread src/insexpand.c Outdated
Comment thread src/insexpand.c Outdated
Comment thread runtime/doc/options.txt Outdated
Comment thread src/insexpand.c
Comment thread src/insexpand.c
Comment thread src/insexpand.c Outdated
Comment thread src/insexpand.c Outdated
@techntools

Copy link
Copy Markdown

@glepnir Thank you for working on this

Might I suggest:

  1. whole_line -> wholeline or just line (no underscore and no plural)

  2. files -> file or filename (no plural)

@techntools

Copy link
Copy Markdown

It just sounds consistent with:

set completeopt=popuphidden --- not pupup_hidden

set cursorlineopt=screenline ---> not screen_line

set messagesopt=hit-enter ---> - is used

@zeertzjq

zeertzjq commented Mar 6, 2025

Copy link
Copy Markdown
Member

:h complete_info_mode

@techntools

Copy link
Copy Markdown

But those are return values of complete_info(mode), correct ?

A bit different than values for set someoption=...

@chrisbra

chrisbra commented Mar 6, 2025

Copy link
Copy Markdown
Member

thanks all.

@zeertzjq

zeertzjq commented Mar 7, 2025

Copy link
Copy Markdown
Member

But those are return values of complete_info(mode), correct ?

A bit different than values for set someoption=...

There is also 'mousemodel', which accepts popup_setpos as a value.

@chrisbra

chrisbra commented Mar 7, 2025

Copy link
Copy Markdown
Member

Unfortunately, this introduce 2 warnings in Coverity:

  1. https://scan5.scan.coverity.com/#/project-view/41242/10101?selectedIssue=1644149
leader = ins_compl_leader();
       54. Condition leader != NULL, taking false branch.
       55. var_compare_op: Comparing leader to null implies that leader might be null.
3961    if (leader != NULL)
3962        leader_len = STRLEN(leader);
3963
3964    // skip non-consecutive prefixes
      
CID 1644149: (#1 of 1): Dereference after null check (FORWARD_NULL)
56. var_deref_model: Passing null pointer leader to strncmp, which dereferences it.
3965    if (STRNCMP(prefix, leader, leader_len) != 0)
3966        goto end;
  1. https://scan5.scan.coverity.com/#/project-view/41242/10101?selectedIssue=1644150
         }
       12. Condition in_fuzzy_collect, taking true branch.
       13. Condition leader_len > 0, taking true branch.
       25. Condition in_fuzzy_collect, taking true branch.
       26. Condition leader_len > 0, taking true branch.
1854            else if (in_fuzzy_collect && leader_len > 0)
1855            {
1856                line_end = find_line_end(ptr);
       14. Condition ptr < line_end, taking true branch.
       27. Condition ptr < line_end, taking true branch.
       32. Condition ptr < line_end, taking true branch.
       37. Condition ptr < line_end, taking true branch.
1857                while (ptr < line_end)
1858                {
       15. Condition fuzzy_match_str_in_line(&ptr, leader, &len, NULL, &score), taking false branch.
       28. Condition fuzzy_match_str_in_line(&ptr, leader, &len, NULL, &score), taking false branch.
       33. Condition fuzzy_match_str_in_line(&ptr, leader, &len, NULL, &score), taking false branch.
      
CID 1644150: (#3 of 3): Untrusted value as argument (TAINTED_SCALAR)
38. tainted_data: Passing tainted expression *ptr to fuzzy_match_str_in_line, which uses it as an offset.[show details]
       Ensure that tainted values are properly sanitized, by checking that their values are within a permissible range.
       CID 1644150:(#1 of 3):Untrusted value as argument (TAINTED_SCALAR) [ "select issue" ]
       CID 1644150:(#2 of 3):Untrusted value as argument (TAINTED_SCALAR) [ "select issue" ]
1859                    if (fuzzy_match_str_in_line(&ptr, leader, &len, NULL, &score))
1860                    {
1861                        char_u *end_ptr = ctrl_x_mode_line_or_eval()
1862                                        ? find_line_end(ptr) : find_word_end(ptr);
1863                        add_r = ins_compl_add_infercase(ptr, (int)(end_ptr - ptr),
1864                                            p_ic, files[i], *dir, FALSE, score);
1865                        if (add_r == FAIL)
1866                            break;
1867                        ptr = end_ptr;  // start from next word
1868                        if (compl_get_longest && ctrl_x_mode_normal()
1869                                && compl_first_match->cp_next
1870                                && score == compl_first_match->cp_next->cp_score)
1871                            compl_num_bests++;
1872                    }

@glepnir can you please check it?

Thanks

@zeertzjq

zeertzjq commented Mar 7, 2025

Copy link
Copy Markdown
Member

#16814 may fix the first Coverity warning

@Shane-XB-Qian

This comment was marked as off-topic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

6 participants