Effizient navigieren in Vim

Beim Editieren einer Datei ist es entscheidend, dass du deinen Cursor recht schnell bewegen kannst. Vim und Neovim bieten dafür viele Wege, die je nach Situation mehr oder weniger effizient und nützlich sind. Dieser Artikel untersucht die verschiedenen Arten, den Cursor zu bewegen, und vergleicht sie. «Effizienz» meint hier, den Cursor mit möglichst wenig Zeit und Aufwand (also möglichst wenigen Tastenanschlägen) zu navigieren.
Mit der Maus
TL;DR: Nicht empfohlen
Mit dem Mauszeiger durch Vim zu navigieren, erscheint Nutzenden, die von einem
GUI-Editor wie Visual Studio Code oder
Ähnlichem kommen, vielleicht naheliegend. In Vim ist das Ziel aber, die Finger
auf der «Home Row» der Tastatur zu behalten (jener Reihe, in der die Tasten F
und J liegen), und sie nicht weit Richtung Touchpad oder gar Maus bewegen zu
müssen. Das soll die Belastung von Händen und Handgelenken reduzieren und das
Editieren effizienter machen. Von der Navigation mit der Maus ist daher in den
meisten Situationen dringend abzuraten – sie ist sogar standardmässig
deaktiviert.
Sie zu aktivieren, kann für Umsteigende von einem der genannten Editoren
hilfreich sein, die einen sanften Übergang wollen: Sie erlauben sich anfangs die
Maus und schalten sie später auf ihrem Lernweg wieder ab. Um die Maus-Navigation
einzuschalten, fügst du Folgendes in deine Konfigurationsdatei ein (entweder
~/.vimrc oder ~/.config/nvim/init.vim):
" Maus-Unterstützung temporär aktivieren
set mouse=a
Damit kannst du den Cursor per Klick bewegen und durch den aktuellen Buffer scrollen.
Mit den Pfeiltasten
TL;DR: Nicht empfohlen
Auch hier gilt: Wer andere Texteditoren oder gar Textverarbeitungen wie LibreOffice Writer gewohnt ist, greift verständlicherweise auf Bekanntes zurück. In diesen Programmen navigiert man per Tastatur meist mit den Pfeiltasten. Davon ist abzuraten, weil … du ahnst es: Sie zwingen dich, die Finger von der Home Row wegzubewegen.
Die Alternative ist, wie im nächsten Abschnitt beschrieben, die Tasten h, j,
k und l, die praktischerweise mittig liegen – genau dort, wo du die Finger
die meiste Zeit ohnehin hast.
Mit h, j, k, l
TL;DR: Für kleine Bewegungen nutzen. Mit relativen Zeilennummern kombinieren.
h, j, k und l sind die grundlegenden Bewegungstasten in Vim. Du solltest
sie statt der üblichen Pfeiltasten verwenden, um – wie oben besprochen – die
Finger möglichst auf der Home Row zu lassen. Das braucht etwas Übung, zahlt sich
aber aus.
Ganz wichtig: Drücke diese Tasten nicht mehrfach hintereinander und halte sie
schon gar nicht gedrückt, um mehrere Spalten oder Zeilen zu überbrücken. Wie
viele Befehle in Vim lassen sie sich mit Zahlen präfixen, um sich mehrfach zu
bewegen. Statt zwölfmal j zu drücken, kannst du zum Beispiel 12j verwenden –
offensichtlich viel effizienter (3 statt 12 Tastenanschläge). Es empfiehlt sich
aber, diese Tasten nur für kleine Bewegungen zu nutzen und hauptsächlich, um
Zeilen hoch- oder runterzugehen, denn für längere vertikale und für horizontale
Distanzen gibt es effizientere Wege.
Sehr nützlich ist es, relative Zeilennummern zu aktivieren, um auf einen Blick
zu sehen, welche Zahl du j oder k voranstellen musst, um zu einer bestimmten
Zeile zu springen. Du aktivierst sie, indem du folgende zwei Zeilen in deine
Konfigurationsdatei einfügst:
" Relative Zeilennummern aktivieren
set relativenumber
set number
Damit wird immer die absolute Nummer der Zeile angezeigt, auf welcher der Cursor gerade steht, und für alle anderen die relative Nummer.
Navigation innerhalb einer Zeile
TL;DR: Meistens f verwenden. Auch w, b, e, ^ und $ im Blick
behalten.
Bisher haben wir uns vor allem die Navigation von Zeile zu Zeile angeschaut. Der
nächste Schritt ist die Navigation innerhalb einer Zeile. Naheliegend ist oft,
w oder W zum nächsten Wort, b oder B zum vorherigen Wort oder e bzw.
E direkt ans Ende des nächsten Worts zu verwenden. Bei allen betrachtet die
Kleinbuchstaben-Variante als «Wort», was wir intuitiv als solches sehen, und
nutzt Trennzeichen wie -, / oder ., um Wörter voneinander abzugrenzen. Die
Grossbuchstaben-Variante betrachtet alles als Wort, was durch Whitespace
getrennt ist. Natürlich lässt sich jedem dieser Befehle eine Zahl voranstellen,
um mehrere Wörter auf einmal zu überspringen (z.B. 7w). Weitere nützliche
Befehle sind ^, das zum ersten Nicht-Whitespace-Zeichen der Zeile springt, und
$, das zum letzten Zeichen einer Zeile springt. Nehmen wir folgende Zeile
abc def-ghi-jkl mno
mit dem Cursor auf dem Zeichen g: Dann sind die folgenden Befehle jeweils der
effizienteste Weg zu einem bestimmten Zielzeichen:
| Zielzeichen | Befehl |
|---|---|
j |
2w |
m |
W |
d |
B |
i |
e |
l |
E |
a |
^ or 0 |
o |
$ |
Wenn du mehrere Wörter vor- und zurückspringst oder an eine bestimmte Stelle
innerhalb eines Worts willst, sind t und f unglaublich hilfreich. Besonders
f springt zum nächsten Vorkommen eines bestimmten Zeichens und erlaubt dir so
grosse Sprünge innerhalb einer Zeile. Der Unterschied: f springt auf ein
Zeichen, t direkt davor. t ist deshalb vor allem nützlich, um alles bis zu
einem Zeichen zu löschen. Die Grossbuchstaben-Varianten F und T tun
dasselbe, nur rückwärts. All diese Befehle lassen sich mit ; «wiederholen»,
was zum nächsten Vorkommen des Zielzeichens springt, während , zum vorherigen
springt.
Ein weiterer erwähnenswerter Befehl ist %. Du kannst ihn verwenden, wenn unter
deinem Cursor ein Zeichen steht, das Teil eines Paars ist (z.B. [ oder }).
Der Befehl % bringt den Cursor zum entsprechenden «Partner» dieses Zeichens.
Setzt du den Cursor also auf ein ( und führst diesen Befehl aus, landest du
bei der schliessenden ).
Changelist und Jumplist
TL;DR: Mit ctrl+o und ctrl+i «zurück» und «vorwärts» springen. Mit g;
zur letzten Änderung springen.
Die Jumplist enthält alle Stellen in beliebigen Buffern, zu denen du kürzlich
gesprungen bist (z.B. mit 12j). Du erreichst sie mit :jumps. Die Befehle, um
in der Jumplist vor- und zurückzuspringen, sind ctrl+o bzw. ctrl+i. Sie sind
sehr nützlich, weil sie sich wie die «Zurück»- und «Vorwärts»-Buttons im Browser
verhalten.
Die Changelist hingegen enthält alle Stellen im aktuellen Buffer, an denen du
kürzlich etwas geändert hast. Du erreichst sie mit dem Befehl :changes. Sehr
nützlich ist hier g;, das zur letzten Stelle springt, an der du etwas geändert
hast (also in der Changelist zurückspringt). g, bringt dich dagegen dorthin
zurück, wo du vorher warst (springt also in der Changelist vorwärts). So kannst
du bequem zwischen einem Referenzpunkt (z.B. einer Dokumentation) und der
Stelle, an der du gerade editierst, hin- und herwechseln.
Suche
TL;DR: Ideal für grössere Distanzen – vertikal wie horizontal
Mit Abstand einer der effizientesten Wege, längere Distanzen horizontal und
vertikal in einem Buffer zurückzulegen, ist die Suche. Mit der Taste / suchst
du nach einem Begriff und springst bequem zu seiner Stelle. Mit n und N
springst du zum nächsten bzw. vorherigen Vorkommen des Suchbegriffs. Die Taste
? sucht von der aktuellen Cursorposition aus rückwärts (was n und N
umkehrt). Auch wenn der Hauptzweck des Suchbefehls offensichtlich das Suchen
ist, ist er ein unglaublich mächtiges Werkzeug für schnelle und effiziente
Navigation.
Die Nutzungserfahrung des Suchbefehls lässt sich massiv verbessern, indem du folgende Einstellungen in deine Konfigurationsdatei einfügst:
" Inkrementell schon beim Tippen suchen
set incsearch
" Smart Case für die Suche verwenden
set ignorecase
set smartcase
" Suchtreffer hervorheben
set hlsearch
" <C-L> verwenden, um die Hervorhebung von :set hlsearch zu löschen.
if maparg('<C-L>', 'n') ==# ''
nnoremap <silent> <C-L> :nohlsearch<C-R>=has('diff')?'<Bar>diffupdate':''<CR><CR><C-L>
endif
incsearch sorgt dafür, dass das Suchmuster schon während des Tippens
inkrementell angewendet wird, statt erst nach dem Drücken der Enter-Taste. Die
Kombination aus ignorecase und smartcase ignoriert die
Gross-/Kleinschreibung des Suchbegriffs, solange du keine Grossbuchstaben
verwendest, und beachtet sie, sobald mindestens ein Grossbuchstabe vorkommt –
sehr bequem und überraschend intuitiv. hlsearch hebt alle Treffer des
Suchbegriffs hervor, sodass du einfach mit n und N dazwischen springen
kannst. Die letzte Anweisung lässt dich die hervorgehobenen Suchergebnisse mit
ctrl+l löschen, um deine Ansicht aufzuräumen, wenn du mit Suchen und Springen
fertig bist.
Insgesamt ist die Suche eines der mächtigsten Werkzeuge für intuitive und effiziente Navigation. Sie deckt den häufigen Fall ab, dass du das Wort oder einen Wortteil kennst, zu dem du willst, deine Augen aber noch nicht direkt dorthin gerichtet sind. Ausserdem ist sie in vielen Fällen schlicht der schnellste Weg, irgendwohin zu springen, und schlägt darin andere Navigationsmethoden recht häufig.
Grobe Bewegungen
TL;DR: Nur für sehr spezifische Fälle. gg und G sind hilfreich, um eine
Datei kennenzulernen.
In diesem Abschnitt geht es um das, was man als «grobe Bewegungen» bezeichnen kann. Sie lassen dich grössere Distanzen im Buffer überbrücken, opfern dafür aber Präzision. Genau deshalb sind diese Befehle weniger nützlich. Vim kann ein sehr effizienter Texteditor sein, indem du dir überlegst, was du ändern willst, mit wenigen Tastenanschlägen präzise dorthin springst, in den Insert Mode wechselst, die Änderung mit skalpellartiger Präzision vornimmst und den Insert Mode danach sofort wieder verlässt. Die Bewegungsbefehle in diesem Abschnitt bringen den Cursor dagegen grob im Dokument umher, wobei sich kaum auf einen Blick vorhersagen lässt, in welcher Zeile und Spalte er genau landet.
Ein gutes Beispiel sind die Tasten H, M und L, die den Cursor an den
oberen Rand, in die Mitte bzw. an den unteren Rand des aktuellen Viewports
bringen. Das ist zwar eine grosse Bewegung mit nur einem Tastenanschlag, aber
sehr wahrscheinlich landet der Cursor nicht exakt auf der benötigten Zeile,
sodass du zusätzlich mehrfach j oder k drücken musst – was deutlich mehr
Nachdenken und viel mehr Tastenanschläge bedeutet als mit anderen Methoden.
Ähnlich sind die Tasten { und }, die den Cursor zum nächsten Absatz bringen
(ein durch Leerzeilen abgegrenzter Textblock).
Eine nützliche Ausnahme sind die Befehle gg und G, die den Cursor zur ersten
bzw. letzten Zeile eines Buffers bringen. Wohin dich diese Bewegungen führen,
lässt sich mühelos vorhersagen. Besonders G ist praktisch, weil du damit mit
nur zwei Tastenanschlägen etwas an eine Datei anhängen kannst (G gefolgt von
o).
Plugins
TL;DR: Nur die nötigen Plugins installieren. Schau dir fzf an!
Bisher haben wir nur über Features gesprochen, die in Vim eingebaut sind oder sich in einer unveränderten Installation konfigurieren lassen. Es gibt aber viele nützliche Plugins, welche die Navigation in Vim noch effizienter machen. Wichtig ist, sie sorgfältig auszuwählen, denn jedes Plugin kann Vim langsamer und/oder instabiler machen.
fzf
Eines der nützlichsten Plugins ist fzf,
das ohnehin grossartig ist. Es bietet viele hilfreiche Befehle wie :BLines, um
den aktuellen Buffer mit intelligentem Fuzzy Matching zu durchsuchen, oder
:Rg, um sogar das ganze Projekt nach bestimmten Mustern zu durchsuchen – was
dich im Gegensatz zu den bisherigen Methoden auch zwischen Dateien navigieren
lässt. fzf eignet sich zum Springen zwischen Dateien und Buffern, aber auch
zwischen verschiedenen Stellen innerhalb davon. Ich empfehle dir sehr, es
auszuprobieren und folgende Zeilen in deine Konfigurationsdatei einzufügen:
" Zu einer bestimmten Datei springen
nnoremap <C-P> :Files<cr>
" Das ganze Projekt durchsuchen
nnoremap \ :Rg<space>
Mit der ersten Zeile öffnest du Dateien im aktuellen Projekt, indem du ctrl+p
drückst und dann mit Fuzzy Matching tippst. Die zweite Zeile erlaubt dir, mit
\ das gesamte Projekt per Fuzzy Matching zu durchsuchen (im Gegensatz zu /,
das den aktuellen Buffer durchsucht).
Sneak
Ein weiteres nützliches Plugin ist
Sneak. Statt nach einer Suche mehrfach
n zu drücken, um zum richtigen Vorkommen des Suchbegriffs zu springen, hebt es
jedes Vorkommen hervor und weist ihm eine eindeutige Zeichenkombination zu. Mit
dieser Kombination springst du mit sehr wenigen Tastenanschlägen direkt dorthin.
Ein zusätzlicher Bonus: Etwas sehr Ähnliches gibt es als Browser-Erweiterung, die viele weitere Vim-Befehle im Webbrowser verfügbar macht und Surfen nur mit der Tastatur ermöglicht. Sie heisst Vimium.
Fazit
Natürlich gibt es noch viele andere Wege, in Vim-Buffern zu navigieren, die hier nicht abgedeckt sind. Das sind nur einige der möglichen Navigationstechniken, und welche in welcher Situation am bequemsten und intuitivsten sind, ist oft Geschmackssache.
Ausserdem behandelt dieser Artikel nur Bewegungsbefehle. Befehle, die beim
Bewegen des Cursors an eine bestimmte Stelle gleichzeitig in den Insert Mode
wechseln (z.B. A, das den Cursor ans Zeilenende bringt und in den Insert Mode
geht), bespricht er nicht. Die können zwar unglaublich nützlich sein, hätten
hier aber den Rahmen gesprengt.
Ich empfehle dir sehr, möglichst viele verschiedene Techniken kennenzulernen und sorgfältig zu überlegen, welche in welcher Situation Sinn ergibt. Scheu dich nicht, dich ein wenig zu zwingen, verschiedene auszuprobieren, bis du deinen eigenen Werkzeugkasten für unterschiedliche Situationen gefunden hast. Es braucht etwas Übung, bis das ins Muskelgedächtnis übergeht – aber es lohnt sich, um aus Vim den effizienten Texteditor zu machen, der er sein kann.
Ein vollständiges Konfigurationsbeispiel findest du in meinen eigenen Dotfiles.