Comment créer ma propre liste de saisie semi-automatique pour certains types de fichiers?
Par exemple, je voudrais que css et html se complètent automatiquement à partir de la liste des classes css dans FontAwesome .
Comment créer ma propre liste de saisie semi-automatique pour certains types de fichiers?
Par exemple, je voudrais que css et html se complètent automatiquement à partir de la liste des classes css dans FontAwesome .
Réponses:
L'achèvement du dictionnaire serait une solution peu coûteuse et non intrusive:
enregistrez fontawesome.txt quelque part sur votre machine,
mettez-le after/ftplugin/css.vim
(créez le fichier s'il n'existe pas):
setlocal complete+=k
setlocal dictionary+=/path/to/fontawesome.txt
setlocal iskeyword+=-
démarrer une nouvelle session ou faire :e
dans un tampon CSS pour forcer la source du fichier ci-dessus,
appuyez sur <C-n>
ou <C-p>
en mode insertion,
prendre plaisir!
Référence:
:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'
EDIT Merci au commentaire de romainl J'ai modifié ma réponse à montrer comment créer une fonction d'achèvement définie par l' utilisateur. Dans la version précédente, je remplaçais l'omni-complétion intégrée, ce qui n'était pas bon car l'utilisateur aurait perdu la complétion par défaut qui est assez puissante.
Une solution vimscript
Une solution consiste à utiliser vimscript et le fait que vim vous permet de créer une fonction de complétion personnalisée.
L'avantage de cette solution est que vous n'avez pas besoin d'un plugin supplémentaire, vous pouvez simplement créer une fonction d'achèvement définie par l'utilisateur et utiliser la fonction d'achèvement intégrée.
Je vais utiliser votre exemple des classes fontAwesome dans les css
fichiers:
Créez le fichier ~/.vim/autoload/csscomplete.vim
et insérez-y les lignes suivantes:
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
Créez ensuite le fichier ~/.vim/after/ftplugin/css.vim
et insérez-y la ligne suivante:
setlocal completefunc=csscomplete#CompleteFA
Ensuite, vous pouvez déclencher votre fonction d'achèvement définie par l'utilisateur avec <C-x><C-u>
. Il essaiera de trouver une correspondance avec le dernier mot tapé.
Dans la capture d'écran, j'ai tapé .fa-l
puis déclenché la fonction avec <C-x><C-u>
:
Comment ça marche?
Voici d'abord quelques sujets de documentation pertinents:
Une excellente réponse sur l'organisation des fichiers.
Si vous souhaitez créer une complétion personnalisée pour un type de fichier particulier, vous devez le mettre dans le fichier $HOME/.vim/autoload/{FILETYPE}complete.vim
.
Ensuite, dans ce fichier, vous devez créer votre fonction d'achèvement qui est appelée deux fois:
Au premier appel, son premier argument est la position actuelle du curseur et la fonction déterminera le mot à terminer. Dans ma fonction, j'ai utilisé 3 comparaisons pour terminer le mot parce que la classe peut être composée de lettres, .
et -
(je pense qu'il est possible d'améliorer cette correspondance mais je suis vraiment mauvais avec regex)
Au deuxième appel, le deuxième argument est le mot à faire correspondre, puis la fonction le compare à la liste des classes possibles pour correspondre à 1 . Ici, vous voyez que je retourne un dictionnaire qui remplira le menu d'achèvement, mais quand vous lirez la documentation, vous verrez que vous pouvez créer un dictionnaire beaucoup plus complexe pour personnaliser encore plus le comportement de votre fonction.
Vous devez également dire à Vim "pour ce type de fichier, utilisez cette fonction complète que j'ai créée". Pour ce faire, vous devez définir completefunc
le nom de la fonction que vous avez créée (ici csscomplete#CompleteFA
) et ce paramètre doit être effectué dans le fichier $HOME/.vim/after/ftplugin/{FILETYPE}.vim
.
1 Dans ma fonction, la variable s:matches
contient toutes les correspondances possibles. Ici je ne mets que quelques suggestions de lisibilité mais vous pouvez mettre toutes les classes proposées par FontAwesome (Vous pouvez trouver la liste complète dans ce fichier créé par romainl).
Et si je n'aime pas Vimscript?
Une possibilité est d'utiliser le plugin YoucompleteMe qui propose une API pour jouer avec le menu de complétion. Vous pouvez créer une fonction python qui fera le travail de correspondance et utilisera l'API pour remplir l'interface Vim. Plus de détails ici .
Parfois, vous voulez une auto-complétion personnalisée qui n'interfère pas du tout avec les auto-complétion intégrées ou définies par l'utilisateur. Ceci est particulièrement utile pour les scripts ou plugins qui sont destinés à fonctionner pour un large éventail de types de fichiers.
Cela peut être fait assez facilement avec la
complete()
fonction et un simple wrapper; la plupart de la procédure est la même que celle décrite dans
:help complete-functions
la réponse de Statox, sauf que vous devez définir vos propres mappages et devez complete()
vous appeler au lieu de renvoyer une valeur.
Voici un exemple de base, les commentaires devraient expliquer comment cela fonctionne.
" 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
.