Wer in Vim LaTeX schreibt, hat Vim nicht wegen LaTeX gewählt. Man wohnt bereits in Vim oder Neovim und möchte, dass LaTeX zu einem kommt. Ein nacktes Vim weiß durchaus, was eine .tex-Datei ist – es bringt eine Syntaxdatei und ein Filetype-Plugin mit –, doch im Kopf dieses Plugins, ftplugin/tex.vim, steht bis heute Last Change: Wed 19 Apr 2006. Kein Bauen, keine PDF-Anzeige, keine \ref-Vervollständigung, keine Liste der Abschnitte. All das kommt erst mit vimtex, dem Plugin von Karl Yngve Lervåg. Diese Seite behandelt, was vimtex gegenüber einem nackten Vim hinzufügt, die dauerhaft laufende latexmk-Kompilierung hinter \ll, die Textobjekte, mit denen sich Umgebungen und Befehle in Vims eigener Grammatik bearbeiten lassen, und die Stellen, an denen sich Vim und Neovim wirklich unterscheiden.
Was ein nacktes Vim über LaTeX weiß
Was ein nacktes Vim über eine .tex-Datei weiß, sind Farben und drei kleine Kunstgriffe: [d springt zur Definition eines \newcommand oder \def, gf und [i lesen den Inhalt von \include{...} als Dateinamen, und mit aktiviertem matchit springt % zwischen \begin{...} und \end{...} hin und her. Die gesamte Umsetzung passt in rund vierzig Zeilen ftplugin/tex.vim, die das heutige Vim 9.1 unverändert mitliefert – mit Benji Fishers Namen und der Zeile Version: 1.4 / Last Change: Wed 19 Apr 2006. Die Syntaxdatei syntax/tex.vim ist immerhin bis Version 121 gewachsen, doch in ihrem Kopf steht, dass diese Runtime-Datei einen neuen Betreuer sucht.
Ein nacktes Vim bringt zudem eine Compiler-Definition mit, compiler/tex.vim. Nach :compiler tex lautet makeprg latex -interaction=nonstopmode, und errorformat erhält ein langes Muster zum Lesen von LaTeX-Logs – ein schlichtes :make füllt damit die Quickfix-Liste mit den Fehlern. Selbst ein nacktes Vim reicht also für „schreiben, :make, zur fehlerhaften Zeile springen“. Was es nicht kann: das PDF öffnen, zwischen Quelle und PDF wechseln, \ref oder \cite vervollständigen, durch die Struktur des Dokuments navigieren. All das übernimmt vimtex und ersetzt für den Dateityp tex Vims internes TeX-Plugin durch sein eigenes.
" What bare Vim gives you, without any plugin at all.
packadd! matchit " % jumps between \begin{...} and \end{...}
compiler tex " :make runs latex and fills the quickfix listWarum eine frische .tex-Datei plaintex wird und vimtex nicht lädt
Die Antwort ist schlicht: Vim rät, indem es den Inhalt der Datei liest. FTtex() in autoload/dist/ft.vim von Vim 9.1 prüft zuerst eine %&Format-Zeile ganz oben und durchsucht dann tausend Zeilen ab der ersten Nicht-Kommentarzeile nach \documentclass, \usepackage, \begin{, \newcommand oder \renewcommand. Findet sich nichts davon, greift ein Vorgabewert – und der ist, solange g:tex_flavor nicht gesetzt ist, plain. Der Dateityp lautet dann plaintex statt tex. Eine leere neue Datei oder ein Fragment ohne \documentclass ist genau dieser Fall.
Das Interessante daran: Der übliche Rat zu diesem Thema – let g:tex_flavor = 'latex' in die vimrc – wirkt mit vimtex genau andersherum. vimtex überschreibt die Dateityperkennung in seinem eigenen ftdetect/tex.vim und setzt g:tex_flavor selbst auf latex. Die Dokumentation nennt den Grund ausdrücklich: Die Überschreibung soll verhindern, dass .tex-Dateien überraschend als plaintex erkannt werden. Mit installiertem vimtex braucht man g:tex_flavor also gar nicht zu setzen. Ein anderer Wert als latex ist umgekehrt die Art, vimtex diese Übernahme zu verweigern – dafür lohnt sich die Option.
vimtex einrichten – und warum man es nicht lazy laden darf
Klar gesagt: vimtex nicht lazy laden. Der Grund ist technischer Natur, keine Geschmacksfrage. Die Rückwärtssuche – vom PDF zurück in die Quelle – hängt an :VimtexInverseSearch, einem globalen Befehl, den der Betrachter von außerhalb des Editors aufruft. Ist der Plugin-Rumpf nicht geladen, existiert dieser Befehl nicht. Hinzu kommt: vimtex ist ein Filetype-Plugin und nutzt den autoload-Mechanismus, wird also ohnehin erst bei Bedarf geladen; für einen Plugin-Manager bleibt nichts mehr zu verzögern. In lazy.nvim heißt das lazy = false, in vim-plug: keine for-Klausel.
Zwei weitere Voraussetzungen. Erstens die Editorversion. Seit vimtex 2.18 vom Juli 2026 werden Vim 9.2 oder Neovim 0.12.4 verlangt; auf älteren Versionen lädt es schlicht nicht. Wer auf einem älteren Editor festsitzt, pinnt richtigerweise das Tag v2.17; let g:vimtex_version_check = 0 bringt die Prüfung zum Schweigen. Zweitens filetype plugin on und syntax enable. Ohne das erste lädt vimtex gar nicht, ohne das zweite fällt alles aus, was auf Syntaxinformationen beruht – das Erkennen von Mathematikbereichen, das Textobjekt i$. Auch wer in Neovim auf Tree-sitter setzt, lässt Vims Syntaxfunktionen besser eingeschaltet.
call plug#begin()
Plug 'lervag/vimtex'
" Pin an older tag if you are stuck on Vim < 9.2:
" Plug 'lervag/vimtex', { 'tag': 'v2.17' }
call plug#end()
filetype plugin indent on " required (indent is optional)
syntax enable " required for math zones, i$ and friends
set encoding=utf-8 " needed in Vim, not in Neovim
let maplocalleader = ' ' " Space as <localleader>; default is backslash
let g:vimtex_view_method = 'zathura'In Neovim schreibt man dasselbe in Lua, und die Einstellungen gehören in init, damit sie greifen, bevor der Plugin-Rumpf lädt. maplocalleader ist die Tür zu fast jedem vimtex-Befehl – das Standardpräfix steckt in g:vimtex_mappings_prefix mit dem Vorgabewert <localleader>l, und <localleader> selbst ist standardmäßig ein Backslash. Es ausdrücklich zu setzen erspart späteres Rätselraten. Bleibt es beim Backslash, tippt man \ll; wird daraus Leertaste, drückt man Leertaste und dann ll.
return {
"lervag/vimtex",
lazy = false, -- never lazy-load: it breaks :VimtexInverseSearch
init = function()
vim.g.maplocalleader = " "
vim.g.vimtex_view_method = "zathura" -- "skim" on macOS
vim.g.vimtex_compiler_method = "latexmk"
end,
}\ll: latexmk bleibt im Hintergrund und das PDF folgt jedem Speichern
Einmal \ll drücken, und latexmk läuft im Dauerbetrieb; noch einmal drücken, und es hält an. Der Umschalter entsteht dadurch, dass die Standardeinstellungen in g:vimtex_compiler_latexmk continuous aktivieren, was darunter latexmks Dauerüberwachung nutzt. Von da an löst jedes Speichern einen neuen Lauf aus, und das PDF im Betrachter zieht von selbst nach. Für einen einzelnen Durchlauf gibt es \lS (:VimtexCompileSS), zum Anhalten \lk (oder \lK für alle Projekte).
| Tastenfolge | Befehl | Wirkung |
|---|---|---|
\ll | :VimtexCompile | Dauerkompilierung starten oder anhalten (Umschalter) |
\lS | :VimtexCompileSS | Einzelner Durchlauf, wie ihn auch CI ausführt |
\lv | :VimtexView | PDF öffnen und zur Cursorposition vorwärtssuchen |
\lt | :VimtexTocOpen | Inhaltsverzeichnis-Puffer öffnen (\lT schaltet um) |
\le | :VimtexErrors | Fehler und Warnungen im Quickfix-Fenster auflisten |
\lo | :VimtexCompileOutput | Die Rohausgabe des Compilers anzeigen |
\lc | :VimtexClean | Hilfsdateien aufräumen (\lC entfernt auch die Ausgabe) |
\li | :VimtexInfo | Erkannte Hauptdatei, Pakete und weiteren Zustand anzeigen |
\ls | :VimtexToggleMain | Umschalten, ob die aktuelle Datei als Hauptdatei gilt |
Standardmäßig gehen vier Optionen an latexmk: -verbose, -file-line-error, -synctex=1 und -interaction=nonstopmode. Weil -synctex=1 von Anfang an dabei ist, entstehen die für Vorwärts- und Rückwärtssuche nötigen Synchronisationsdaten ganz ohne eigenes Zutun. Für Fehler steht g:vimtex_quickfix_mode standardmäßig auf 2 – das Quickfix-Fenster öffnet sich selbst, nimmt aber nicht den Fokus –, was zum Mitlesen aus dem Augenwinkel passt. Um den Compiler selbst zu tauschen, setzt man g:vimtex_compiler_method auf latexmk (Vorgabe), latexrun, tectonic, arara, texpresso oder generic.
Wenn \ll die falsche Engine startet: -pdf gegen $pdf_mode
Man schreibt $pdf_mode = 3 in die .latexmkrc und der Bau geht trotzdem nicht über DVI. Die Ursache: vimtex hängt jedes Mal ein Engine-Flag an die Kommandozeile. Die Engine stammt aus der Zuordnungstabelle g:vimtex_compiler_latexmk_engines, deren Standardschlüssel _ auf -pdf zeigt. Ein -pdf auf der Kommandozeile sticht $pdf_mode aus der .latexmkrc, die Konfigurationsdatei wird also stillschweigend übergangen. vimtex leitet die Engine zwar aus $pdf_mode ab – laut Dokumentation aber nur für 1 (pdfLaTeX), 4 (LuaLaTeX) und 5 (XeLaTeX). Der DVI-Weg, die 3, fehlt darin.
Richtig behebt man das, indem man oben in die Hauptdatei eine TeX-Programm-Direktive schreibt. Ihre rechte Seite muss ein Schlüssel jener Tabelle sein: für LuaLaTeX also lualatex, für den DVI-Weg pdfdvi (das auf -pdfdvi abbildet). Die eigentlichen Aufrufe von upLaTeX und dvipdfmx gehören dann in die .latexmkrc – die klassische Kombination für japanische Aufsätze. Die latexmk-Konfiguration selbst gehört der Seite zu automatisierten Builds; Einzelheiten stehen dort.
% In the main .tex file, first line: pick the key, not the binary name.
% !TeX program = pdfdvi
# .latexmkrc -- upLaTeX and dvipdfmx do the actual work
$latex = 'uplatex -synctex=1 -interaction=nonstopmode -file-line-error %O %S';
$bibtex = 'upbibtex %O %B';
$biber = 'biber --bblencoding=utf8 -u -U --output_safechars %O %S';
$makeindex = 'upmendex %O -o %D %S';
$dvipdf = 'dvipdfmx %O -o %D %S';
$max_repeat = 5;Entscheidend ist, -synctex=1 auch an $latex zu übergeben: So gelangen die Synchronisationsdaten selbst über den Umweg DVI bis ins PDF. Wer latexmk verlässt, hat ein anderes Bild – der Wechsel zu Tectonic besteht nur darin, g:vimtex_compiler_method auf tectonic zu setzen, ohne Engine-Auswahl und ohne .latexmkrc.
Textobjekte: \begin{...} in Vims eigener Grammatik bearbeiten
Hier liegt der eine unersetzliche Grund, LaTeX in Vim zu schreiben. Vims Bearbeitung beruht auf einer Grammatik aus Verb plus Objekt: d (löschen) oder c (ändern) in Verbindung mit iw (innerhalb eines Wortes) oder ap (ein ganzer Absatz). vimtex fügt diesem Wortschatz die Strukturen von LaTeX selbst hinzu. dae löscht alles von \begin{...} bis \end{...}, cie ersetzt nur den Inhalt, und ci$ tippt nur das Innere einer Inline-Formel neu. Zeilen zählen, um eine dreißigzeilige align-Umgebung zu löschen, entfällt.
| Objekt | Erfasst | Typischer Einsatz |
|---|---|---|
ie / ae | Eine Umgebung (außer dem äußersten document) | dae löscht die ganze Umgebung, cie ersetzt nur den Inhalt |
i$ / a$ | Eine Mathematikumgebung ($...$, \[...\]) | ci$ tippt nur das Innere der Formel neu |
ic / ac | Ein Befehl samt Argumenten | dac entfernt ein ganzes \textbf{...} |
id / ad | Ein Paar zusammengehöriger Begrenzer | Das LaTeX-kundige ci(; erfasst auch \left(...\right) |
iP / aP | Ein Abschnitt | daP verschiebt oder löscht einen ganzen Abschnitt |
im / am | Ein einzelnes \item | Erfasst genau einen Eintrag einer Liste |
Dazu kommt ein Trio zum Umschreiben von Strukturen: ds entfernt eine Umschließung, cs ändert sie, ts schaltet sie um. dse schält eine Umgebung ab und lässt den Inhalt stehen, cse macht aus einem itemize ein enumerate (die Vervollständigung liefert die Kandidaten), dsc/csc tun dasselbe für einen Befehl, dsd/csd für einen Begrenzer. tse wechselt die Umgebung, tss schaltet ihre gesternte Form um, tsc den Stern eines Befehls, und tsd pendelt zwischen (...) und \left(...\right). Zur Bewegung springt % zwischen zusammengehörigen Paaren, ]]/[[ zum nächsten und vorigen Abschnittsanfang, ][/[] zu den Enden, ]m/[m zu Umgebungen und ]n/[n zu Formeln. Steht der Cursor auf einem Befehl, öffnet K die Dokumentation des zugehörigen Pakets.
Sich in einem langen Dokument bewegen: TOC-Puffer und \ref-Vervollständigung
Ein Druck auf \lt und das Inhaltsverzeichnis des gesamten Dokuments öffnet sich als gewöhnlicher Puffer. Weil es ein gewöhnlicher Puffer ist, lässt es sich mit / durchsuchen, mit j und k durchlaufen, und Enter springt zum Abschnitt. Auch bei einem auf mehrere Dateien verteilten Dokument folgt vimtex \input und \include ab der Hauptdatei, sodass ein einziges kapitelübergreifendes Verzeichnis entsteht. Standardmäßig erscheint es in einem fünfzig Spalten breiten Fenster; Aussehen und Verhalten regelt g:vimtex_toc_config. Ob die gerade bearbeitete Datei als Hauptdatei gilt, schaltet \ls um, und \li zeigt, welche Datei vimtex dafür hält.
Die Vervollständigung setzt auf Vims eigener Mechanik auf. In einem tex-Puffer wird omnifunc automatisch auf vimtex#complete#omnifunc gesetzt (g:vimtex_complete_enabled ist standardmäßig an), sodass Ctrl-X Ctrl-O im Einfügemodus Kandidaten liefert. Direkt nach \cite{ erscheinen Zitierschlüssel aus den .bib-Dateien und \bibitems, nach \ref{ die \labels des Dokuments, nach \usepackage{ die installierten .sty-Dateien, nach \includegraphics{ Dateinamen. Diese Tastenfolge jedes Mal zu drücken ermüdet, deshalb hängt man den omnifunc in der Praxis an eine Vervollständigungs-Engine – die omni-Quelle von nvim-cmp in Neovim oder die Erweiterung coc-omni von coc.nvim, die in beiden läuft. Die Arbeitsteilung bleibt stets dieselbe: vimtex erzeugt die Kandidaten, die Engine entscheidet, wann und wie sie erscheinen.
local cmp = require("cmp")
cmp.setup({
sources = cmp.config.sources({
{ name = "omni" }, -- pulls vimtex candidates through omnifunc
}),
})Worin sich Vim und Neovim wirklich unterscheiden
Was das Bearbeiten angeht, sind Textobjekte, Inhaltsverzeichnis und Vervollständigung in beiden völlig gleich. Der Unterschied betrifft genau eine Sache: ob etwas von außen den Editor zurückrufen kann. Die Rückwärtssuche verlangt, dass der Betrachter in den Editor hineingreift, und in Vim ist dieser Kanal die Funktion +clientserver. Die vimtex-Dokumentation schreibt unmissverständlich, dass unter Windows oder in gVim automatisch ein Server startet, nicht aber bei einem Vim im Terminal unter Linux oder macOS. Neovim besitzt gar kein clientserver und nutzt stattdessen MessagePack-RPC; vimtex behandelt beide gleich, und in beiden Fällen steht die Adresse in v:servername.
Und „im Terminal-Vim einfach einen Server starten“ hilft nicht immer. Das mit macOS ausgelieferte /usr/bin/vim meldet -clientserver – die Funktion ist gar nicht einkompiliert, remote_startserver() existiert also nicht, und das Schnipsel unten bewirkt nichts. Dann bleibt die Wahl zwischen einem Build mit +clientserver, etwa MacVim oder Homebrews Vim, und dem Umstieg auf Neovim. Der praktische Schluss dieses Abschnitts ist das Spiegelbild davon: Auf der Neovim-Seite ist überhaupt keine Konfiguration nötig. Zwei kleinere Unterschiede bleiben: Vim braucht encoding auf utf-8, Neovim nicht, und die verlangten Editorversionen werden getrennt als Vim 9.2 und Neovim 0.12.4 genannt.
" Vim only, and only in a build that has +clientserver.
if empty(v:servername) && exists('*remote_startserver')
call remote_startserver('VIM')
endifBetrachter wählen und die Kommandozeile der Rückwärtssuche
Am häufigsten missverstanden wird hier der Vorgabewert von g:vimtex_view_method. Er wird nicht klug je Plattform gewählt: auf jedem Betriebssystem lautet die Vorgabe general und fällt damit auf einen generischen Start zurück – xdg-open unter Linux, open unter macOS, SumatraPDF und Verwandte unter Windows. Dieser generische Betrachter wird in g:vimtex_view_general_viewer benannt. Als eigene Methoden gibt es zathura, zathura_simple, skim, mupdf, galley und sioyek; einen Wert sumatrapdf gibt es nicht. SumatraPDF unter Windows läuft über general. Wie SyncTeX selbst funktioniert, steht auf der eigenen Seite; hier folgt nur die Konfiguration.
Die Vorwärtssuche (Quelle → PDF) ist bloß \lv und braucht kaum Konfiguration. Die Arbeit steckt in der Rückwärtssuche: Dem Betrachter muss beigebracht werden, beim Klick einen bestimmten Befehl auszuführen. Dieser Befehl lautet VimtexInverseSearch <Zeile> <Datei>. Zu beachten ist allein, dass die Platzhalter für Zeilennummer und Dateiname je Betrachter anders geschrieben werden: zathura nutzt %{line} und %{input}, Skim %line und %file, SumatraPDF %l und %f. Mit g:vimtex_view_method = 'zathura' startet vimtex zathura mit -x und übergibt diesen Befehl selbst, sodass auf den meisten Systemen ein Strg-Klick auch ohne jede eigene Zeile zurückführt.
# Linux: zathura. Ctrl-click in the PDF jumps back to the source.
set synctex true
set synctex-editor-command "nvim --headless -c 'VimtexInverseSearch %{line} %{input}'"Für Skim unter macOS öffnet man den Reiter „Sync“ der Einstellungen, setzt die Voreinstellung auf „Custom“ und trägt Befehl samt Argumenten ein; die Rückwärtssuche ist dann Cmd-Shift-Klick. Für SumatraPDF unter Windows kommt eine Zeile derselben Bauart in das Feld für die Rückwärtssuch-Kommandozeile; ausgelöst wird sie per Doppelklick. Mit gVim ersetzt man den Teil nvim --headless durch vim -v --not-a-term -T dumb.
# macOS, Skim: Preferences > Sync > Preset: Custom
Command: nvim
Arguments: --headless -c "VimtexInverseSearch %line '%file'"
# Windows, SumatraPDF: Settings > Options > inverse search command-line
cmd /c start /min "" nvim --headless -c "VimtexInverseSearch %l '%f'"Die vier Handgriffe, die zuerst sitzen sollten
vimtex ist kein Werkzeug, das man beherrschen müsste, bevor man zu schreiben anfängt. Mit \ll die Dauerkompilierung starten, speichern, mit \lv die passende Stelle im PDF ansehen und mit \le nur die Fehler lesen – sitzen diese vier Handgriffe, lässt sich alles Weitere an dem Tag ergänzen, an dem es gebraucht wird. Auch bei den Textobjekten lohnt der Start mit bloß dae und cse, um dann auf ci$ und tsd auszuweiten; rasch zeigt sich, welche Handgriffe man tatsächlich täglich braucht.
Bevor das Dokument auf mehrere Dateien verteilt wird, lohnt eine einmalige Prüfung: Erzeugt \ll aus einer Kapiteldatei heraus noch dasselbe PDF? \li zeigt, welche Datei vimtex als Hauptdatei ansieht; stimmt sie nicht, hilft \ls oder ein Verweis auf die Hauptdatei mit % !TeX root = main.tex. Ist das geklärt, bleibt der Bau ruhig, während man Vervollständigungs-Engines und Snippets darüberlegt.