Jak utworzyć własną listę autouzupełniania dla niektórych typów plików?
Na przykład chciałbym, aby css i html uzupełniały się automatycznie z listy klas css w FontAwesome .
Jak utworzyć własną listę autouzupełniania dla niektórych typów plików?
Na przykład chciałbym, aby css i html uzupełniały się automatycznie z listy klas css w FontAwesome .
Odpowiedzi:
Uzupełnianie słownika byłoby tanim i nieinwazyjnym rozwiązaniem:
zapisz fontawesome.txt gdzieś na swoim komputerze,
wstaw to after/ftplugin/css.vim
(utwórz plik, jeśli nie istnieje):
setlocal complete+=k
setlocal dictionary+=/path/to/fontawesome.txt
setlocal iskeyword+=-
rozpocznij nową sesję lub zrób :e
w buforze CSS, aby wymusić źródło pliku powyżej,
naciśnij <C-n>
lub <C-p>
w trybie wstawiania,
cieszyć się!
Odniesienie:
:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'
EDYCJA Dzięki komentarzowi romainla zredagowałem swoją odpowiedź, aby pokazać, jak utworzyć funkcję uzupełniania zdefiniowaną przez użytkownika. W poprzedniej wersji zastępowałem wbudowane omni-uzupełnianie, co nie było dobre, ponieważ użytkownik straciłby domyślne uzupełnienie, które jest dość potężne.
Rozwiązanie vimscript
Jednym z rozwiązań jest użycie vimscript i fakt, że vim pozwala ci stworzyć niestandardową funkcję uzupełniania.
Zaletą tego rozwiązania jest to, że nie potrzebujesz dodatkowej wtyczki, możesz po prostu utworzyć funkcję uzupełniania zdefiniowaną przez użytkownika i użyć wbudowanej funkcji uzupełniania.
Wykorzystam twój przykład klas fontAwesome w css
plikach:
Utwórz plik ~/.vim/autoload/csscomplete.vim
i umieść w nim następujące linie:
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
Następnie utwórz plik ~/.vim/after/ftplugin/css.vim
i umieść w nim następujący wiersz:
setlocal completefunc=csscomplete#CompleteFA
Następnie możesz uruchomić funkcję uzupełniania zdefiniowaną przez użytkownika za pomocą <C-x><C-u>
. Spróbuje znaleźć dopasowanie do ostatniego wpisanego słowa.
Na zrzucie ekranu wpisałem, .fa-l
a następnie uruchomiłem funkcję za pomocą <C-x><C-u>
:
Jak to działa?
Najpierw kilka istotnych tematów dokumentacji:
Wielki odpowiedź o organizacji plików.
Jeśli chcesz utworzyć niestandardowe uzupełnienie dla określonego rodzaju pliku, musisz umieścić go w pliku $HOME/.vim/autoload/{FILETYPE}complete.vim
.
Następnie w tym pliku musisz utworzyć funkcję uzupełniania, która jest wywoływana dwukrotnie:
Przy pierwszym wywołaniu jego pierwszym argumentem jest bieżąca pozycja kursora, a funkcja określi słowo do uzupełnienia. W mojej funkcji użyłem 3 porównań, aby uzupełnić słowo, ponieważ klasa może składać się z liter, .
i -
(myślę, że można poprawić to dopasowanie, ale naprawdę źle rozumiem wyrażenie regularne)
Przy drugim wywołaniu drugim argumentem jest słowo do dopasowania, a następnie funkcja porównuje je z listą możliwych klas do dopasowania 1 . Tutaj widzisz, że zwracam słownik, który zapełni menu uzupełniające, ale kiedy przeczytasz dokumentację, zobaczysz, że możesz stworzyć znacznie bardziej złożony słownik, aby jeszcze bardziej dostosować zachowanie twojej funkcji.
Musisz także powiedzieć Vimowi „dla tego rodzaju pliku, użyj tej pełnej funkcji, którą stworzyłem”. Aby to zrobić, musisz ustawić completefunc
nazwę utworzonej funkcji (tutaj csscomplete#CompleteFA
) i to ustawienie musi zostać wykonane w pliku $HOME/.vim/after/ftplugin/{FILETYPE}.vim
.
1 W mojej funkcji zmienna s:matches
zawiera wszystkie możliwe dopasowania. Tutaj zamieszczam tylko kilka sugestii dotyczących czytelności, ale możesz umieścić wszystkie klasy oferowane przez FontAwesome (pełną listę można znaleźć w tym pliku utworzonym przez romainl).
Co jeśli nie podoba mi się Vimscript?
Jedną z możliwości jest użycie wtyczki YoucompleteMe, która oferuje API do zabawy z menu ukończenia. Możesz utworzyć funkcję python, która wykona pasujące zadanie i użyje interfejsu API do zapełnienia interfejsu Vima. Więcej informacji tutaj .
Czasami potrzebujesz niestandardowego autouzupełniania, które nie koliduje z żadnymi wbudowanymi lub zdefiniowanymi przez użytkownika autouzupełnianiami. Jest to szczególnie przydatne w przypadku skryptów lub wtyczek przeznaczonych do pracy z szeroką gamą typów plików.
Można to zrobić dość łatwo za pomocą
complete()
funkcji i prostego opakowania; większość procedur jest taka sama, jak opisano w
:help complete-functions
odpowiedzi Statox, z wyjątkiem tego, że musisz zdefiniować własne odwzorowania i musisz wywołać complete()
siebie zamiast zwracać wartość.
Oto podstawowy przykład, w komentarzach należy wyjaśnić, jak to działa.
" 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
.