Wie erstelle ich meine eigene Autovervollständigungsfunktion?

22

Wie erstelle ich meine eigene Liste der automatischen Vervollständigung für bestimmte Dateitypen?

Zum Beispiel möchte ich, dass CSS und HTML automatisch aus der Liste der CSS-Klassen in FontAwesome vervollständigt werden .

firedev
quelle

Antworten:

22

Die Vervollständigung des Wörterbuchs wäre eine kostengünstige und nicht aufdringliche Lösung:

  1. speichere fontawesome.txt irgendwo auf deinem Rechner,

  2. Setze dies ein after/ftplugin/css.vim(erstelle die Datei, wenn sie nicht existiert):

    setlocal complete+=k
    setlocal dictionary+=/path/to/fontawesome.txt
    setlocal iskeyword+=-
    
  3. Starten Sie eine neue Sitzung oder verwenden Sie :eeinen CSS-Puffer, um die obige Datei zwangsweise als Quelle zu verwenden.

  4. Drücken Sie <C-n>oder <C-p>im Einfügemodus.

  5. genießen!

    Vervollständigung des Wörterbuchs

Referenz:

:help ins-completion
:help 'complete'
:help 'dictionary'
:help 'iskeyword'
romainl
quelle
17

EDIT Dank romainl Kommentar Ich habe meine Antwort bearbeitet zu zeigen , wie eine benutzerdefinierte Vervollständigungsfunktion zu erstellen. In der vorherigen Version habe ich die eingebaute Omni-Vervollständigung überschrieben, was nicht gut war, da der Benutzer die Standard-Vervollständigung verloren hätte, die ziemlich mächtig ist.


Eine Vimscript-Lösung

Eine Lösung ist die Verwendung von Vimscript und die Tatsache, dass Sie mit Vim eine benutzerdefinierte Vervollständigungsfunktion erstellen können.

Der Vorteil dieser Lösung ist, dass Sie kein zusätzliches Plugin benötigen. Sie können einfach eine benutzerdefinierte Vervollständigungsfunktion erstellen und die integrierte Vervollständigungsfunktion verwenden.

Ich werde Ihr Beispiel der fontAwesome-Klassen in cssDateien verwenden:

Erstellen Sie die Datei ~/.vim/autoload/csscomplete.vimund fügen Sie die folgenden Zeilen ein:

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

Dann erstelle die Datei ~/.vim/after/ftplugin/css.vimund füge die folgende Zeile ein:

setlocal completefunc=csscomplete#CompleteFA

Dann können Sie mit Ihre benutzerdefinierte Vervollständigungsfunktion auslösen <C-x><C-u>. Es wird versucht, eine Übereinstimmung mit dem zuletzt eingegebenen Wort zu finden.

Im Screenshot habe ich getippt .fa-lund dann die Funktion ausgelöst mit <C-x><C-u>:

Bildbeschreibung hier eingeben


Wie funktioniert es?

Hier sind zunächst einige relevante Dokumentationsthemen:

Wenn Sie eine benutzerdefinierte Vervollständigung für einen bestimmten Dateityp erstellen möchten, müssen Sie diese in die Datei einfügen $HOME/.vim/autoload/{FILETYPE}complete.vim.

Dann müssen Sie in dieser Datei Ihre Vervollständigungsfunktion erstellen, die zweimal aufgerufen wird:

  • Beim ersten Aufruf ist das erste Argument die aktuelle Position des Cursors und die Funktion bestimmt das zu vervollständigende Wort. In meiner Funktion I 3 Vergleiche das Wort vollständig zu erhalten , weil die Klasse kann aus Buchstaben besteht, .und - (ich glaube , es ist möglich , diese Anpassung zu verbessern , aber ich bin wirklich schlecht mit regex)

  • Beim zweiten Aufruf ist das zweite Argument das zu vergleichende Wort, und die Funktion vergleicht es mit der Liste der möglichen Klassen, die mit 1 übereinstimmen . Hier sehen Sie , dass ich ein Wörterbuch zurück , die den Abschluss Menü bevölkern, aber wenn Sie die Dokumentation lesen werde sehen Sie , dass Sie ein viel komplexeres Wörterbuch erstellen anpassen noch das Verhalten Ihrer Funktion.

Sie müssen Vim auch mitteilen, dass für diese Art von Datei die von mir erstellte vollständige Funktion verwendet werden soll. Dazu müssen Sie completefuncden Namen der von Ihnen erstellten Funktion (hier csscomplete#CompleteFA) angeben und diese Einstellung in der Datei vornehmen $HOME/.vim/after/ftplugin/{FILETYPE}.vim.

1 In meiner Funktion s:matchesenthält die Variable alle möglichen Übereinstimmungen. Hier habe ich nur einige Vorschläge für die Lesbarkeit, aber Sie können alle von FontAwesome angebotenen Klassen einfügen (Sie finden die vollständige Liste in dieser von romainl erstellten Datei).


Was ist, wenn ich Vimscript nicht mag?

Eine Möglichkeit besteht darin, das Plugin YoucompleteMe zu verwenden, das eine API zum Spielen mit dem Vervollständigungsmenü bietet. Sie können eine Python-Funktion erstellen, die den passenden Job ausführt und die API verwendet, um die Vim-Oberfläche zu füllen. Weitere Details hier .

statox
quelle
2
Die standardmäßige Omni-Vervollständigung für CSS und HTML ist bereits sehr nützlich, und Sie können jeweils nur eine verwenden. Ich würde daher vorschlagen, stattdessen die benutzerdefinierte Vervollständigung zu verwenden. Sehen :help i_ctrl-x_ctrl-u.
Romainl
@romainl: Du hast vollkommen recht, ich werde sehen, wie ich meine Antwort anpasse.
statox
5

Manchmal möchten Sie eine benutzerdefinierte automatische Vervollständigung, die die integrierten oder benutzerdefinierten automatischen Vervollständigungen überhaupt nicht beeinträchtigt. Dies ist besonders nützlich für Skripte oder Plugins, die für eine Vielzahl von Dateitypen geeignet sind.

Dies kann mit der complete() Funktion und einem einfachen Wrapper relativ einfach durchgeführt werden . Der größte Teil der Prozedur ist derselbe wie in :help complete-functions und Statoxs Antwort beschrieben, außer dass Sie Ihre eigenen Zuordnungen definieren und sich complete()selbst aufrufen müssen, anstatt einen Wert zurückzugeben.

Hier ist ein einfaches Beispiel, die Kommentare sollten erklären, wie es funktioniert.

" 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", "[email protected]"],
        \ ["Eek the Cat", "[email protected]"]
    \ ]

    " 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
Martin Tournoij
quelle