VIM-Meister seine Notizen

Florian Stöhr

Modes

Normal mode

Counter können vor Kommandos kommen:

10<C-a> -> Integer +10  
10<C-x> -> Integer -10  
10dw oder d10w -> 10 Worte löschen  

Die letzte Position kann mit <C-o> angesprungen werden, dann wieder vorwärts mit <C-i>.

Einfache Kommandos wiederholen mit .. Komplexe Kommandos (genaugenommen "Letzte Kommandozeile", etwa search/replace) kann man mit @: und danach mit @@ wiederholen.

Insert mode

Korrekturen im Insert-Mode:

<C-h> -> Backspace
<C-w> -> Wort löschen
<C-u> -> Zeile löschen

Insert-Normal-Mode:

Um ein EINZELNES Normal-Kommando im Insert-Mode zu machen, <C-o>

Register

Register direkt einfügen:

<C-r><reg>, z.B. <C-r>0

Berechnungen mit dem Expression-Register:

<C-r>=

Das kann komplette Skripts, aber auch einfache Rechnungen machen.

Sonderzeichen

Numerische Codes über 'ga' auf einem Zeichen herausfinden.

Einfügen:

<C-v>{123}      -> Einfache Zeichen
<C-v>u{1234}    -> Unicode
<C-v>{nondigit} -> Direkt einfügen
<C-k>{dg}{dg}   -> Digraph

Digraph '?I' macht '¿' beispielsweise. Übersicht unter ':h digraph-table'

Visual mode

v     -> Zeichenweise selektieren. Optional Motion wie etwa 'iw'
V     -> Zeilenweise selektieren
<C-v> -> Blockweise selektieren
o     -> An anderes Ende wechseln
b,e,  -> Selektion ausdehnen/schrumpfen
u     -> In Kleinbuchstaben wandeln
U     -> In Großbuchstaben wandeln

Der '.' funktioniert auch dann noch, wenn die Auswahl nicht mehr besteht. Allerdings wird die gleiche Textlänge bearbeitet - Vorsicht bei Auswahl von 'it' beispielsweise. Ggf. besser Normal-Mode-Kommandos verwenden.

Wird im Blockmodus mit c was geändert, wird die Änderung nach <ESC> auf alle Zeilen angewendet. Für A funktioniert das auch, wenn die Zeilen unterschiedlich lang sind (z.B. ';' an mehrere Zeilen anhängen).

Auch mit visueller Auswahl kann man mit * und / suchen und die Auswahl vergrößern.

Tabellen bearbeiten

Spalte markieren (z.B. <C-v>3j). Dann mit '|' füllen via r|. Trennzeile beispielsweise mit V (Zeile markieren), dann r- um alle Buchstaben mit '-' zu ersetzen.

Bestimmten Offset mit <pos>| anspringen.

Command-Line mode

Hilfe über ':h ex-cmd-index'.

Hier die Kommandos, die direkt Text bearbeiten:

:[range]d(elete) [x]        Zeilen löschen (nach Register x)
:[range]y(ank) [x]          Zeilen kopieren (nach Register x)
:[line]pu(t) [x]            Inhalt von Register x einfügen
:[range]co(py)/t {address}  Zeilen unter Adresse einkopieren
:[range]m(ove) {address}    Zeilen unter Adresse verschieben
:[range]j(oin)              Zeilen joinen
:[range]norm(al) {commands} Normal-Kommandos für jede Zeile ausführen
:[range]s/pat/replace/flags Ersetzen
:[range]g/pat/cmd           Kommando für alle passenden Zeilen ausführen

Der [range] kann bestehen aus

Normal-Mode-Kommandos über range ausführen

Kommandos können über :norm . nach Markieren eines Ranges wiederholt werden. Natürlich geht auch beispielsweise 13,26norm A; oder %norm I//.

Ex-Kommandos komplettieren

Analog zur Shell mit <Tab>. Ein <C-d> zeigt Vorschläge an. Beispielsweise Eingabe von col<Tab> wird irgendwann bei colorscheme landen. Ein ' ' und <C-d> zeigt die verfügbaren Farbschemata an. Das ist kontextsensitiv. Bei einem Kommando, welches einen Pfad erwartet, wird <C-d> Dateinamen anzeigen.

Aktuelles Wort einfügen

Mit <C-r><C-w> wird das aktuelle Wort in der Commandline eingefügt. Soll ein WORT genommen werden (alles bis zum nächsten non-blank), <C-r><C-a>.

History

History über q: für Ex-Commands oder q/ für Suchkommandos. Aus der Kommandozeile heraus über <C-f> aufrufen.

Shell

:shell                      Shell starten
:!{cmd}                     Kommando ausführen
:r(ead) !{cmd}              Kommando ausführen, Ausgabe laden
:[range]w(rite) !{cmd}      Kommando w/ [range] als Eingabe
:[range]!{filter}           Abschnitt [range] durch Kommando filtern

Files

Buffer

:ls                         Alle buffer anzeigen
:bn(ext)                    Nächster Puffer
:bp(revious)                Voriger Puffer
:b[n]                       Auf Puffer [n] schalten
:bd(elete)[n]               Puffer [n] löschen, default=Aktiver Puffer
:bufdo {cmd}                Kommando auf alle Puffer anwenden. Mehrere
                            Kommandos durch '|' voneinender trennen.

Argumentenlisten

:args                       Zeigt aktuelle Argumente an
:args {list}                Liste neu setzen
:args `shellstuff`          Liste mit Ausgabe von Shell-Kommando füllen
:n(ext)                     Nächste Datei
:prev(ious)                 Vorherige Datei
:argdo {cmd}                Kommand auf alle Dateien anwenden. Mehrere
                            Kommandos durch '|' voneinender trennen.

Globs können verwendet werden. *.xy nimmt aktuelles Verzeichnis, **/*.xy arbeitet rekursiv. Es können auch mehrere angegeben werden:

:args **/*.asm **/*.c

Symbole

%                           Aktiver Pfad mit Dateinamen
%:h                         Nur Directory des aktiven Pfads

Windows

<C-w>s                      Horizontal splitten
<C-w>v                      Vertikal splitten
:sp(lit) {file}             Horizontal splitten und Datei laden
:vsp(lit) {file}            Vertikal splitten und Datei laden
:cl(ose)                    Fenster schließen
:on(ly)                     Alle anderen Fenster schließen

<C-w>w/<C-w><C-w>           Durchrotieren
<C-w>h                      Links
<C-w>j                      Unten
<C-w>k                      Oben
<C-w>l                      Rechts

<C-w>=                      Höhe/Breite überall gleich einstellen
<C-w>_                      Höhe maximieren
<C-w>|                      Breite maximieren
[N]<C-w>_                   Höhe auf [N] Zeilen
[N]<C-w>|                   Breite auf [N] Spalten

Tabs

Tabs sind wie Workspaces - jede kann ihre eigenen Split-Windows haben.

:tabe(dit) {file}           Neuen Tab erzeugen, optional mit Datei
:tabn(ext)                  Nächster Tab, auch <C-PgDn>
:tabp(revious)              Vorheriger Tab, auch <C-PgUp>
:tabm(ove) [N]              Tab nach [N] schieben. 0 = Anfang, kein N = Ende

File explorer

:e.                         Explorer für aktives Directory öffnen
:E                          Explorer für Directory des aktiven Puffers öffnen

Schnell navigieren

Motions

Hilfe unter ':h motion.txt'.

Die Kommandos h,j,k,l,0,$ arbeiten mit "echten" Zeilen. Wird ein g vorangestellt, arbeiten sie mit "angezeigten" Zeilen.

Zusätzlich gibt's das:

w                           Nächstes Wort, Anfang
W                           Nächstes WORT (alles bis blank, inkl z.B. '.')
b                           Voriges Wort, Anfang
B                           Voriges WORT
e                           Ende vom Wort
E                           Ende vom WORT
ge                          Ende vom vorigen Wort
gE                          Ende vom vorigen WORT

f{ch}                       Nächstes Vorkommen von {ch}
F{ch}                       Voriges Vorkommen von {ch}
t{ch}                       Zeichen VOR nächstem Vorkommen von {ch}
T{ch}                       Zeichen VOR vorigem Vorkommen con {ch}
;                           Suche wiederholen
,                           Suche wiederholen (rückwärts)

Das Suchkommando / kann auch verwendet werden. Im Visual Mode ebenfalls, also markieren und das ende per Suchkommando anspringen.

Löschen geht noch schneller mit d/<search>., weil das Suchziel selbst nie mit eingeschlossen wird. Geht auch für v, y, ...

Präzise Textobjekte

a)                          Paar von ()
i)                          Innerhalb von ()
a}                          Paar von {}
i}                          Innerhalb von {}
a]                          Paar von []
i]                          Innerhalb von []
a>                          Paar von <>
i>                          Innerhalb von <>
a'                          Paar von ''
i'                          Innerhalb von ''
a"                          Paar von ""
i"                          Innerhalb von ""
a`                          Paar von `
i`                          Innerhalb von ``
at                          Paar von <xml>tags</xml>
it                          Innerhalb von <xml>tags</xml>

iw                          Aktuelles Wort
aw                          Aktuelles Wort + 1 Leerzeichen
iW                          Aktuelles WORT
aW                          Aktuelles WORT + 1 Leerzeichen
is                          Aktueller Satz
as                          Aktueller Satz + 1 Leerzeichen
ip                          Aktueller Absatz
ap                          Aktueller Absatz + 1 Leerzeile

Generell gilt:
d{motion} zum Löschen -> besser mit a...
c{motion} zum Ändern -> besser mit i...

Markierungen

Manuell

m{a-zA-Z}                   Markierung setzen
'{a-zA-Z}                   Markierung anspringen (Zeile)
`{a-zA-Z}                   Markierung anspringen (Zeile+Spalte)

Kleinbuchstaben gelten pro Puffer. Großbuchstaben gelten global.

Automatisch

``                          Position vor letztem Sprung
`.                          Position der letzten Änderung
`^                          Position des letzten Einfügens
`[                          Start von letzter Änderung oder yank
`]                          Ende von letzter Änderung oder yank
`<                          Start letzter visueller Auswahl
`>                          Ende letzter visueller Auswahl
%                           Passende Klammer
                            Steht Cursor nicht auf der Klammer, wird nach
                            rechts gesucht, bis eine gefunden wird. So kann
                            etwa 'd%' bei 'myfunc(42)' mit dem Cursor am
                            Anfang trotzdem den gesamten Call löschen!

Jumps

[line]G                     Springen zu Zeile
//pattern<CR>               Springen zu Suchbegriff
//?pattern<CR>              Springen zu Suchbegriff, rückwärts
(/)                         Anfang von vorigem/nächstem Satz
{/}                         Anfang von vorigem/nächstem Absatz
H/M/L                       Sprung zu Anfang/Mitte/Ende vom Bildschirm
gf                          Öffnen von Dateiname unter dem Cursor
<F2>                        Keyword unter Cursor aufrufen
%                           Klammer anspringen
'{mark}/`{mark}             Markierung anspringen

Jumps können über <C-o> und <C-i> ausgeführt werden. :jumps zeigt Liste.

Register

Schreibbare Register

"{a-z}                      Normale Register
_                           Black-Hole-Register: '_d' löscht komplett
"0                          Yank-Register, immer letzter ge-yankter Text
"+                          System clipboard
"*                          X11-primary (auch Clipboard bei nicht-X11)
"=                          Expression-Register, z.B. für Berechnungen
""                          Unnamed register

Nur lesbare Register

"%                          Name der aktuellen Datei
"#                          Name der alternativen Datei 
".                          Letzter eingefügter Text
":                          Letztes Ex-Kommando
"/                          Letztes Suchmuster

Registerzugriff

Register mit Ctrl+r+reg einfügen. Kommando :put a fügt Registerinhalt 1:1 ins Dokument ein. Ein "ayy kopiert die ganze Zeile wieder ins Register a zurück.

Um ein Register zu löschen, einfach ein Null-Makro machen, z.B. qaq.

Hinweis: Wird p auf eine Auswahl im Visual Mode angewendet, werden Register und Auswahl vertauscht - sinnvoll zum Wörtertausch!

Register manell kopieren mit :let @<dest>=@<source>, also z.B. :let @+=@a um Register a in die Zwischenablage zu kopieren.

Makros

q[a-z]                      Makro a-z aufnehmen
q[A-Z]                      Kommandos an Makro a-z anhängen
q                           Aufnahme beenden
@[a-z]                      Makro abspielen
@@                          Makro erneut abspielen
:27,42 norm @a              Makro 'a' auf Zeile 27-42 anwenden
3@a                         Makro 'a' 3x anwenden

Makros sind normaler Registerinhalt: reg a zeigt Inhalt von Makro a an.

Makros mit Zählern

  1. Zähler initialisieren mit :let i=0.
  2. Aufnahme starten qa
  3. Zähler einfügen mit <C-r>=i<CR>
  4. Weiterzählen :let i+=1
  5. Beenden q

Patterns

Pattern und Literale matchen

Prefixes im Suchstring

\c                          Groß/Kleinschreibung ignorieren
\C                          Groß/Kleinschreibung erzwingen
\v                          Very magic: alles außer _,digit,letter -> Regex
\V                          Very nomagic: alles außer \ -> verbatim
\%V                         Nur in visueller Auswahl suchen

Submatches

In () eingeschlossenes kann als \1, \2 usw. gefangen werden. Gesamter Match kann über \0 abgerufen werden. Auch ohne Klammern.

()                          Gruppieren und fangen
%()                         Gruppieren OHNE fangen, %(And|D)rew etwa
<                           Wortanfang
>                           Wortende
\zs \ze                     Subset fangen (s->start, e->end):
                            /\v"\zs[^"]+\ze" fängt Text innerhalb von " "

Beispiel /\v(\w+)\_s+\1> fängt doppelte Wörter, auch über Zeilenumbruch hinweg.

Suchen

:s/pattern//gn              Zählt Anzahl der Vorkommen
                            Siehe ':help s_flags' und ':help count-items' 
/pattern/e                  Stellt Cursor ans Ende des Matches. Hier kann
                            beispielsweise mit 'ea<bla>' angehängt werden,
                            dann mit 'n' nächsten Treffer suchen und mit '.'
                            erneut anhängen.
//                          Letzte Suche wiederholen
//e                         Letzte Suche wiederholen, aber Ende anspringen                                

Suche wird im /-Register abgelegt. Also kann es mit <C-r>/ eingefügt oder mit q/ bearbeitet werden.

Patterns können auch als Motion für Kommandos verwendet werden, z.B. gU//e.

Ersetzen

Flags

g                           Mehrmals pro Zeile treffen
n                           Vorkommen zählen
e                           Fehler unterdrücken (multi-file-replace)
c                           Jede Ersetzung bestätigen lassen
&                           Flags vom letzten Lauf verwenden

Spezielle Zeichen im Ersetzungsstring

\r                          CR einfügen
\t                          Tab einfügen
\\                          Einen '\' einfügen
\1                          Ersten Submatch einfügen
...
\0                          Gesamten Match einfügen
&                           Gesamtes gefundenes Pattern einfügen
~                           Ersetzung vom letzen Aufruf verwenden
\={Vim script}              Script auswerten und Ergebnis einfügen

Register entweder über <C-r>{reg} oder mit \=@{reg} einfügen.

Ersetzungskommando über ganze Datei wiederholen

g&                          Via globalem Kommando
:%&&                        Letzte Ersetzung wiederholen, mit letzten Flags
:%s//~/&                    Via Ersetzungskommando

Arithmetik bei Ersetzungen

Beispiel: <h2>/</h2> -> <h1>/</h1> usw. generisch. Es wird nach dem Tag gesucht, dann wird via \zs der Start des Matches auf die Ziffer gelegt:

/\v\<\/?h\zs\d

Anschließend kann via Vim-Skript ersetzt werden:

%s//\=submatch(0)-1/g

Worttausch über Dictionary

Hier sollen die Wörter "man" und "dog" im Text vertauscht werden.
Man kann Dictionaries anlegen, als Zuordnungstabellen:

:let swapper={"dog":"man","man":"dog"}
:echo swapper["man"]  # Gibt "dog" aus usw.

Suchausdruck:

/\v(<man>|<dog>)

Ersetzung:

:%s//\={"dog":"man","man":"dog"}[submatch(1)]/g

Ersetzen in mehreren Dateien:

:args **/*.ttx
:argdo %s/search/replace/ge

Globale Kommandos

Kombiniert Ex-Kommandos mit Pattern-Funktionalität.

:[range]g[!] /{pattern}/ [[range] cmd]
:[range]v /{pattern}/ [[range] cmd]

Der range ist die gesamte Datei (%) im Defaultfall.
Wird :g! oder :v verwendet, werden nur Zeilen bearbeitet, wo das Muster NICHT matcht. Das Default-Kommando ist print.

:g/TODO/                    -> Gibt alle TODO-Zeilen aus
:g/TODO/y A                 -> Alle Zeilen nach '"a' schreiben. Unbedingt
                               hier 'A' und nicht 'a', sonst wird nur die
                               letzte Zeile drin landen. Vorher Register
                               über 'qaq' löschen!

Jeder Pattern-Treffer in :g wird an das Kommando weitergeleitet - welches wieder seinen eigenen Range verwenden kann. Beispiel:

:g/{/.+1,/}/-1 sort

Hier, :g/{/ findet alle Zeilen, die { enthalten. Für das :sort-Kommando wird .+1 als Anfang und /}/-1 als Ende verwendet. Bewirkt also, dass alles, was in {} steht, sortiert wird.

Allgemeines Pattern für sowas:

:g/{start}/ .,{ende} [cmd]

Tools

ctags

Exuberant ctags muss installiert sein. Websuche, die Windows-Version enthält bereits das executable. Unter OSX am besten brew install ctags verwenden.

Ausführen:

:!ctags -R                                      # Direkt
:nnoremap <key> :!ctags -R<CR>                  # Shortcut
:autocmd BufWritePost * call system("ctags -R") # Immer beim Speichern

Verwenden:

<C-]>                       Springt zum Keyword
g<C-]>                      Listenauswahl falls mehrere Treffer
<C-t>                       Rücksprung

Quickfix List

:make     (-> <F9>)         Make ausführen, zu erstem Fehler springen
:make!                      Make ausführen, Cursor bleibt, wo er ist
:copen    (-> <F10>)        Quickfix-Liste öffnen
:cclose   (-> <F11>)        Quickfix-Liste schließen
:[count]cn                  Nächster Eintrag
:[count]cp                  Vorheriger Eintrag
:cfirst                     Erster Eintrag
:clast                      Letzter Eintrag
:cnfile                     Erster Eintrag in nächster Datei
:cpfile                     Letzer Eintrag in vorheriger Datei
:cc N                       Eintrag N anspringen

Natürlich kann man auch in der Liste normal navigieren und mit <ENTER> den aktuellen Eintrag öffnen!

Suchen mit grep, vimgrep etc.

:grep <pattern> *           Führt grep -n aus. Andere Flags können angegeben
                            werden.

Die Variablen grepprg und grepformat steuern das Ganze.
Alternativ kann :vim verwendet werden. Ist langsamer, arbeitet aber mit Vim's regulären Ausdrücken:

:vim[grep][!] /pattern/[g][j] {file}

Flag 'g' -> Mehrere Treffer pro Zeile erlauben
Flag 'j' -> Cursor bleibt, wo er ist
{file} muss angegeben werden. * = Alle Dateien, ** = Alle Dateien rekursiv

Vorsicht beim wiederholen von Suchmustern - hier muß mit <C-r>/ gearbeitet werden, dieses Kommando versteht ein leeres Suchfeld als Wiederholung des letzten Patterns nicht.

Autocomplete

Im Insert-Mode:

<C-n>                       Completion starten
<C-n><C-p>                  Real-time-updating
<C-x><C-f>                  Dateinamen vervollständigen

Im Popup:

<C-p>                       Vorheriges Item, Dokument updaten
<C-n>                       Nächstes Item, Dokument updaten
<Up>                        Vorheriges Item
<Down>                      Nächstes Item
<C-y>                       Akzeptieren
<C-e>                       Abbrechen
<C-h>/<BS>                  Ein Zeichen von Auswahl löschen
<C-l>                       Ein Zeichen hinzufügen

Gibt noch mehr, siehe :h ins-completion.

Wird mit <Up> und <Down> gearbeitet, muss die Auswahl explizit mit <C-y> oder mit <CR> bestätigt werden. Wird dagegen <C-n> oder <C-p> verwendet, kann man einfach weiter tippen.

Wird die Liste mit <C-p><C-n> aufgerufen, kann man das Wort weiter Tippen und es wird real-time gefiltert. Auswahl muss aber immer noch manuell erfolgen.

Rechtschreibprüfung

:set spell                  Spelling einschalten
:set spelllang=de           Sprache festlegen

Im Rechtschreibmodus:

]s (Flo: <F8>)              Nächster Fehler
[s (Flo: <F7>)              Vorheriger Fehler
z=                          Korrektur vorschlagen
zg                          Wort in Liste aufnehmen
zw                          Wort aus Liste entfernen

Im Insert-Modus:

<C-x>s                      Autocompletion für Wort

Tips

Konfiguration neu laden

:so %                       Wenn .vimrc aktuelle Datei ist
:so $MYVIMRC                Wenn nicht

Arbeitsverzeichnis setzen

:cd %:p:h                   Für VIM
:lcd %:p:h                  Neu für aktuelles Fenster

Aktive Datei ausgeben

:echo @%

Find

:(tab)find **/*partialfn    Findet und editiert Datei

Datei umschalten

<Ctrl-6>                    Schaltet zwischen aktiver und letzter Datei um

Relative Zeilennummern

:relativenumber             Schaltet ein. Mit '!' am Ende toggeln.

Man kann z.B. mit "V3+" aktive Zeile + 3 Zeilen danach markieren. Das geht mit den meisten Kommandos. Natürlich immer, aber so kann man direkt die Zeile sehen.