¿Cómo crear mi propia función de autocompletar?


22

¿Cómo creo mi propia lista de autocompletado para ciertos tipos de archivos?

Por ejemplo, me gustaría que css y html se autocompleten de la lista de clases css en FontAwesome .

Respuestas:


22

La finalización del diccionario sería una solución barata y no intrusiva:

  1. guarde fontawesome.txt en algún lugar de su máquina,

  2. pon esto en after/ftplugin/css.vim(crea el archivo si no existe):

    setlocal complete+=k
    setlocal dictionary+=/path/to/fontawesome.txt
    setlocal iskeyword+=-
    
  3. iniciar una nueva sesión o hacerlo :een un búfer CSS para forzar el archivo anterior

  4. presione <C-n>o <C-p>en modo de inserción,

  5. ¡disfrutar!

    finalización del diccionario

Referencia:

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

17

EDITAR Gracias al comentario de romainl, he editado mi respuesta para mostrar cómo crear una función de finalización definida por el usuario. En la versión anterior, estaba anulando el omni-finalización incorporado que no era bueno porque el usuario habría perdido la finalización predeterminada que es bastante poderosa.


Una solución vimscript

Una solución es usar vimscript y el hecho de que vim le permite crear una función de finalización personalizada.

La ventaja de esta solución es que no necesita un complemento adicional, simplemente puede crear una función de finalización definida por el usuario y usar la función de finalización incorporada.

Usaré tu ejemplo de las clases fontAwesome en cssarchivos:

Cree el archivo ~/.vim/autoload/csscomplete.vimy ponga las siguientes líneas en él:

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

Luego cree el archivo ~/.vim/after/ftplugin/css.vimy ponga en él la siguiente línea:

setlocal completefunc=csscomplete#CompleteFA

Luego puede activar su función de finalización definida por el usuario con <C-x><C-u>. Intentará encontrar una coincidencia con la última palabra escrita.

En la captura de pantalla, escribí .fa-ly luego activé la función con <C-x><C-u>:

ingrese la descripción de la imagen aquí


¿Como funciona?

Primero, aquí hay algunos temas de documentación relevantes:

Si desea crear una finalización personalizada para un tipo de archivo en particular, debe colocarla en el archivo $HOME/.vim/autoload/{FILETYPE}complete.vim.

Luego, en este archivo, debe crear su función de finalización, que se llama dos veces:

  • En la primera llamada, su primer argumento es la posición actual del cursor y la función determinará la palabra a completar. En mi función, utilicé 3 comparaciones para completar la palabra porque la clase puede estar compuesta de letras .y - (creo que es posible mejorar esta coincidencia, pero estoy muy mal con la expresión regular)

  • En la segunda llamada, el segundo argumento es la palabra que debe coincidir y luego la función la compara con la lista de posibles clases para que coincida con 1 . Aquí puede ver que devuelvo un diccionario que completará el menú de finalización, pero cuando lea la documentación verá que puede crear un diccionario mucho más complejo para personalizar aún más el comportamiento de su función.

También debe decirle a Vim "para este tipo de archivo, use esta función completa que creé". Para hacerlo, debe establecer completefuncel nombre de la función que creó (aquí csscomplete#CompleteFA) y esta configuración debe realizarse en el archivo $HOME/.vim/after/ftplugin/{FILETYPE}.vim.

1 En mi función, la variable s:matchescontiene todas las coincidencias posibles. Aquí solo pongo algunas sugerencias de legibilidad, pero puedes poner todas las clases ofrecidas por FontAwesome (Puedes encontrar la lista completa en este archivo creado por romainl).


¿Qué pasa si no me gusta Vimscript?

Una posibilidad es usar el complemento YoucompleteMe que ofrece una API para jugar con el menú de finalización. Puede crear la función de Python que hará el trabajo correspondiente y utilizará la API para completar la interfaz de Vim. Más detalles aquí .


2
La finalización omni predeterminada para CSS y HTML ya es bastante útil y solo puede tener una a la vez, por lo que sugeriría usar en su lugar "finalización definida por el usuario". Ver :help i_ctrl-x_ctrl-u.
romainl

@romainl: Tienes toda la razón, veré cómo adaptar mi respuesta.
statox

5

A veces, desea un autocompletado personalizado que no interfiera con ninguno de los autocompletados integrados o definidos por el usuario. Esto es especialmente útil para scripts o complementos que están destinados a funcionar para una amplia gama de tipos de archivos.

Esto se puede hacer bastante fácil con la complete() función y un contenedor simple; la mayor parte del procedimiento es el mismo que se describe en :help complete-functions la respuesta de Statox, excepto que necesita definir sus propias asignaciones y debe llamarse a complete()sí mismo en lugar de devolver un valor.

Aquí hay un ejemplo básico, los comentarios deben explicar cómo 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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.