Ultisnips: Using built-in completion with UltiSnips

Created on 29 Aug 2017  路  8Comments  路  Source: SirVer/ultisnips

Vim has various built-in completion systems, e.g.:

  • <C-x C-l>: Line
  • <C-x C-i>: From current and included files
  • <C-x C-]>: Tags
  • <C-x C-f>: Filenames
  • <C-x C-n> or <C-n>: From after cursor position
  • <C-x C-p> or <C-p>: From before cursor position

Can any of these be used to select a snippet? For example, I have various snippets defined as ifvariable, iffileexists, etc... I'd like be able to just type if then a trigger (like C-x C-p), and then select from a list of my snippets that begin with if. Is that possible?

Thanks!

answered or workaround exists caused by vims design user question

Most helpful comment

@robenkleene You can write a custom completefunc to use with built-in <C-x C-u>.
I use the following function for markdown files (based on @lacygoill and this SO answer):

function! functions#ListSnippets(findstart, base) abort
    if empty(UltiSnips#SnippetsInCurrentScope(1))
        return ''
    endif

    if a:findstart
        " locate the start of the word
        let line = getline('.')
        let start = col('.') - 1
        while start > 0 && (line[start - 1] =~ '\a')
            let start -= 1
        endwhile
        return start
    else
        " find classes matching "a:base"
        let res = []
        for m in keys(g:current_ulti_dict_info)
            if m =~ a:base
                let n = {
                    \ 'word': m,
                    \ 'menu': '[snip] '. g:current_ulti_dict_info[m]['description']
                    \ }
                call add(res, n)
            endif
        endfor
        return res
    endif
endfunction

and then in ftplugin/markdown.vim:
setlocal completefunc=functions#ListSnippets

it still needs some tweaking, but it gets the job done quite well.

All 8 comments

FWIW, I use something similar to this:

ino <silent> <c-x><c-z> <c-r>=<sid>ulti_complete()<cr>

fu! s:ulti_complete() abort
    if empty(UltiSnips#SnippetsInCurrentScope(1))
        return ''
    endif
    let word_to_complete = matchstr(strpart(getline('.'), 0, col('.') - 1), '\S\+$')
    let contain_word = 'stridx(v:val, word_to_complete)>=0'
    let candidates = map(filter(keys(g:current_ulti_dict_info), contain_word),
                   \  "{
                   \      'word': v:val,
                   \      'menu': '[snip] '. g:current_ulti_dict_info[v:val]['description'],
                   \      'dup' : 1,
                   \   }")
    let from_where = col('.') - len(word_to_complete)
    if !empty(candidates)
        call complete(from_where, candidates)
    endif
    return ''
endfu

It installs a mapping on C-x C-z which should complete the text before the cursor using the tab triggers you defined for the current filetype.

For more information, see:

:help complete()
:help UltiSnips#SnippetsInCurrentScope

Thanks lacygoill! I was able to set this up and it looks like it's working. I'd still prefer it if there were a way to use one of Vim's many existing completion systems to complete snippets, but this is the next best thing!

@robenkleene I do not know of a way of extending Vim's built in completion with custom completion (i.e. snippets). @lacygoill Solution is the closest you can get.

@robenkleene You can write a custom completefunc to use with built-in <C-x C-u>.
I use the following function for markdown files (based on @lacygoill and this SO answer):

function! functions#ListSnippets(findstart, base) abort
    if empty(UltiSnips#SnippetsInCurrentScope(1))
        return ''
    endif

    if a:findstart
        " locate the start of the word
        let line = getline('.')
        let start = col('.') - 1
        while start > 0 && (line[start - 1] =~ '\a')
            let start -= 1
        endwhile
        return start
    else
        " find classes matching "a:base"
        let res = []
        for m in keys(g:current_ulti_dict_info)
            if m =~ a:base
                let n = {
                    \ 'word': m,
                    \ 'menu': '[snip] '. g:current_ulti_dict_info[m]['description']
                    \ }
                call add(res, n)
            endif
        endfor
        return res
    endif
endfunction

and then in ftplugin/markdown.vim:
setlocal completefunc=functions#ListSnippets

it still needs some tweaking, but it gets the job done quite well.

Thanks for sharing this @wolloda! I've switched to this method and so far it's working great.

If we want to match from beginning:

if m =~ "^" . a:base
 " ...       
endif

@wolloda Thanks for sharing.

can ultisnips has this function as built-in function? can be better than the prompt way

can ultisnips has this function as built-in function? can be better than the prompt way

Yeah man, would be great

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jonathf picture jonathf  路  6Comments

chrisrytting picture chrisrytting  路  7Comments

Alex-Canales picture Alex-Canales  路  4Comments

Industrial picture Industrial  路  8Comments

ghost picture ghost  路  8Comments