Як створити власний список автоматичного заповнення для певних файлів?
Наприклад, я хотів би, щоб css і html автозаповнювалися зі списку класів css у FontAwesome .
Як створити власний список автоматичного заповнення для певних файлів?
Наприклад, я хотів би, щоб css і html автозаповнювалися зі списку класів css у FontAwesome .
Відповіді:
Завершення словника буде дешевим і не нав'язливим рішенням:
збережіть fontawesome.txt десь на вашій машині,
поставте це after/ftplugin/css.vim
(створіть файл, якщо його не існує):
setlocal complete+=k
setlocal dictionary+=/path/to/fontawesome.txt
setlocal iskeyword+=-
запустити новий сеанс або зробити :e
в буфері CSS, щоб насильно джерело файлу,
натисніть <C-n>
або <C-p>
в режимі вставки,
насолоджуйтесь!
Довідка:
:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'
EDIT Завдяки коментарю romainl я відредагував свою відповідь, щоб показати, як створити визначену користувачем функцію завершення. У попередній версії я переосмислив вбудований омні-завершення, що було не дуже добре, оскільки користувач втратив би завершення за замовчуванням, яке досить потужне.
Вимскриптове рішення
Одне рішення - використовувати vimscript і те, що vim дозволить вам створити налаштовану функцію завершення.
Перевага цього рішення полягає в тому, що вам не потрібен додатковий плагін, ви можете просто створити визначену користувачем функцію завершення та використовувати вбудовану функцію завершення.
Я буду використовувати ваш приклад класів fontAwesome у css
файлах:
Створіть файл ~/.vim/autoload/csscomplete.vim
і помістіть у нього наступні рядки:
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
Потім створіть файл ~/.vim/after/ftplugin/css.vim
і вставте в нього такий рядок:
setlocal completefunc=csscomplete#CompleteFA
Тоді ви можете запустити функцію завершення, визначену користувачем <C-x><C-u>
. Він спробує знайти відповідність останньому набраному слову.
На скріншоті я набрав, .fa-l
а потім запустив функцію за допомогою <C-x><C-u>
:
Як це працює?
Спочатку наведено декілька відповідних тем документації:
Прекрасна відповідь про організацію файлів.
Якщо ви хочете створити спеціальне завершення для певного типу файлів, ви повинні помістити його у файл $HOME/.vim/autoload/{FILETYPE}complete.vim
.
Потім у цьому файлі ви повинні створити функцію завершення, яка викликається двічі:
При першому виклику його першим аргументом є поточне положення курсору, і функція визначатиме слово, яке потрібно виконати. У своїй функції я використав 3 порівняння для того, щоб довести слово до кінця, тому що клас може складатися з літер, .
і -
(я думаю, що можна покращити цю відповідність, але я дуже поганий з регулярним виразом)
Під час другого виклику другим аргументом є слово, яке відповідає, а потім функція порівнює його зі списком можливих класів, які відповідають 1 . Тут ви бачите, що я повертаю словник, який заповнить меню завершення, але коли ви прочитаєте документацію, ви побачите, що ви можете створити набагато складніший словник, щоб ще більше налаштувати поведінку вашої функції.
Ви також повинні сказати Vim "для цього типу файлів, використовуйте цю повну функцію, яку я створив". Для цього вам потрібно встановити completefunc
ім'я створеної вами функції (тут csscomplete#CompleteFA
), і це налаштування потрібно виконати у файлі $HOME/.vim/after/ftplugin/{FILETYPE}.vim
.
1 У моїй функції змінна s:matches
містить усі можливі збіги. Тут я вкладаю лише кілька пропозицій щодо читабельності, але ви можете розмістити всі класи, запропоновані FontAwesome (Повний список ви можете знайти в цьому файлі, створеному romainl).
Що робити, якщо мені не подобається Vimscript?
Однією з можливостей є використання плагіна YoucompleteMe, який пропонує API для відтворення з меню завершення. Ви можете створити функцію python, яка буде виконувати відповідні завдання та використовуватиме API для заповнення інтерфейсу Vim. Детальніше тут .
Іноді потрібно налаштувати власне автоматичне завершення, яке взагалі не заважає вбудованому або визначеному користувачем автозавершенням. Це особливо корисно для сценаріїв або плагінів, які призначені для роботи для широкого спектру файлів.
Це можна зробити досить легко за допомогою
complete()
функції та простої обгортки; більшість процедур є такими ж, як описано у
:help complete-functions
відповіді Статокса, за винятком того, що вам потрібно визначити власні відображення та зателефонувати complete()
собі, а не повертати значення.
Ось основний приклад, коментарі повинні пояснити, як це працює.
" 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
.