Kendi otomatik tamamlama işlevimi nasıl oluşturabilirim?


22

Belirli dosya türleri için kendi otomatik tamamlama listemi nasıl oluştururum?

Örneğin, FontAwesome css sınıfları listesinden otomatik tamamlama css ve html istiyorum .

Yanıtlar:


22

Sözlüğü tamamlamak ucuz ve müdahaleci olmayan bir çözüm olacaktır:

  1. kaydetmek fontawesome.txt makinenizde bir yere,

  2. bunu içine koy after/ftplugin/css.vim(eğer yoksa dosyayı oluştur):

    setlocal complete+=k
    setlocal dictionary+=/path/to/fontawesome.txt
    setlocal iskeyword+=-
    
  3. :eyukarıdaki dosyayı zorla kaynaklamak için yeni bir oturum başlatın veya bir CSS arabelleğinde yapın,

  4. basın <C-n>veya <C-p>ekleme modunda,

  5. keyfini çıkarın!

    sözlük tamamlama

Referans:

:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'

17

EDIT romainl'in yorumu sayesinde, kullanıcı tanımlı bir tamamlama işlevinin nasıl oluşturulacağını göstermek için cevabımı düzenledim. Önceki sürümde, bu çok iyi olmayan buil-in omni-tamamlamayı geçersiz kılıyordum çünkü kullanıcı oldukça güçlü olan varsayılan tamamlamayı kaybederdi.


Vimscript çözümü

Bir çözüm vimscript ve vim'in size özel bir tamamlama işlevi oluşturmanıza izin vermesidir.

Bu çözümün avantajı, ek bir eklentiye ihtiyacınız olmamasıdır, sadece kullanıcı tanımlı bir tamamlama işlevi oluşturabilir ve yerleşik tamamlama özelliğini kullanabilirsiniz.

FontAwesome sınıfları örneğini cssdosyalarda kullanacağım :

Dosyayı oluşturun ~/.vim/autoload/csscomplete.vimve içine aşağıdaki satırları yerleştirin:

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

Sonra dosyayı oluşturun ve ~/.vim/after/ftplugin/css.vimaşağıdaki satırı ekleyin:

setlocal completefunc=csscomplete#CompleteFA

Ardından, kullanıcı tanımlı tamamlama işlevinizi ile tetikleyebilirsiniz <C-x><C-u>. Son yazılan kelimeye bir eşleşme bulmaya çalışacaktır.

Ekran görüntüsünde .fa-lfonksiyonu yazdım ve tetikledim <C-x><C-u>:

resim açıklamasını buraya girin


O nasıl çalışır?

İlk olarak, ilgili bazı dokümantasyon konuları şunlardır:

Belirli bir dosya türü için özel bir tamamlama oluşturmak istiyorsanız, dosyayı dosyaya koymanız gerekir $HOME/.vim/autoload/{FILETYPE}complete.vim.

Daha sonra bu dosyada iki kez çağrılan tamamlama işlevinizi oluşturmanız gerekir:

  • İlk çağrıda ilk argümanı imlecin geçerli konumudur ve fonksiyon tamamlanacak kelimeyi belirler. Fonksiyonumda, kelimeyi tamamlamak için 3 karşılaştırma kullandım çünkü sınıf harflerden oluşabilir .ve - (bu eşleştirmeyi iyileştirmenin mümkün olduğunu düşünüyorum ama normal ifade ile gerçekten kötüyüm)

  • İkinci görüşmesinde İkinci argüman maç için sözcüktür ve ardından fonksiyon maç için olası sınıfların listeyle karşılaştırır 1 . Burada, tamamlama menüsünü dolduracak bir sözlük döndürdüğümü görüyorsunuz, ancak belgeleri okuduğunuzda, işlevinizin davranışını daha da özelleştirmek için çok daha karmaşık bir sözlük oluşturabileceğinizi göreceksiniz.

Ayrıca Vim'e "bu tür bir dosya için oluşturduğum bu tam işlevi kullan" demeniz gerekir. Bunu yapmak için completefuncoluşturduğunuz işlevin adını (burada csscomplete#CompleteFA) ayarlamanız gerekir ve bu ayarın dosyada yapılması gerekir $HOME/.vim/after/ftplugin/{FILETYPE}.vim.

1 İşlevimde, değişken s:matchesolası tüm eşleşmeleri içerir. Burada sadece okunabilirlik için bazı öneriler koydum, ancak FontAwesome tarafından sunulan tüm sınıfları koyabilirsiniz ( romainl tarafından oluşturulan bu dosyadaki tam listeyi bulabilirsiniz ).


Vimscript'i sevmezsem ne olur?

Bir olasılık, tamamlama menüsü ile oynamak için bir API sunan YoucompleteMe eklentisini kullanmaktır . Eşleştirme işini yapacak ve Vim arayüzünü doldurmak için API'yı kullanacak olan python işlevi oluşturabilirsiniz. Daha fazla ayrıntı burada .


2
CSS ve HTML için varsayılan omni tamamlama zaten oldukça kullanışlıdır ve bir kerede yalnızca bir tane olabilir, bunun yerine "kullanıcı tanımlı tamamlama" kullanmanızı öneririm. Bkz :help i_ctrl-x_ctrl-u.
romainl

@romainl: Kesinlikle haklısın, cevabımı nasıl uyarlayacağımı göreceğim.
statox

5

Bazen, yerleşik veya kullanıcı tanımlı otomatik tamamlamaların hiçbirini etkilemeyen özel bir otomatik tamamlama isteyebilirsiniz. Bu, özellikle çok çeşitli dosya türlerinde çalışması amaçlanan komut dosyaları veya eklentiler için kullanışlıdır.

Bu complete() işlev ve basit bir sargı ile oldukça kolay yapılabilir ; prosedürün çoğu, :help complete-functions kendi eşlemelerinizi tanımlamanız ve complete()bir değer döndürmek yerine kendinizi çağırmanız gerekmesi dışında Statox'un cevabı ile aynıdır .

İşte temel bir örnek, yorumlar nasıl çalıştığını açıklamalıdır.

" 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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.