Come faccio a creare il mio elenco di completamento automatico per determinati tipi di file?
Ad esempio, vorrei che CSS e HTML completassero automaticamente dall'elenco delle classi CSS in FontAwesome .
Come faccio a creare il mio elenco di completamento automatico per determinati tipi di file?
Ad esempio, vorrei che CSS e HTML completassero automaticamente dall'elenco delle classi CSS in FontAwesome .
Risposte:
Il completamento del dizionario sarebbe una soluzione economica e non intrusiva:
salva fontawesome.txt da qualche parte sul tuo computer,
inseriscilo after/ftplugin/css.vim
(crea il file se non esiste):
setlocal complete+=k
setlocal dictionary+=/path/to/fontawesome.txt
setlocal iskeyword+=-
avviare una nuova sessione o eseguirla :e
in un buffer CSS per eseguire forzatamente l'origine del file sopra,
premere <C-n>
o <C-p>
in modalità inserimento,
godere!
Riferimento:
:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'
MODIFICA Grazie al commento di Romainl ho modificato la mia risposta per mostrare come creare una funzione di completamento definita dall'utente. Nella versione precedente stavo scavalcando l'omni-completamento integrato che non era buono perché l'utente avrebbe perso il completamento predefinito che è piuttosto potente.
Una soluzione vimscript
Una soluzione è usare vimscript e il fatto che vim ti permetta di creare una funzione di completamento personalizzata.
Il vantaggio di questa soluzione è che non hai bisogno di un plug-in aggiuntivo, puoi semplicemente creare una funzione di completamento definita dall'utente e utilizzare la funzione di completamento integrata.
Userò il tuo esempio delle classi fontAwesome nei css
file:
Crea il file ~/.vim/autoload/csscomplete.vim
e inserisci le seguenti righe:
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
Quindi creare il file ~/.vim/after/ftplugin/css.vim
e inserirvi la seguente riga:
setlocal completefunc=csscomplete#CompleteFA
Quindi è possibile attivare la funzione di completamento definita dall'utente con <C-x><C-u>
. Tenterà di trovare una corrispondenza con l'ultima parola digitata.
Nello screenshot ho digitato .fa-l
e quindi attivato la funzione con <C-x><C-u>
:
Come funziona?
Innanzitutto ecco alcuni argomenti di documentazione rilevanti:
Un'ottima risposta sull'organizzazione dei file.
Se si desidera creare un completamento personalizzato per un particolare tipo di file, è necessario inserirlo nel file $HOME/.vim/autoload/{FILETYPE}complete.vim
.
Quindi in questo file devi creare la tua funzione di completamento che si chiama due volte:
Alla prima chiamata il suo primo argomento è la posizione corrente del cursore e la funzione determinerà la parola da completare. Nella mia funzione ho usato 3 confronti per ottenere il completamento della parola perché la classe può essere composta da lettere .
e -
(penso che sia possibile migliorare questa corrispondenza ma sto davvero male con regex)
Alla seconda chiamata il secondo argomento è la parola da abbinare e quindi la funzione la confronta con l'elenco di possibili classi da abbinare a 1 . Qui vedi che restituisco un dizionario che popolerà il menu di completamento, ma quando leggerai la documentazione vedrai che puoi creare un dizionario molto più complesso per personalizzare ancora di più il comportamento della tua funzione.
Devi anche dire a Vim "per questo tipo di file, usa questa funzione completa che ho creato". Per fare ciò devi impostare completefunc
il nome della funzione che hai creato (qui csscomplete#CompleteFA
) e questa impostazione deve essere fatta nel file $HOME/.vim/after/ftplugin/{FILETYPE}.vim
.
1 Nella mia funzione la variabile s:matches
contiene tutte le possibili corrispondenze. Qui metto solo alcuni suggerimenti per la leggibilità, ma puoi mettere tutte le classi offerte da FontAwesome (puoi trovare l'elenco completo in questo file creato da romainl).
Cosa succede se non mi piace Vimscript?
Una possibilità è utilizzare il plug-in YoucompleteMe che offre un'API per giocare con il menu di completamento. Puoi creare una funzione Python che farà il lavoro corrispondente e utilizzerà l'API per popolare l'interfaccia di Vim. Maggiori dettagli qui .
A volte desideri un completamento automatico personalizzato che non interferisca con nessuno dei completamenti automatici predefiniti o definiti dall'utente. Ciò è particolarmente utile per script o plugin che funzionano con un'ampia gamma di tipi di file.
Questo può essere fatto abbastanza facilmente con la
complete()
funzione e un semplice wrapper; la maggior parte della procedura è la stessa descritta nella
:help complete-functions
risposta di Statox, tranne per il fatto che è necessario definire i propri mapping e chiamare complete()
se stessi invece di restituire un valore.
Ecco un esempio di base, i commenti dovrebbero spiegare come funziona.
" 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
:help i_ctrl-x_ctrl-u
.