Use a completion dialog for multiple matches

Bug #715955 reported by Ryan Wooden
24
This bug affects 5 people
Affects Status Importance Assigned to Milestone
UltiSnips
Triaged
Wishlist
Unassigned

Bug Description

This started in bug #714119, the ideas are summarized here.

The idea is to use the standard vim completion window when more than one completion matches the typed text. This seems like a much cleaner way of handling this case, rather than using the menu UltiSnips uses now.

You can force a completion menu using the complete() function. I don't think you can find out exactly which thing the user picks though. I was thinking that maybe we could trigger the completion window, and if it matched multiple snippets with the same trigger, then we could append a number (or similar) to the end to make them unique. We can add the number to the "word" part of the completion-item and not the "abbr" part which is shown in the menu (see complete-items). If we did this, then we would need to temporarily add the new triggers to the snippet as well.

For the regular expressions, we may be able to temporarily do something to make them unique, then if it's picked, put the original text back in and force that snippet to expand so that the match information is generated properly

Revision history for this message
SirVer (sirver) wrote :

This is a non trivial change to UltiSnips but one I wholeheartedly agree with.

Changed in ultisnips:
status: New → Confirmed
importance: Undecided → Low
Revision history for this message
SirVer (sirver) wrote :

Just a comment: snipmate uses menus like we currently do.

I prefer the xptemplate way in theory, but after testing it, I realized that it didn't expand snippets when I used supertab and expand on tab. I am unsure if this is a bug in xptemplate or a problem when using the completion menu.

SirVer (sirver)
Changed in ultisnips:
importance: Low → Wishlist
Revision history for this message
SirVer (sirver) wrote :

I further investigated it and think now that it is not worth the trouble. Xptemplate makes a huge fuzz to support it using heuristics to guess when the user has accepted an input from the dialog compared to when he just canceled the completion dialog (at least thats what I made from the source code.... vim script is not really easy to read for me).

All together I guess this is a lot of work and I feel (currently) too little benefit. I set this to incomplete - when noone complains I will mark it Won't fix in 60 days.

Changed in ultisnips:
status: Confirmed → Incomplete
Revision history for this message
Rich Alesi (scio62) wrote :

Snipmate uses Tom Link's tlib package (http://www.vim.org/scripts/script.php?script_id=1863) to allow tab completion of possible entries.

It is quite simple to use, UltiSnips would just need to add a function to echo out all possible snippets that match, you then call this function within tlib#input#CommandSelect and you get a list that can be further reduced by additional typing, or selected with the keyboard. Once selected, you just need to figure out the command to run with the selected text (like the mapping to complete a snippet).

An example I have for listing all the available marks (just from the default :marks command in vim), and jump to the selected mark is:

command! TMarks exec 'norm! `'. matchstr(tlib#input#CommandSelect('marks'), '^ \+\zs.')

If I could find a way to stdout the possible snippets in a command without using the inputlist() you use in _ask_snippets(), it would be relatively straightforward to get it working with Tlib

Revision history for this message
Rich Alesi (scio62) wrote :

I hacked a working copy together: It lists possible options if more than one (selecting it will complete the snippet), or completes the snippet if only one is available.

in vimrc:

" Need a command to list the snippets
command! UltiList :call UltiSnips_ListSnippetsNP()

func! SnippetList()
    " exec ':norm a'. matchstr(tlib#input#CommandSelect('UltiList'), '^\S\+\s(\zs.*\ze)') . "ì"

    let response = matchstr(tlib#input#CommandSelect('UltiList'), '^\S\+\s(\zs.*\ze)')
    if !empty(response)
        " find the part of the line that already has been typed
        let part = matchstr(response,getline('.'))
        if !empty(part)
            let response = strpart(response,len(part))
        endif
        exec ':norm a'.response
        :norm l
        :call UltiSnips_ExpandSnippet()
    endif
endfunc

nnoremap ,s :call SnippetList()<cr>
inoremap <c-x><c-s> <esc>:call SnippetList()<cr>

in UltiSnips __init__.py:
    @err_to_scratch_buffer
    def list_snippets_noprompt(self):
        before, after = _vim.buf.current_line_splitted
        snippets = self._snips(before, True)

        # Sort snippets alphabetically
        snippets.sort(key=lambda x: x.trigger)

        snippet = self._ask_snippets(snippets,prompt=False)

in UltiSnips.vim:
    function! UltiSnips_ListSnippetsNP()
        exec g:_uspy "UltiSnips_Manager.list_snippets_noprompt()"
    endfunction

I can try to submit it as a patch, but wanted to see if you were interested first.

Revision history for this message
Rich Alesi (scio62) wrote :

Oops, it's a bit easier than that (no need to modify original source):

" Need a command to list the snippets
command! UltiList :call UltiSnips_ListSnippets()

func! SnippetList()
    let response = matchstr(tlib#input#CommandSelect('UltiList'), '^\S\+\s(\zs.*\ze)')
    if !empty(response)
        " find the part of the line that already has been typed
        echom expand("<cword>")
        let part = matchstr(response,expand("<cword>"))
        if !empty(part)
            let response = strpart(response,len(part))
        endif
        exec ':norm a'.response
        :norm l
        :call UltiSnips_ExpandSnippet()
    endif
endfunc

nnoremap ,s :call SnippetList()<cr>
inoremap <c-x><c-s> <esc>:call SnippetList()<cr>

This also allows completion for snippets with the `w` flag

Revision history for this message
SirVer (sirver) wrote :

Rich, thanks for your work on this! However, having a third party dependency is currently out of the question: In fact I heard several times that people prefered UltiSnips over snipmate because it did not have any dependency at all.

However that you provided a workable solution means that it is technically feasible. If it works in VimL, it should work in python with less code as well. However, I will not be able to work on this for quite some time

Revision history for this message
Manpreet Singh (junkblocker) wrote :

+1 Having to hunt and type numbers in long list is a pain. As an example, the unite plugin has a very nice ecosystem of 'drop-in plugins that generate selectable items' built around providing this selection mechanism which is a pleasure to use. So, please do consider implementing this! :)

Revision history for this message
SirVer (sirver) wrote : Re: [Bug 715955] Re: Use a completion dialog for multiple matches

I have two questions:

1) When do you have long lists to pick from? I practically never use the
selection menu - only when I have more than one snippet with the same
tab trigger.

2) unite plugin seems to do something along this line: Open a new window
that shows 'results' and lets you select them comparable to how the
quickfix window works. Is this correct? Why do you prefer this over the
completion dialogue that vim provides? (eg with C-N C-X)

Otherwise: I am terribly busy with my dissertation atm, so do not hold
your breath for new feature in the foreseeable future. Patches are always
welcome though.

Revision history for this message
Launchpad Janitor (janitor) wrote :

[Expired for UltiSnips because there has been no activity for 60 days.]

Changed in ultisnips:
status: Incomplete → Expired
Revision history for this message
SirVer (sirver) wrote :

Manpreet, could you please review my questions in #9?

Changed in ultisnips:
status: Expired → Incomplete
Revision history for this message
Launchpad Janitor (janitor) wrote :

[Expired for UltiSnips because there has been no activity for 60 days.]

Changed in ultisnips:
status: Incomplete → Expired
Revision history for this message
SirVer (sirver) wrote :

Well, this idea seems to have support, but not enough to keep people answering use case questions. I have no use for it and little time for UltiSnips. I will accept well made patches though.

Changed in ultisnips:
status: Expired → Triaged
Revision history for this message
stardiviner (numbchild) wrote :

I hope to let UltiSnips be one source of neocomplcache plugin. neocomplcache has one snippet plugin called neocomplcache-snippets-complete, but it does not have many features, so I hope there is an plugin can add UltiSnips's possible snippets into neocomplcache popup menu candidates list.

Why I need this ?
Well, I find it is complicated between different languages, (I'm not very familar with programming languages), for example, some language use "def" to define a function, so I'll set triiger to "def", some language like shell will use "function" to define, then this is different between languages.
And there are some snippets like `if`, `ife`, `ifee`, they are `if .. end`, `if .. else .. end`, `if .. elif .. else .. end`, when I type `if`, Vim popup available snippets is really needed. (well, maybe is not that so needed, because maybe most people use UltiSnips remember what they write in snippets file).

Revision history for this message
DavidBriscoe (idbrii) wrote :

My two use cases stem from making my snippet triggers descriptive words to make them better mnemonics (for my poor memory):

I name my snippet triggers so that if the boilerplate code is an if statement, the trigger begins with if (I find it easier to remember what snippets I have this way). Each language has different snippets, but I know I want to do something conditional, I type if and trigger snippet completion to see which one I wanted. I can't use shorter snippet names or I'll never remember them. Since I have several if snippets, I use completion a lot.

I also have 6 snippets for debug info. They all start with db, followed by the type of info: dbtext for screen text, dbprint for logging, etc... I often use snippet completion for these.

The big advantage of using ins-completion over Ultisnip's 123 completion is that if there are many snippets with similar triggers, it's easier to narrow the list of possibilities: you just type more of the trigger. Also, I'm using ins-completion constantly when writing in vim, so my fingers know how to work it. I have to look at the numbered list and then the keyboard to do 123 completion (my touch typing is only really good for text).

Revision history for this message
SirVer (sirver) wrote :

Thanks for providing this use case. Could you have a look at MarcWebers branch of Ultisnips?
https://github.com/MarcWeber/ultisnips

He did some work prepping Ultisnips so that we can merge snipMate functionality into it and he implemented this very feauture. Please report back how that works for you and if this is what you had intended.

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.