Vim

Lesezeit: 31 Minuten

Vim ist ein Texteditor mit einer Fülle an Modi und Befehlen, um ohne Einsatz einer Maus effizient Textinhalte bearbeiten zu können. Vim ist mein Standardwerkzeug, wenn ich auf der Shell unterwegs bin, sei es auf meinem Linux-Desktop, meinem Linux-Server, auf einem meiner Raspberry Pis oder meinem beruflich eingesetzten MacBook.

In diesem Beitrag möchte ich die Grundlagen von Vim vermitteln, sowie auch viele interessante Möglichkeiten aufzeigen, die sicher nicht jedem geläufig sind. Vim bietet genug Stoff für ein Buch mit sehr vielen Seiten, weshalb ich viele Features gar nicht vorstelle und andere nur grob anreiße. Dennoch ist der Artikel sehr lang geworden. Ich habe mich aber entschieden, Artikel nicht mehr zweizuteilen, auch da ich das Veröffentlichungsintervall konsequent weiter strecke.

Vorgeschichte

Die Vorgeschichte von Vim beginnt im Jahr 1965 mit einem zeilenorientierten Editor namens QED (quick editor). 1973 veröffentlichte Ken Thompson den Editor ed, der sich vieles von QED abgeschaut hatte und Teil des POSIX-Standards geworden ist. Thompson ist bekannt als Erfinder von Unix und der Programmiersprache B, dem Vorläufer von C. ed ist mehr berüchtigt als berühmt und wurde unter anderem als the most user-hostile editor ever created bezeichnet. Der Brite George Coulouris entwickelte 1975 eine verbesserte Version von ed, die er em nannte. Er zeigte dies dem späteren Mitbegründer von Sun Microsystems, Bill Joy, der wiederum den Code modifizierte und damit ex schuf, einen Texteditor, der Teil von BSD (1978-1995) wurde. ex erhielt später eine visuelle Benutzerschnittstelle. 1979 wurde der visuelle Modus von ex erstmals als Editor vi mit BSD ausgeliefert.

1987 entwickelte Tim Thompson Stevie (ST Editor for VI Enthusiasts), einen vi-Klon für den Atari ST. Ob Tim Thompson und Ken Thompson miteinander verwandt sind oder ob der gemeinsame Nachname reiner Zufall ist, ist mir nicht bekannt. Tim Thompson arbeitete jedenfalls ebenfalls für Bell Labs und AT&T und hat eine Webseite, die ich am Ende des Beitrags verlinkt habe. 1991 erschien Vim, entwickelt von Bram Moolenaar als Portierung von Stevie.

Vim ist Open Source und der Quellcode auf GitHub verfügbar. Neben vim als Kommandozeilenprogramm existiert auch eine Auslieferung mit graphischer Benutzeroberfläche, GVim. Einige Programme integrieren Vim teilweise oder vollständig, zum Beispiel IntelliJ IDEA in Form eines Plugins. 2015 erschien NeoVim, ein Fork von Vim, mit dem Ziel, durch ein großangelegtes Refactoring die Pflege und Weiterentwicklung des Quellcodes sowie die Beteiligung Dritter daran zu vereinfachen, die Erweiterbarkeit durch Plugins zu verbessern und APIs für diverse Programmiersprachen zur Verfügung zu stellen. NeoVim ist überwiegend kompatibel zu Vim.

Modi

Vim ist nach Programmstart im Modus normal. In diesem Modus ist die Cursorposition sichtbar und bewegbar. Der normale Modus dient dazu, schnell im Text zu navigieren, etwa an den Anfang oder das Ende einer Datei zu springen, zu einer angegebenen Zeilennnummer oder den Cursor Zeichen für Zeichen oder Wort für Wort vor und zurück zu bewegen. Im normalen Modus können auch Zeichen, Wörter und Zeilen ausgeschnitten, kopiert oder eingefügt werden (und vieles mehr).

Der Einfügemodus, insert mode, dient in erster Linie dazu, Text zu schreiben. Es gibt viele Möglichkeiten, vom normalen Modus aus relativ von der Cursorposition in den Einfügemodus zu wechseln, z.B. an den Beginn oder das Ende der aktuellen Zeile.

Der visuelle Modus, visual mode, dient unter anderem dem Ausschneiden, Löschen oder Ersetzen eines markierten Abschnittes. Streng genommen gibt es hier nochmal mehrere Modi:

  • Im visual mode werden einzelne Zeichen selektiert.
  • Im visual line mode werden Zeilen selektiert.
  • Im visual block mode werden, nun ja… Blöcke selektiert, z.B. die Zeichen vier bis acht drei aufeinanderfolgender Zeilen.

Der Befehlsmodus, command mode, ermöglicht die Ausführung verschiedenster Befehle und gibt im Gegensatz zum normalen Modus visuelles Feedback: Der Befehl wird in einer Eingabeaufforderung geschrieben und mit Druck auf die Eingabetaste abgesetzt. Im Befehlsmodus kann man z.B. Ersetzungen mit Unterstützung für reguläre Ausdrücke durchführen, sortieren, die Vim-Konfiguration ändern, Tabs aufmachen und schließen oder den Editor horizontal oder vertikal teilen (split screen).

Es gibt noch weitere Modi, die oben genannten sind aber die wichtigsten. Fun Fact am Rande: Mit vim -e startet man Vim im ex mode, der noch auf die Zeit zurückzuführen ist, als vi als neuer Modus für den Texteditor ex angesehen werden konnte.

Öffnen, Speichern und Verlassen

Vielleicht die größte Hürde, wenn man das erste Mal mit Vim in Berührung kommt, sind die Kürzel zum Speichern einer Datei und zum Beenden des Editors. Daher gehe ich hier kurz darauf ein.

Der Befehl vim test.txt auf der Kommandozeile öffnet die bestehende Datei test.txt oder erstellt eine neue Datei mit diesem Namen im gegenwärtigen Verzeichnis. Aus dem normalen Modus heraus kann die Datei via :q gefolgt von der Eingabetaste geschlossen und Vim verlassen werden. Wurde die Datei mit Vim verändert, wird ein Verlassen ohne Speichern mit :q! durchgeführt, gewissermaßen um zu sagen „Ja ich weiß, dass ich etwas geändert habe und ich möchte diese Änderungen verwerfen“. Mit :w wird der Bearbeitungsstand gespeichert. Mit :wq werden die Änderungen gespeichert und Vim verlassen. Jetzt aber erstmal zur Navigation…

Der normale Modus ist für die Navigation optimiert. Die Navigationsmöglichkeiten im Einfügemodus sind auf aus typischen Texteditoren bekannte Navigationsmöglichkeiten wie die Pfeiltasten beschränkt. Statt der Pfeiltasten lässt sich im normalen Modus mit den Tasten h, j, k und l navigieren. h und l navigieren ein Zeichen nach links und rechts, j und k nach unten und oben. Mit einem Tastaturschema wie QWERTY oder QWERTZ funktioniert das gut. Da ich gelegentlich mit Dvorak unterwegs bin, greife ich meist auf die Pfeiltasten zurück. Ein Gedanke bei Vim ist der Einsatz des Zehnfingersystems: Die Pfeiltasten liegen weit von der Basisreihe entfernt, so dass ich zumindest jedem empfehlen würde, die Variante mit h, j, k und l mal auszuprobieren.

Im normalen Modus bewegt man den Cursor mit w wie word ein Wort vorwärts und b wie back ein Wort zurück. Mit 0 springt der Cusor an den Anfang einer Zeile, und mit $ ans Ende. Mit G navigiert man zu einer angegebenen Zeile. G selbst ist synonym zu 0G bzw. $G und springt zur letzten Zeile. 1G bewegt den Cursor in die erste Zeile und 25G in Zeile 25 oder die letzte Zeile, wenn die Datei weniger Zeilen hat. Übrigens werden die Zeichen nacheinander eingegeben und müssen nicht mit der Eingabetaste oder sonstwie bestätigt werden, es gibt auch kein visuelles Feedback vor Ende der Eingabe. Um es nochmal auf den Punkt zu bringen: Befindet man sich in Zeile 13 einer Datei mit 100 Zeilen und möchte zur Zeile 25 navigieren, so drückt man die Zeichen 2, 5, und G nacheinander. Nach Eingabe des dritten Zeichens befindet sich der Cursor in Zeile 25. Man kann die Zeichen schnell hintereinander eingeben, oder jeweils drei Sekunden warten, entscheidend ist nur, dass man während der Eingabe des Befehls keine anderen Tasten (wie die Pfeiltasten) drückt, sonst führt man ggf. unabsichtlich einen anderen Befehl aus.

Anhand der Navigation kann man gut das Konzept der Wiederholung einführen: Wenn ich drei Wörter vorwärts springen möchte, so kann ich dreimal die Taste w drücken, ich kann aber auch 3w eingeben. Analog kann ich mit 5j fünf Zeilen nach unten navigieren und mit 4<Pfeiltaste-nach-oben> den Cursor vier Zeilen nach oben bewegen. Die Taste . (Punkt) wiederholt den letzten Befehl. Wenn ich also in 10er-Schritten eine lange Datei nach unten navigieren möchte, kann ich einmalig 10j eingeben und dann mit wiederholter Betätigung der Punkt-Taste mich weiter nach unten bewegen.

Mit % (Prozentzeichen) lässt sich übrigens der Cursor von einer sich öffnenden zur passenden sich schließenden Klammer bewegen. Dies funktioniert in meiner Version von Vim für runde, eckige und geschweifte, nicht aber spitze Klammern. In vielen Programmiersprachen mit C-ähnlicher oder LISP-ähnlicher Syntax ist das sehr praktisch.

Suche in der Navigation

Mit der Taste / (Slash) wird eine Suche eingeleitet. Die Semantik hier ähnelt dem Befehlsmodus (mehr dazu später). Am unteren Ende des Fensters wird eine Suchzeile beginnend mit einem Slash angezeigt. Gibt man nun einen Suchbegriff, z.B., „Mod“ ein und drückt die Eingabetaste, so springt der Cursor zum nächsten Treffer. Mit n kann man den Cursor zum jeweils nächsten und mit N zum jeweils vorherigen Treffer bewegen. Weitere Möglichkeiten die Suche einzuleiten sind die Tasten * und #. Beide beziehen sich auf das Wort an der aktuellen Cursorposition und navigieren vorwärts bzw. rückwärts zu den weiteren Treffern. Ein Unterschied ist hier, dass nur ganze Wörter einen Treffer darstellen. Befindet sich der Cursor auf dem Wort Modus und man drückt die Taste *, so wechselt der Cursor zum nächsten Treffer für dieses Wort, ignoriert dabei aber Wörter wie Modusauswahl, die keinen exakten Treffer darstellen. Bei der weiteren Navigation sind die beiden Tasten mit n und N austauschbar, d.h. dass man auch bei einer mit / eingeleiteten Suche mit * und # navigieren kann und umgekehrt.

Die Befehle f und F bzw. t und T erlauben sehr mächtige Manipulationen. fa bewegt den Cursor zur nächsten Position des Zeichens a in der aktuellen Zeile. F. bewegt den Cursor zurück zur vorherigen Position des Zeichens . (Punkt) in der aktuellen Zeile. ta bzw. T. bewegen den Cursor zum Zeichen davor bzw. danach. Dazu ein Beispiel:

Dies ist ein Satz. Noch | ein Satz.

Die Pipe | soll die aktuelle Cursorposition darstellen. Das passiert, wenn man von dieser Ausgangslage die vier oben angegebenen Befehle ausführt:

  • fa bewegt den Cursor auf das a von Noch ein Satz.
  • F. bewegt den Cursor auf den Punkt, der den ersten Satz abschließt.
  • ta bewegt den Cursor auf das S von Noch ein Satz, also unmittelbar vor das a.
  • T. bewegt den Cursor auf das Leerzeichen zwischen Punkt und Noch, also unmittelbar hinter den Punkt.

Ich komme gleich nochmal auf diese Befehle zurück, weil sie sehr hilfreich sein können. Um noch ein wenig Verwirrung zu stiften: Diese Befehle lassen sich nicht mit . wiederholen. Stattdessen kann man die Befehle mit ; (Semikolon) vorwärts (kleines f/t) und mit , (Komma) rückwärts (großes F/T) wiederholen.

Ausschneiden, Kopieren und Einfügen

Die aktuelle Zeile kann im normalen Modus mit dd (delete) gelöscht werden. Mit yy (yank) wird die Zeile in die Zwischenablage kopiert. Mit p (paste) wird der Inhalt der Zwischenablage nach dem Cursor eingefügt. Mit diesen Befehlen sollte die Grundstruktur von Befehlen im normalen Modus langsam deutlich werden, die oft auf Angabe einer Wiederholung oder Spanne basiert, gefolgt von einer Aktion gefolgt von einer Selektion.

Schauen wir uns dazu einmal das Löschen genauer an. Mit 5dd werden ausgehend von der Cursorposition die nächsten 5 Zeilen gelöscht. Mit dw wird ausgehend von der Cursorposition der Rest des aktuellen Wortes gelöscht. Befindet sich der Cursor an der Position des kleinen L von Befehlsmodus, so wird lsmodus gelöscht und Befeh bleibt erhalten. diw (delete in word) würde in dem Fall das ganze Wort löschen. Mit d0 wird alles vor der aktuellen Cursorposition in der Zeile gelöscht. Mit d$ wird alles nach der aktuellen Cursorposition in der Zeile gelöscht. 4dw löscht die nächsten vier Worte. dip löscht einen ganzen Paragraphen. Befindet sich der Cursor in Zeile 3 von 5 Zeilen, die Zeile 1 und 5 sind Leerzeilen während die Zeilen 2, 3 und 4 Inhalte haben, so führt der Befehl dip dazu, dass nur die Leerzeilen 1 und 5 verbleiben.

Mit yy gefolgt von p kann eine Zeile dupliziert werden. Mit yy gefolgt von 4p wird eine Zeile verfünffacht. Mit yw gefolgt von 4P wird das aktuelle Wort verfünffacht, wenn sich der Cursor auf dem ersten Zeichen des jeweiligen Wortes befindet. Beim Einfügen mit p (danach) oder P (davor) ist darauf zu achten, ob der Inhalt eine ganze Zeile oder nur einzelne Zeichen darstellt. Werden die Zeichen vim innerhalb einer Zeile mit yw in die Zwischenablage geschrieben und der Cursor befindet sich an Position des ersten Zeichens, v, so wird vim durch p zu vvimim und durch P zu vimvim.

Mit x und X werden einzelne Zeichen gelöscht. 3x löscht drei Zeichen ab der Cursorposition, 5X löscht die fünf Zeichen vor der Cursorposition.

Weitere Möglichkeiten im normalen Modus

Die letzte Änderung kann mit u (undo) rückgängig gemacht werden und das Undo wiederum mit strg+r (redo) rückgängig gemacht werden. Natürlich kann ich auch mit 3u die letzten drei Änderungen rückgängig machen. Ich bin kein großer Fan von den meisten Kürzeln mit der Strg-Taste in Vim, da es oft Konflikte mit anderen Programmen gibt, z.B. bei Vim-Plugins in IDEs oder Überschneidungen mit Kürzeln in Terminalanwendungen.

f und t lassen sich hervorragend mit y und d kombinieren. Den Inhalt eines langen Html-Tags <p>sehr langer Text</p> kann ich löschen, indem ich den Cursor auf den Buchstaben s von sehr setze und per dt< alle Zeichen bis vor der sich öffnenden spitzen Klammer entferne. Analog kann ich den Inhalt auch mit yt< kopieren um ihn später mit p woanders einzufügen. Wie gehe ich damit um, wenn ich in dem Paragraphen-Tag einen eingebetteten Tag habe? Am Beispiel <p>sehr <small>langer</small> Text</p> führe ich einfach d3t< aus, um den kompletten Inhalt des Paragraphen zu löschen (lösche alles bis zur dritten spitzen Klammer).

g ist eine Taste mit vielen Bedeutung. Mit ihr lässt sich unter anderem Text ersetzen. Der Befehl gUiw konvertiert das aktuelle Wort in Großbuchstaben, der Befehl guip konvertiert den kompletten Paragraphen in Kleinbuchstaben.

Der Einfügemodus

Vom normalen Modus gelangt man via i, I, a, A, o, O und c in den Einfügemodus. Den jeweiligen Effekt möchte ich anhand eines Beispieles zeigen:

abc
123 4|56 789
xyz

Die Cursorposition in dieser Datei wird wieder durch die Pipe | symbolisiert: Der Cursor ist auf dem Zeichen 5, zwischen 4 und 5 gibt es keine Leerzeichen. Die Ausgangslage ist der normale Modus.

  • i – der Cursor springt auf die 4, neue Zeichen werden zwischen 4 und 5 eingefügt
  • a – der Cursor bleibt auf der 5, neue Zeichen werden zwischen 5 und 6 eingefügt
  • I – der Cursor springt an den Anfang der Zeile, neue Zeichen werden vor der 1 eingefügt
  • A – der Cursor springt an das Ende der Zeile, neue Zeichen werden nach der 9 eingefügt
  • o – der Cursor springt an den Anfang einer neuen Zeile, die vor der Zeile mit xyz eingefügt wird
  • O – der Cursor springt an den Anfang einer neuen Zeile, die nach der Zeile mit abc eingefügt wird

c (change) ist etwas mächtiger. Der Befehl verhält sich wie d (delete) und wechselt dabei in den Einfügemodus. Ein paar Beispiele:

  • ciw löscht 456, neue Zeichen werden zwischen den beiden Leerzeichen zwischen 123 und 789 eingefügt
  • c0 löscht die Zeichen 123 4, neue Zeichen werden am Anfang der Zeile vor der 5 eingefügt
  • c$ löscht alle Zeichen ab der 5, neue Zeichen werden nach der 4 eingefügt

Im Einfügemodus können Tasten wie die Pfeiltasten, Pos1/Home, Ende/End, Bild hoch/runter etc. zur Navigation verwendet werden. Mit Escape oder alternativ strg+c wechsle ich vom Einfügemodus zurück in den normalen Modus. Befehle werden über die Strg-Taste abgewickelt, damit es keine Konflikte mit der beabsichtigten Texteingabe gibt. Ich nenne hier nur zwei Beispiel um aufzuzeigen, was alles möglich ist.

Angenommen ich will eine Rechenaufgabe inklusive Lösung schreiben und habe eine Zeile mit dem Inhalt 29 * 37 = |, wobei die Pipe wie immer für die Cursorposition steht. Im Einfügemodus kann ich nun über strg+r gefolgt von = auf VimScript zurückgreifen, 29*37 eingeben und die Eingabetaste drücken und das Ergebnis von 1073 wird mir an der Cursorposition eingefügt.

Beispiel Nummer zwei, ich möchte Zeichen einfügen, die nicht auf meiner Tastatur sind. Per strg+k kann ich aus dem Einfügemodus heraus zweistellige Zeichencodes eingeben, die ein neues Zeichen bedeuten. strg+k S* fügt das Summenzeichen Σ ein, strg+k != ein Ungleichzeichen ≠, strg+k >= ein Größergleichzeichen ≥ etc.

Um eine Liste aller möglichen Zeichen einzusehen, kann man vom normalen Modus über die Eingabe von : (Doppelpunkt) in den Befehlsmodus wechseln, dann help digraph-table eingeben und die Eingabetaste drücken. Mit den Pfeiltasten lässt sich durch die Liste navigieren und mit :q gefolgt von der Eingabetaste zurück in den normalen Modus wechseln.

Makros

Ein Makro ist eine Aufnahme mehrere Eingaben, die zu einem späteren Zeitpunkt beliebig oft wiederholt werden kann. Nehme ich mal an, ich habe die Liste weiter oben der sechs Beispiele zu den Befehlen i, a, I, A, o und O als Text vorliegen:

i - der Cursor springt auf die 4, neue Zeichen werden zwischen 4 und 5 eingefügt
a - der Cursor bleibt auf der 5, neue Zeichen werden zwischen 5 und 6 eingefügt
I - der Cursor springt an den Anfang der Zeile, neue Zeichen werden vor der 1 eingefügt
A - der Cursor springt an das Ende der Zeile, neue Zeichen werden nach der 9 eingefügt
o - der Cursor springt an den Anfang einer neuen Zeile, die vor der Zeile mit xyz eingefügt wird
O - der Cursor springt an den Anfang einer neuen Zeile, die nach der Zeile mit abc eingefügt wird

Ich möchte diesen Text wie folgt ändern: Das Kürzel und der Bindestrich sollen verschwinden. Der Satz soll mit einem großen D anfangen. Am Ende soll ein Punkt eingefügt werden. Die erste Zeile soll also wie folgt aussehen:

Der Cursor springt auf die 4, neue Zeichen werden zwischen 4 und 5 eingefügt.

Um dies zu erreichen kann ich die erste Zeile anpassen, die Anpassung als Makro aufnehmen und das Makro 5x abspielen. Ein Makro wird in ein Register geschrieben. Das Thema geht für den Artikel zu weit, es sei nur so viel gesagt, dass ich das Register a verwenden kann und die Befehle y und p ebenfalls Zugriff auf die Register haben, mir in dem Sinne also mehrere Zwischenablagen parallel zur Verfügung stehen.

Die Aufnahme des Makros beginne ich im normalen Modus mit der Eingabe von qa. Dann führe ich meine Änderungen aus und beende die Aufnahme mit q. Abspielen kann ich das Makro dann mit @a.

Zunächst aber zu der Änderung:

  • Ich beginne im normalen Modus mit dem Cursor an Position des ersten Zeichens der Zeile, also i.
  • Ich lösche vier Zeichen mit 4x.
  • Ich ersetze das Zeichen an der Cursorposition mit dem Befehl r (replace) durch ein D, also rD.
  • Ich springe zum Ende der Zeile mit A in den Einfügemodus.
  • Ich schreibe das Zeichen Punkt.
  • Ich beende den Einfügemodus mit Escape.
  • Ich springe zum Anfang der Zeile mit 0.
  • Ich springe in die nächste Zeile mit j.

Diese Sequenz nehme ich auf und spiele sie danach 5x ab. Zum Nachspielen mit dem oben angegebenen Inhalt hier die vollständige Abfolge der Befehle:

1Gqa4xrDA.Escape0jq5@a

Die Makrofunktion glänzt vor allem dann, wenn man es mit großen Inhalten zu tun hat und die händische Bearbeitung sehr viel Aufwand bedeuten würde.

Der visuelle Modus

Der visuelle Modus ermöglichst das visuelle Auswählen von Text und wird aus dem normalen Modus heraus erreicht. Ich kann mit 3yw die nächsten drei Wörter in die Zwischenablage schreiben, oder ich wechsel mit v in den visuellen Modus und selektiere dann mit den Pfeiltasten respektive h, j, k und l die nächsten drei Worte. Der visuell selektierte Text kann dann mit y in die Zwischenablage kopiert werden. Analog kann ich mit d ausgewählten Text löschen, mit c dabei in den Einfügemodus wechseln oder ihn mit p durch Inhalt aus der Zwischenablage ersetzen. Der visuelle Modus wird mit Escape oder alternativ strg+c beendet.

Mit V wechsle ich in den visual line mode, in dem ich nicht mehr einzelne Zeichen, sondern nur ganze Zeilen auswählen kann. Der visual block mode ist über die Kombination strg+v erreichbar. In diesem Modus lässt sich Text in mehreren Zeilen gleichzeitig manipulieren. Den folgenden Zeilen wollen wir demonstrativ einen Bindestrich voranstellen:

Eine Aufgabe
Noch eine Aufgabe
Eine weitere Aufgabe
Die letzte Aufgabe

Dies kann ich wie folgt erreichen:

1Gstrg+v3jI-Escape → (eine Sekunde Geduld, nichts tun)

Dies lässt sich natürlich auch mit dem Einsatz eines Makros erreichen, oder mit Ersetzungen, oder mit dem Aufruf eines externen Programmes aus dem Befehlsmodus, oder dem Einsatz von Registern oder VimScript oder oder oder. Mit Vim führen oft sehr viele Wege zum Ziel. Mit u und U lässt sich übrigens eine Selektion in Klein- und Großbuchstaben konvertieren, VU konvertiert entsprechend die aktuelle Zeile in Großbuchstaben.

Der Befehlsmodus

Wir nähern uns dem Ende dieses Artikels und dem meiner Meinung nach mächtigsten Modus von Vim. Den Befehlsmodus haben wir weiter oben kurz beim Speichern und Verlassen kennengelernt und am Rande beim Aufruf der Vim-eigenen Hilfe. Der Befehlsmodus ist vom normalen Modus aus via : (Doppelpunkt) erreichbar. Die Anwendung eines Befehls mit der Eingabetaste führt in der Regel zurück in den normalen Modus.

Während man im normalen Modus oft auf Wiederholungen zurückgreift, etwa 3dd, kann man im Befehlsmodus mit Bereichen (Ranges) arbeiten. Der Befehl 3,5d löscht die Zeilen 3, 4 und 5. Um es nochmal zu verdeutlichen. Aus dem normalen Modus wird dieser Löschbefehl wie folgt umgesetzt: :3,5d gefolgt von Eingabetaste.

Der Befehl 8,$d löscht alle Zeilen nach Zeile 7. Der Befehl 1,.d (Eins Komma Punkt d) löscht alle Zeilen ab der ersten Zeile bis einschließlich der Cursorposition. Der Befehl %d löscht alle Zeilen, so dass die Datei im Anschluss leer ist. Mit m (move) lassen sich Zeilen verschieben. m0 verschiebt die aktuelle Zeile ganz nach vorne, m1 hinter die erste Zeile und m$ ganz ans Ende der Datei.

Mit sort lassen sich Zeilen sortieren. 1,3sort n sortiert die Zeilen 1 bis 3 in numerische Reihenfolge aufsteigend, z.B. 1, 9, 10. 1,3sort hingegen sortiert die Zeilen alphabetisch, d.h. z.B. 1, 10, 9 (10 kommt alphanumerisch vor 9 genau wie ba vor z kommt). 2,$sort! sortiert die Zeilen ab Zeile 2 absteigend – so lässt sich z.B. die Kopfzeile einer CSV-Datei aus der Sortierung raushalten.

s (substitute) ist ein mächtiger Befehl, über den man problemlos einen eigenen Artikel schreiben könnte. Der Befehl s/foo/bar/g ersetzt alle Vorkomnisse von foo durch bar. Lässt man das Flag g (global) weg, so wird nur der erste Treffer ersetzt. s bezieht sich hier auf die aktuelle Zeile, mit dem Präfix % wird der Befehl hingegen auf die gesamte Datei angewandt (analog zu: %d). Das Flag c am Ende, also etwa in %s/foo/bar/gc, fragt bei jeder Ersetzung nach, wie damit verfahren werden soll, also etwa ersetzen, nicht ersetzen, Vorgang abbrechen etc. Ersetzungen werden oft mit regulären Ausdrücken umgesetzt. Da dabei häufig viele Zeichen escaped werden müssen, weil sie eine besondere Bedeutung haben, kennt Vim vier verschiedene Ebenen der Unterstützung regulärer Ausdrücke: magic, nomagic, very magic und very nomagic – Kein Scherz, auf reguläre Ausdrücke in Vim weiter einzugehen sprengt aber den Umfang dieses Artikels.

Der Befehl g (global) ist ähnlich aufgebaut wie s, führt anstatt Ersetzungen aber Befehle aus. g/foo/d löscht alle Zeichen, in denen foo enthalten ist. Der Befehl g/foo/norm gU$ konvertiert alle Zeilen in Großbuchstaben, die foo enthalten. Die Anweisung norm wird hier verwendet, um einen Befehl aus dem normalen Modus zu importieren. Quizfrage am Ende: Der Befehle g//m0 dreht die Reihenfolge aller Zeilen einer Datei um, so dass aus der Zeilenreihenfolge 1, 2, …, $ die Reihenfolge $, …, 2, 1 wird – Warum?

Tabs und Splits

Vorweg sei gesagt: Vim hat eine Konfiguration, die sich üblicherweise im Home-Verzeichnis in einer Datei .vimrc befindet. Meine Datei hat aktuell folgenden Inhalt und ich gehe nur ganz kurz darauf ein:

filetype on
filetype plugin on
filetype indent on
syntax on
set number
set cursorline
set shiftwidth=4
set tabstop=4
set expandtab
set showmatch
set hlsearch

Diese Konfiguration führt unter anderem dazu, dass Vim für verschiedene Dateiendungen Syntax Highlighting vornimmt, Einrückungen beim Einfügen einer neuen Zeile berücksichtigt, Zeilennummern anzeigt, eine feste Tabgröße hat und Tabs durch Leerzeichen ersetzt. Für alles Weitere möchte ich auf Suchmaschinen bzw. die Vim-Hilfe/-Dokumentation verweisen.

Tabs in Vim lassen sich im Befehlsmodus mit tabnew dateiname anlegen. Mit tabclose wird der aktuelle Tab geschlossen. Bei ungespeicherten Änderungen muss ein ! (Ausrufezeichen) angehängt werden. Mit gt und gT kann man im normalen Modus die Tabs vorwärts bzw. rückwärts wechseln. In der Tabliste oben wird neben dem Dateinamen ein + angezeigt, wenn es ungespeicherte Änderungen in der geöffneten Datei gibt.

Innerhalb eines Tabs oder auch einfach wenn man keinen zweiten Tab öffnet, kann man das Fenster im Befehlsmodus teilen. Dies funktioniert via split (horizontal) und vsplit (vertikal). Gibt man keinen Dateinamen an, wird die aktuell geöffnete Datei nochmal geöffnet. Mit split dateiname öffne ich die Datei dateiname in der Art, dass die obere Hälfte des Fensters die Datei dateiname zeigt und die untere Hälfte die zuvor geöffnete Datei. Das folgende Bild verdeutlicht, dass sich dieses Prinzip beliebig verschachteln lässt und gibt auch einen Eindruck vom Syntax-Highlighting für verschiedenste Programmiersprachen.

Um Details im Screenshot gut erkennen zu können, kann das Bild einfach in einem eigenen Tab geöffnet werden. Zu sehen ist hier das Syntax-Highlighting für C++, C#, Fortran, Lua, Ruby, Rust und Scheme. Ich finde, Vim tut dabei einen ziemlich guten Job!

Mit strg+w aus dem normalen Modus heraus ist ein Wechsel zwischen den verschiedenen Fenstern möglich. Folgt auf diese Tastenkombination ein w, so wird zum nächsten Fenster gewechselt. Etwas intuitiver ist meiner Meinung nach die Navigation via Pfeiltasten bzw. h, j, k und l. Um zwei Fenster nach oben zu gehen ist es nicht möglich zweimal hintereinander k bzw. <Pfeil-nach-oben> zu drücken, es muss zwischenzeitig wieder strg+w gedrückt werden. Was wirklich? Nein, nach dem Durchlesen dieses Artikels sollte eigentlich jeder auf die Idee kommen, wie man das Vim-like umsetzt: strg+w gefolgt von 2k.

Fenster im Splitmodus können genauso wie auch Tabs mit :q verlassen werden.

Es gibt noch mehr

Die Möglichkeiten von Vim sind schier endlos. Hier nur ein paar kurz angerissene Möglichkeiten was sich noch so machen lässt.

Mit map lassen sich pro Modus Befehle mappen. Wenn man die Taste , (Komma) z.B. im normalen Modus nicht braucht, kann man sich den Doppelpunkt auf Komma setzen und spart sich so das Drücken der Shifttaste beim Wechsel in den Befehlsmodus. Das Mapping wird im Befehlsmodus wie folgt gesetzt: nmap , :. Das n steht hier für normal, dem gegenüber gibt es auch imap (insert), vmap (visual) und cmap (command). Im Befehlsmodus gilt die Änderung nur für die aktuelle Session, er lässt sich aber auch in die .vimrc eintragen.

Mit ! können im Befehlsmodus Shell-Befehle ausgeführt und mit read! in die geöffnete Datei eingefügt werden. ! ls zeigt mir unter Linux direkt in Vim an, was sich so alles im gegenwärtigen Verzeichnis befindet. read! date fügt unter Linux das aktuelle Datum plus Uhrzeit nach der Cursorposition ein.

Mit dem Befehl iab lassen sich Abkürzungen verwalten, auch dies ist in der .vimrc persistent möglich. Habe ich also keine Lust meinen vollen Namen (oder E-Mail-Adresse) immer auszuschreiben, kann ich mir ein entsprechendes Kürzel im Befehlsmodus konfigurieren: iab sig Christian Pflugradt. Damit wird der im Einfügemodus eingegebene Text sig sofort durch meinen vollen Namen ersetzt. Bei der Arbeit mit Kürzeln sollte man sich ein gutes Namensschema überlegen, da sie sofort ersetzt werden und es nur über Umwege möglich ist, in meinem Beispiel das Wort sig in eine Datei zu schreiben.

Beim Umgang mit Quellcode oder strukturierten Formaten wie JSON ist es hilfreich, einzelne Abschnitte auf- und zuklappen zu können. Dazu kann eine foldmethod definiert werden. Im Befehlsmodus kann das etwa so aussehen: set foldmethod=indent. Damit können Einrückungen mit dem Befehl za auf- und zugeklappt werden, etwa Blöcke in der Sprache Python.

Fazit

Vim ersetzt für mich keine vollwertige IDE, reicht mir aber in vielen Fällen aus. Auch wenn ich denke, dass ich mich relativ gut mit Vim auskenne, weiß ich, dass es noch sehr sehr viel gibt, wo mein Wissen schnell an Grenzen stößt. Seien es VimScript, Quickfixes, Location Lists oder der effiziente Umgang mit Sessions und Registern: Es gibt noch viel zu entdecken und Vim macht einfach Spaß!

- Vim auf GitHub
- Vim Online-Dokumentation
- Webseite von Tim Thompson