Как создать собственную функцию автозаполнения?

Ответы:

22

Завершение словаря было бы дешевым и ненавязчивым решением:

  1. сохраните fontawesome.txt где-нибудь на своей машине,

  2. вставьте это after/ftplugin/css.vim(создайте файл, если он не существует):

    setlocal complete+=k
    setlocal dictionary+=/path/to/fontawesome.txt
    setlocal iskeyword+=-
    
  3. начать новый сеанс или сделать :eв буфере CSS, чтобы принудительно получить файл выше,

  4. нажмите <C-n>или <C-p>в режиме вставки,

  5. наслаждаться!

    завершение словаря

Ссылка:

:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'
romainl
источник
17

РЕДАКТИРОВАТЬ Благодаря комментарию 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. Подробнее здесь .

statox
источник
2
Омни-завершение по умолчанию для CSS и HTML уже весьма полезно, и вы можете иметь только одно по одному, поэтому я бы предложил использовать вместо этого «определяемое пользователем завершение». См :help i_ctrl-x_ctrl-u.
Ромен
@romainl: Вы абсолютно правы, я посмотрю, как адаптировать свой ответ.
statox
5

Иногда вам нужно пользовательское автозаполнение, которое вообще не мешает ни одному из встроенных или определенных пользователем автозаполнений. Это особенно полезно для скриптов или плагинов, которые предназначены для работы с широким диапазоном типов файлов.

Это можно сделать довольно легко с помощью 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
Мартин Турной
источник