Как создать собственный список автозаполнения для определенных типов файлов?
Например, я хотел бы, чтобы 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'
РЕДАКТИРОВАТЬ Благодаря комментарию romainl я отредактировал свой ответ, чтобы показать, как создать пользовательскую функцию завершения. В предыдущей версии я переопределял встроенное омни-завершение, что было не очень хорошо, потому что пользователь потерял бы завершение по умолчанию, которое является довольно мощным.
Vimscript решение
Одним из решений является использование 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
ответе Statox, за исключением того, что вам нужно определить свои собственные сопоставления и вызывать 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
.