Einführung in vim

3. Januar 2020 (letzte Änderung am 16. April 2020)

Was ist vim?

vim steht für Vi IMproved und ist eine Weiterentwicklung des Texteditors vi, der in seiner ursprünglichen Version 1976 entstanden ist. Der vi-Entwickler Billy Joy nutzte damals ein ADM-3A-Computerterminal mit solch einer Tastatur:

Quelle: Wikipedia. Die Autorenschaft wurde nicht in einer maschinell lesbaren Form angegeben. Es wird StuartBrady als Autor angenommen (basierend auf den Rechteinhaber-Angaben)., CC BY-SA 3.0

Auf dieser Tastatur fehlen einige Tasten, die heute Standard sind, insbesondere die Pfeiltasten. Dementsprechend funktioniert die Textbearbeitung in vi(m) ganz anders als mit neueren Texteditoren: Es gibt einen Modus, in dem man Text eingibt, und einen anderen Modus, in dem man mithilfe der Buchstabentasten durch die Datei(en) navigiert, Text löscht, ausschneidet, kopiert oder einfügt (zusätzlich gibt es den Kommandozeilenmodus in vi, sowie weitere Modi in vim).

vim gibt es sowohl als Programm für die Kommandozeile als auch mit GUI. Es ist für praktisch jedes System verfügbar (Linux, BSD, Mac, Windows, Android, u.v.m.). In den meisten Linux-Distributionen ist vim vorinstalliert.

Grundlagen

Viele Neulinge sind erst einmal verwirrt, wenn sie vim zum ersten Mal starten und anfangen zu tippen. Dann passieren nämlich merkwürdige Dinge. Das liegt daran, dass vim immer im Normalmodus startet, wo jede Taste ein Kommando ausführt. Wenn man Text eingeben möchte, muss man zunächst in den Eingabemodus wechseln. Das geht mit i (vor/unter dem Cursor), a (nach dem Cursor), I (am Zeilenanfang) oder A (am Zeilenende). Darüber hinaus kann man noch mit s (substitute) das Zeichen unter dem Cursor löschen und in den Eingabemodus wechseln oder mit c (change) + einem Navigationskommando ein Wort/einen Satz/eine Zeile/u.v.m. löschen und gleichzeitig in den Eingabemodus wechseln.

Zurück in den Normalmodus kommt man mit Esc oder Strg+c.

Im Normalmodus kann man mit folgenden Kommandos die aktuelle Datei speichern und/oder vim beenden:

Aktion Kommando
Datei speichern :w
vim beenden (wenn es keine ungespeicherten Änderungen gibt) :q
Änderungen verwerfen und vim beenden :q!
Änderungen speichern und vim beenden :wq / :x

Navigation

Man kann vim fast wie einen "herkömmlichen" Text-Editor verwenden, indem man gleich in der Eingabemodus wechselt und dann mit den Pfeiltasten hin- und hernavigiert und Text durch mehrmaliges Drücken von Backspace oder Entf löscht. Man nutzt die Effizienz von vim aber erst, wenn man soviel wie möglich im Normalmodus erledigt. Mit den folgenden Kommandos kann man jede Stelle in einer Datei erreichen (und zwar ausschließlich im Normalmodus). Den Eingabemodus benutzt man wirklich nur, um Text einzugeben.

Gehe zum/zur vorherigen/nächsten ... rückwärts vorwärts
Zeichen h/ l/
Zeile k/ j/
Wort1 b w
Wortende1 ge e
Satz ( )
Absatz { }
Dateianfang/-ende gg G
Zeilenanfang/-ende 0/Pos1 $/Ende
Erstes/letztes nicht-leeres Zeichen in Zeile _ g_
Bestimmtes Zeichen in Zeile (z.B. ") 2 F" f"
Vor ein bestimmtes Zeichen in Zeile (z.B. ") 2 T" t"
Wort xyz 3 ?xyz /xyz
Zeile 42 :42/ 42gg / 42G

Anmerkungen:

  1. Ein Wort ist dabei eine Zeichenfolge aus Buchstaben und/oder Zahlen oder eine Folge von Sonderzeichen. Wenn du W, E und B statt w, e und b verwendest, wird jede Zeichenfolge zwischen zwei Leerzeichen als ein Wort gezählt.
  2. Dieses Kommando kann mit ; wiederholt werden. Mit , wird das Kommando in die entgegengesetzte Richtung wiederholt.
  3. Dieses Kommando kann mit n wiederholt werden. Mit N wird das Kommando in die entgegengesetzte Richtung wiederholt.

Kopieren, einfügen, löschen

Kopieren heißt in vim yank, deshalb benutzt man y, um zu kopieren. d (von delete) ist das Kommando zum Löschen, oder besser gesagt Ausschneiden. Darüber hinaus gibt es c (change). Das ist Ausschneiden und in den Eingabemodus wechseln in einem Schritt. All diese Kommandos können auf zwei Arten verwendet werden:

Erst markieren, dann kopieren/ausschneiden

Für vim-Neulinge ist es am einfachsten mit v in den visuellen Modus zu wechseln, einen Bereich mithilfe der Navigationskommandos zu markieren und dann y, d oder c zu drücken. Das kostet zwar einen zusätzlichen Tastenanschlag (den von v), aber dafür sieht man, was genau kopiert wird. Außerdem kann bei dieser Methode die Textauswahl in mehreren Schritten erfolgen.

Direkt kopieren/ausschneiden

Alternativ kombiniert man y, d oder c direkt mit einem Navigationskommando, also zum Beispiel ye, um alles bis zum Ende des aktuellen Wortes zu kopieren.

Oft will man gar nicht ab der Cursorposition kopieren (oder ausschneiden), sondern zum Beispiel das komplette Wort, in dem sich der Cursor gerade befindet, oder alles innerhalb von Klammern. Dafür müsste man den Cursor erst zur öffnenden Klammer bringen und danach bis zur schließenden kopieren, also T(yt). Eleganter geht das mit dem zusätzlichen Kommando i: yi( kopiert alles innerhalb der Klammern zwischen denen sich der Cursor befindet! ya( kopiert das Gleiche, jedoch inklusive der umschließenden Klammern. Anderes Beispiel: diw schneidet das aktuelle Wort aus, daw schließt ein Leerzeichen mit ein.

KopierenAusschneidenÄndernKopieren bis zum
Anfang von ...
Kopieren bis zum
Ende von ...
Zeichen yl dl/x cl/s (r)
Wort yiw diw ciw yb ye
Satz yis dis cis y( y)
Absatz yip dip cip y{ y}
()-Block yi(/yib di(/dib ci(/cib yT( yt)
{}-Block yi{/yiB di{/diB ci{/ciB yT{ yt}
[]-Block yi[ di[ ci[ yT[ yt]
<>-Block yi< di< ci< yT< yt>
Zwischen HTML-/XML-Tags yit dit cit yT> yt<
String in " yi" di" ci" yT" yt"
Zeile yy/Y dd cc/S y0 y$

Einfügen

Der zuletzt kopierte oder ausgeschnittene Text wird mit p nach oder mit P vor dem aktuellen Cursor eingefügt.

Aktionen wiederholen

Eine der besten Funktionen von vim: Jedes Ausschneiden/Löschen, Kopieren, Einfügen, Ändern kann mit . wiederholt werden!

Register

Register sind so etwas wie vim-interne Zwischenablagen. Alles, was mit y, x, d, c oder s kopiert, ausgeschnitten oder ersetzt wird, landet im Standard-Register mit dem Namen ". Text, der mit einem einfachen p oder P eingefügt wird, kommt aus diesem Standardregister. Text, der kopiert wird, kommt zusätzlich ins Register 0. Ausgeschnittener Text kommt ins Register 1, wenn es sich um eine ganze Zeile oder mehr handelt, oder sonst ins Register -. Somit ist der zuletzt kopierte Text noch verfügbar, wenn danach etwas anderes ausgeschnitten wurde. In diesem Fall kann man den zuletzt kopierten Text mit "0p wieder einfügen. (" steht hierbei für einen Zugriff auf ein Register im Allgemeinen und 0 ist der Name des Registers.)

Wenn man Textteile länger benutzen will, kann man sie auch in ein Namensregister (a-z) kopieren. Zum Beispiel kann man die aktuelle Zeile mit "ayy ins Register a kopieren. Einfügen geht dann entsprechend mit "ap.

" letztes Kopieren (yank, y) oder Ausschneiden (x, d, c, s)
0 letztes Kopieren
1-9letztes Ausschneiden (ganze Zeile oder mehr)
- letztes "kleines" Ausschneiden (weniger als eine Zeile)
+ Zwischenablage (System)
/ letzte Suche
% (relativer) Dateiname
# Dateiname der zuvor geänderten Datei

Um Text in die System-Zwischenablage kopieren zu können ("+y...), muss vim mit der Option clipboard kompiliert worden sein. Dies ist der Fall, wenn die Ausgabe von vim --version ein +clipboard enthält. Bei der unter Ubuntu 18.04 vorinstallierten Version von vim ist das nicht der Fall. Dann kann einfach eine vollständigere Version von vim nachinstalliert werden:

sudo apt-get install vim-gtk3

Markierungen

Es kommt immer wieder vor, dass man in einer Datei hin- und herscrollt, etwa um Dinge zu kopieren und woanders wieder einzufügen. Scrollen ist dabei höchst ineffizient. Meistens ist es besser, eine Stelle durch eine kurze Suche zu finden (/xyz) und dann wieder an die Stelle zurückzuspringen, wo man zuletzt war (``) oder wo man zuletzt etwas editiert hat (`.). Wenn es mehrere Stellen gibt, an die man öfter mal springen will, kann man sie auch ausdrücklich markieren: ma (oder m + ein anderer kleiner Buchstabe). Dort hinspringen kann man dann mit `a. Wenn man an den Anfang einer markierten Zeile springen möchte, benutzt man ' + x. Für Markierungen, die dateiübergreifend gelten sollen, benutzt man Großbuchstaben (mA).

Hier die nützlichsten Sprungziele:

KommandoSpringe zur/zum ...
`a Markierung a
`` letzten Sprungmarke (Verlauf: Strgo/Strgi)
`. Position der letzten Bearbeitung (Verlauf: g;/g,)
`[ Beginn des zuletzt kopierten Textes
`] Ende des zuletzt kopierten Textes
`< Beginn der letzten visuellen Textauswahl (mit v/V)
`> Ende der letzten visuellen Textauswahl (mit v/V)

Plugins

Wie die meisten Text-Editoren kann auch vim mit Plugins erweitert werden. Es gibt verschiedene Plugin-Manager, die die Installation und Aktualisierung von Plugins vereinfachen (z.B. vim-plug, Pathogen, Vundle). Ich benutze jedoch nur den eingbebauten Plugin-Manager (verfügbar seit vim8). Dafür installiert man Plugins nach ~/.vim/pack/plugins/start/. Zum Beispiel (in Linux):

mkdir -p ~/.vim/pack/plugins/start/
cd ~/.vim/pack/plugins/start/
git clone https://github.com/ap/vim-buftabline

Plugins, die nicht automatisch beim Start von vim geladen werden sollen, kommen in den Ordner ~/.vim/pack/plugins/opt/. Sie können dann bei Bedarf mit :packadd [Plugin-Name] geladen werden.

Das sind die Plugins, die ich installiert habe und auch wirklich benutze:

vim-buftabline

Zeigt die offenen Buffer (=Dateien) als Tabs an.

Es gibt zwar auch Tabs in vim. Diese haben aber wenig mit Tabs in anderen Text-Editoren zu tun, wo ein Tab eine offene Datei repräsentiert. Siehe auch diese ausführlichen Erläuterungen auf stackoverflow (auf Englisch): Why do Vim experts prefer buffers over tabs?

vim-surround

Führt neue Kommandos ein (y/c/d+s, s=surround), um einen bestimmten Bereich umgebende Sonderzeichen einzufügen/zu ändern/zu löschen.

vim-repeat

Ermöglicht, dass auch Plugin-Kommandos (wie surround) mit . wiederholt werden können.

delimitMate

Fügt automatisch schließende Klammern und Anführungszeichen ein (Alternative: Auto-Pairs). Nervt manchmal, wenn es ungewollte Klammern/Anführungszeichen einfügt. Update: Ich hab es inzwischen wieder deaktiviert (d.h. in den opt-Ordner verschoben).

vim-commentary

Zeilen/Bereiche einfach ein-/auskommentieren.

vim-sneak

Wie f / F + Buchstabe, aber mit s / S + zwei Buchstaben und nicht auf die aktuelle Zeile beschränkt. Das ist viel effizienter, als erst in eine bestimmte Zeile und dann an eine bestimmte Stelle zu springen. Prinzipiell kann man das gleiche auch mit /xy erreichen, aber dafür sind erstens fünf statt drei Tastenanschläge nötig (/ benötigt zwei Tastenanschläge auf einer deutschen Tastatur) und außerdem bleiben dann alle Treffer hervorgehoben (bis man dies ausdrücklich deaktiviert). Mit vim-sneak passiert das automatisch, sobald man den Cursor wieder bewegt. Mit diesem Plugin wird zwar s (=substitute) überschrieben, dieses kann aber auch durch cl ersetzt werden.

vim-mucomplete

In vim gibt es eine Autovervollständigung von Dateinamen mit StrgxStrgf, Autovervollständigung von Code mit StrgxStrgo oder von Worten, die in offenen Dateien enthalten sind, mit Strgp oder Strgn. Das geht noch einfacher mit vim-mucomplete: Damit erfolgen all diese Vervollständigungen mit Tab. Auf Wunsch werden Vorschläge beim Schreiben automatisch eingeblendet.

vim-textobj-line

Ergänzt die vim-Syntax um il und al (l steht hierbei für line). So kann mit yal die aktuelle Zeile, jedoch ohne den Zeilenumbruch kopiert werden. Mit yil wird die aktuelle Zeile ohne führende und abschließende Leerzeichen kopiert. Dieses Plugin benötigt zusätzlich vim-textobj-user.

Update: Inzwischen habe ich die beiden Plugins durch diese Zeilen in meiner .vimrc ersetzt:

" yank, delete or select line without line break
" (replaces plugins vim-textobj-line and vim-textobj-user)
nnoremap yal 0y$
nnoremap yil ^yg_
nnoremap dal 0d$
nnoremap dil ^dg_
nnoremap val 0v$
nnoremap vil ^vg_

vim-css-color

Hinterlegt Farbcodes oder Farbnamen mit der entsprechenden Farbe. Dieses Plugin habe ich im opt-Ordner und aktiviere es nur bei Bedarf.

Tipps

Bei folgenden Tipps handelt es um Einstellungen, die in vims Konfigurationsdatei (i.d.R. ~/.vimrc (Linux) oder %HOME%/_vimrc (Windows)) eingetragen werden. Meine komplette .vimrc kann in meinem dotfiles-Repo auf GitHub eingesehen werden.

Schnelles Speichern

Man sollte lieber einmal zu oft als einmal zu wenig Zwischenstände abspeichern. Andauernd :w zu tippen ist lästig. Auf einer deutschen Tastatur sind das vier Tastenanschläge (für : benötigt man zwei). Ich habe mir diese Funktion auf Leertastew gelegt:

" save file
let mapleader="\<Space>"
noremap <Leader>w :w<cr>

Zwischenablage

Oft will man etwas kopieren und außerhalb vom vim einfügen. "+y ist umständlich zu tippen. Leertastey geht deutlich einfacher (gleiches gilt für d, p und P):

" yank/cut/paste to/from system clipboard
noremap <Leader>y "+y
noremap <Leader>d "+d
noremap <Leader>p "+p
noremap <Leader>P "+P

Black Hole Register

Manchmal schneide ich Text mit d... aus, merke dann, dass ein Leerzeichen zu viel übrig geblieben ist und lösche es mit x. Wenn ich dann den Text woanders wieder einfügen will, erhalte ich nur das danach gelöschte Leerzeichen, weil das Leerzeichen gar nicht gelöscht, sondern ebenfalls ausgeschnitten wurde und den zuvor ausgeschnittenen Text in den Registern " und - überschrieben hat. Wenn man etwas wirklich löschen will, kann man dafür das sogenannte Black-Hole-Register _ verwenden, also z.B. "_x. Vier Tastenanschläge um ein Zeichen zu löschen ist jedoch ein absolut unverhältnismäßiger Aufwand. Deshalb benutze ich für x standardmäßig das Black-Hole-Register. Wenn ich doch mal ein einzelnes Zeichen ausschneiden möchte, kann ich immer noch dl verwenden.

" delete not into register with x (use dl for cutting one character into register)
nnoremap x "_x

; und , tauschen

Die Kommandos f, F, t und T kann man mit ; wiederholen. Mit , wird die gleiche Suche in entgegengesetzte Richtung wiederholt. Letzteres wird deutlich seltener benötigt. Aber leider liegt das Semikolon auf deutschen Tastaturen auf der zweiten Ebene und ist daher umständlicher zu tippen. Deshalb habe ich Komma und Semikolon vertauscht. (Das gilt natürlich nicht im Eingabemodus.)

" swap ; and , (next/previous match after t, T, f, F)
nnoremap ; ,
nnoremap , ;
vnoremap ; ,
vnoremap , ;

Wer das Plugin vim-sneak benutzt, möchte vermutlich auch da Komma und Semikolon vertauschen:

" swap ; and , (next/previous match after s, S)
nmap ; <Plug>SneakPrevious
nmap , <Plug>SneakNext
vmap ; <Plug>SneakPrevious
vmap , <Plug>SneakNext

Ein geöffnetes Python-Skript direkt aus vim heraus ausführen

Wenn man mit vim ein Python-Skript entwickelt, will man nicht immer in die Konsole wechseln, um das Skript zu testen. Mit folgenden Mappings kann man mit Leertastex das aktuelle Skript bzw. im Visual-Modus die aktuelle Auswahl mit Python 3 ausführen. Die Besonderheit hierbei ist, dass das Skript inklusive ungespeicherter Änderungen ausgeführt wird, die Änderungen aber nicht abgespeichert werden. (:w speichert in diesem Fall nicht, sondern streamt den Inhalt des aktuellen Buffers an den Python-Interpreter. Quelle: stackoverflow)

" execute file in python 3
autocmd FileType python nnoremap <Leader>x :w !python3
" execute selection in python
autocmd FileType python xnoremap <Leader>x :w !python3

HTML-Datei im Browser öffnen (Linux)

Mit der folgenden Konfiguration wird die aktuelle Datei nach Leertasteo mit dem Standard-Programm geöffnet (also z.B. eine HTML-Datei im Standard-Browser):

" open file with xdg-open
nnoremap <Leader>o :!xdg-open % &<cr>

Dateimanager mit vim-Keybindings

ranger

Firefox/Chrome mit vim-Keybindings/vim in Textareas im Browser

surfingkeys

Tipps von Bram Moolenaar (dem Entwickler von vim)

https://www.moolenaar.net/habits.html