Como criar minha própria função de preenchimento automático?


22

Como crio minha própria lista de preenchimento automático para certos tipos de arquivos?

Por exemplo, eu gostaria que o CSS e o HTML fossem preenchidos automaticamente a partir da lista de classes de CSS no FontAwesome .

Respostas:


22

A conclusão do dicionário seria uma solução barata e não intrusiva:

  1. salve o fontawesome.txt em algum lugar da sua máquina,

  2. coloque isso after/ftplugin/css.vim(crie o arquivo se ele não existir):

    setlocal complete+=k
    setlocal dictionary+=/path/to/fontawesome.txt
    setlocal iskeyword+=-
    
  3. inicie uma nova sessão ou faça :eum buffer CSS para forçar a origem do arquivo acima,

  4. pressione <C-n>ou <C-p>no modo de inserção,

  5. desfrutar!

    conclusão do dicionário

Referência:

:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'

17

EDIT Graças ao comentário de romainl, editei minha resposta para mostrar como criar uma função de conclusão definida pelo usuário. Na versão anterior, eu estava substituindo a omni-conclusão do buil-in, o que não era bom porque o usuário teria perdido a conclusão padrão, que é bastante poderosa.


Uma solução vimscript

Uma solução é usar o vimscript e o fato de o vim criar uma função de conclusão customizada.

A vantagem desta solução é que você não precisa de um plug-in adicional; basta criar uma função de conclusão definida pelo usuário e usar o recurso de conclusão interno.

Usarei seu exemplo das classes fontAwesome em cssarquivos:

Crie o arquivo ~/.vim/autoload/csscomplete.vime insira as seguintes linhas:

let s:matches=".fa-lg .fa-2x .fa-3x .fa-4x .fa-5x .fa-fw .fa-ul .fa-ul .fa-li .fa-li.fa-lg .fa-border .fa-pull-left .fa-pull-right .fa.fa-pull-left"

function! csscomplete#CompleteFA(findstart, base)
    if a:findstart
        " locate the start of the word
        let line = getline('.')
        let start = col('.') - 1
        while start > 0 && (line[start - 1] =~ '\a' || line[start - 1] =~ '.' || line[start - 1] =~ '-')
            let start -= 1
        endwhile
        return start
    else
        " find classes matching "a:base"
        let res = []
        for m in split(s:matches)
            if m =~ '^' . a:base
                call add(res, m)
            endif
        endfor
        return res
    endif
endfun

Em seguida, crie o arquivo ~/.vim/after/ftplugin/css.vime coloque nele a seguinte linha:

setlocal completefunc=csscomplete#CompleteFA

Em seguida, você pode ativar sua função de conclusão definida pelo usuário com <C-x><C-u>. Ele tentará encontrar uma correspondência com a última palavra digitada.

Na captura de tela, digitei .fa-le, em seguida, ativei a função com <C-x><C-u>:

insira a descrição da imagem aqui


Como funciona?

Primeiro, aqui estão alguns tópicos de documentação relevantes:

Se você deseja criar um preenchimento personalizado para um tipo de arquivo específico, é necessário colocá-lo no arquivo $HOME/.vim/autoload/{FILETYPE}complete.vim.

Nesse arquivo, você deve criar sua função de conclusão, chamada duas vezes:

  • Na primeira chamada, seu primeiro argumento é a posição atual do cursor e a função determinará a palavra a ser concluída. Na minha função, usei 3 comparações para concluir a palavra porque a classe pode ser composta de letras .e - (acho que é possível melhorar essa correspondência, mas sou muito ruim com a expressão regular)

  • Na segunda chamada, o segundo argumento é a palavra a ser correspondida e, em seguida, a função a compara com a lista de classes possíveis para corresponder a 1 . Aqui você vê que eu retorno um dicionário que preenche o menu de conclusão, mas quando você ler a documentação, poderá criar um dicionário muito mais complexo para personalizar ainda mais o comportamento de sua função.

Você também precisa informar ao Vim "para esse tipo de arquivo, use esta função completa que eu criei". Para isso, é necessário definir completefunco nome da função criada (aqui csscomplete#CompleteFA) e essa configuração deve ser feita no arquivo $HOME/.vim/after/ftplugin/{FILETYPE}.vim.

1 Na minha função, a variável s:matchescontém todas as correspondências possíveis. Aqui, apenas coloco algumas sugestões de legibilidade, mas você pode colocar todas as classes oferecidas pelo FontAwesome (Você pode encontrar a lista completa neste arquivo criado por romainl).


E se eu não gostar do Vimscript?

Uma possibilidade é usar o plugin YoucompleteMe, que oferece uma API para brincar com o menu de conclusão. Você pode criar a função python que fará o trabalho correspondente e usará a API para preencher a interface do Vim. Mais detalhes aqui .


2
A conclusão omni padrão para CSS e HTML já é bastante útil e você pode ter apenas uma por vez, então sugiro usar "conclusão definida pelo usuário". Veja :help i_ctrl-x_ctrl-u.
Romainl 30/08/2015

@romainl: Você está absolutamente certo, vou ver como adaptar minha resposta.
statox

5

Às vezes, você deseja um preenchimento automático personalizado que não interfira em nenhum dos preenchimentos automáticos integrados ou definidos pelo usuário. Isso é especialmente útil para scripts ou plugins destinados a trabalhar para uma ampla variedade de tipos de arquivos.

Isso pode ser feito facilmente com a complete() função e um invólucro simples; a maior parte do procedimento é a mesma descrita na :help complete-functions resposta da Statox, exceto que você precisa definir seus próprios mapeamentos e precisa se chamar em complete()vez de retornar um valor.

Aqui está um exemplo básico, os comentários devem explicar como funciona.

" Map <C-x><C-m> for our custom completion
inoremap <C-x><C-m> <C-r>=MyComplete()<CR>

" Make subsequent <C-m> presses after <C-x><C-m> go to the next entry (just like
" other <C-x>* mappings)
inoremap <expr> <C-m> pumvisible() ?  "\<C-n>" : "\<C-m>"

" Complete function for addresses; we match the name & address
fun! MyComplete()
    " The data. In this example it's static, but you could read it from a file,
    " get it from a command, etc.
    let l:data = [
        \ ["Elmo the Elk", "daring@brave.com"],
        \ ["Eek the Cat", "doesnthurt@help.com"]
    \ ]

    " Locate the start of the word and store the text we want to match in l:base
    let l:line = getline('.')
    let l:start = col('.') - 1
    while l:start > 0 && l:line[l:start - 1] =~ '\a'
        let l:start -= 1
    endwhile
    let l:base = l:line[l:start : col('.')-1]

    " Record what matches − we pass this to complete() later
    let l:res = []

    " Find matches
    for m in l:data
        " Check if it matches what we're trying to complete; in this case we
        " want to match against the start of both the first and second list
        " entries (i.e. the name and email address)
        if l:m[0] !~? '^' . l:base && l:m[1] !~? '^' . l:base
            " Doesn't match
            continue
        endif

        " It matches! See :help complete() for the full docs on the key names
        " for this dict.
        call add(l:res, {
            \ 'icase': 1,
            \ 'word': l:m[0] . ' <' . l:m[1] . '>, ',
            \ 'abbr': l:m[0],
            \ 'menu': l:m[1],
            \ 'info': len(l:m) > 2 ? join(l:m[2:], "\n") : '',
        \ })
    endfor

    " Now call the complete() function
    call complete(l:start + 1, l:res)
    return ''
endfun
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.