Über hjkl (Zeichen), w/b (Wort) und 0/$ (Zeile) hinaus hat Vim eine eigene Familie semantischer Motions — Sprünge, die strukturelle Einheiten des Texts erkennen. Ein Satz endet in Vim an ., ! oder ? (gefolgt von Whitespace); ein Absatz an einer Leerzeile; eine Top-Level-Section bei C-artigem Code an einer geschweiften Klammer in Spalte 1; eine Methode bei den meisten Sprachen an der Methode-Signatur. Diese Motions sind oft die schnellste Variante, um sich strukturell im Code oder in Prosa zu bewegen — fünf Absätze nach unten in einer Markdown-Datei ist 5}, zur nächsten Funktion in einer C-Datei ist ]]. Dieser Artikel deckt vier Motion-Familien ab, zeigt typische Operator-Kombinationen und erklärt die Grenzen — welche Filetypes sie sauber unterstützen und welche nicht.
Sätze: ( und )
Vims Satz-Motions springen zwischen Satz-Grenzen. Ein Satz endet in Vims Definition an einem Punkt, Ausrufezeichen oder Fragezeichen, gefolgt von einem Zeilenende oder einem oder mehreren Leerzeichen.
| Taste | Bewegung |
|---|---|
| ( | zum Anfang des aktuellen oder vorherigen Satzes |
| ) | zum Anfang des nächsten Satzes |
Buffer: Das ist Satz eins. Das ist Satz zwei! Und Satz drei? Vier.
^
Cursor am Zeilenanfang (Buchstabe D von "Das"):
) → Cursor auf "D" von "Das ist Satz zwei!"
) → Cursor auf "U" von "Und Satz drei?"
) → Cursor auf "V" von "Vier."
( → einen Satz zurückIm Code-Workflow sind die Satz-Motions selten direkt nützlich (Code besteht meist nicht aus „Sätzen"), in Markdown- und Prosa-Workflows aber zentral: ein einzelner ( oder ) springt präzise zwischen Sätzen, ohne die Zeile zu kennen.
Absätze: { und }
Die Absatz-Motions sind nützlicher und vielseitiger. Ein Absatz endet bei einer Leerzeile.
| Taste | Bewegung |
|---|---|
| { | zum Anfang des aktuellen oder vorherigen Absatzes |
| } | zum Ende des aktuellen Absatzes (= nächste Leerzeile) |
Buffer: Erster Absatz mit
zwei Zeilen.
← Leerzeile = Absatz-Grenze
Zweiter Absatz.
← Leerzeile
Dritter Absatz, der
sich über drei
Zeilen erstreckt.
Cursor in Zeile 1:
} → Cursor auf die Leerzeile nach "zwei Zeilen."
} → Cursor auf die Leerzeile nach "Zweiter Absatz."
} → Cursor auf die letzte Zeile (oder Leerzeile danach)
{ → einen Absatz zurückCounts funktionieren: 5} springt fünf Absätze weiter. In langen Markdown-Dateien oder strukturiertem Plain-Text ist das die effizienteste Navigations-Form überhaupt — schneller als Page Down, präziser als zählen mit j.
Operator-Kombinationen mit Absatz-Motions sind sehr alltäglich:
| Befehl | Aktion |
|---|---|
d} | lösche bis zum Absatz-Ende (vom Cursor bis nächste Leerzeile) |
y} | kopiere bis Absatz-Ende |
c} | ändere bis Absatz-Ende |
>} | rücke Absatz ein (vom Cursor abwärts) |
gq} | reformatiere bis Absatz-Ende |
dap | lösche around paragraph (Text-Object — siehe Kapitel 8) |
dip | lösche inner paragraph |
gqap (reformatiere den ganzen Absatz) ist beim Schreiben von Markdown- und Code-Kommentaren ein Klassiker — Vim umbricht den Absatz auf die textwidth-Spalte.
Top-Level-Sections: [[, ]], [], ][
Bei C-artigen Sprachen (C, C++, Java, Go, Rust, JavaScript) erkennt Vim Top-Level-Funktions-Definitionen an einer öffnenden geschweiften Klammer in Spalte 1. Vier Motions navigieren zwischen ihnen:
| Taste | Bewegung |
|---|---|
| [[ | rückwärts zum Anfang der vorigen Top-Level-Section |
| ]] | vorwärts zum Anfang der nächsten Top-Level-Section |
| [] | rückwärts zum Ende der vorigen Top-Level-Section |
| ][ | vorwärts zum Ende der aktuellen oder nächsten Top-Level-Section |
Buffer (C-Code):
int foo() {
return 1;
}
← Leerzeile
int bar() {
return 2;
}
← Leerzeile
int baz() {
return 3;
}
Cursor irgendwo in foo():
]] → Cursor auf "int bar()" (Anfang der nächsten Top-Level-Funktion)
]] → Cursor auf "int baz()"
[[ → einen Schritt zurück (zu "int bar()")
][ → ans Ende der aktuellen Section (`}` von bar)Das funktioniert allerdings nur, wenn die öffnende Klammer in Spalte 1 steht — die ältere C-Stil-Konvention. Bei moderneren Stilen, wo die Klammer am Funktionsnamen klebt (int foo() { ohne Newline davor), greifen [[/]] nicht wie erwartet. Für moderne Sprachen sind die Method-Motions ([m/]m, nächster Abschnitt) zuverlässiger.
Methoden: [m, ]m, [M, ]M
Die Method-Motions sind die moderne, sprach-übergreifende Variante:
| Taste | Bewegung |
|---|---|
| [m | rückwärts zum Anfang der vorigen Methode |
| ]m | vorwärts zum Anfang der nächsten Methode |
| [M | rückwärts zum Ende der vorigen Methode |
| ]M | vorwärts zum Ende der aktuellen oder nächsten Methode |
Im Default funktionieren diese vier Motions für Sprachen mit der C-typischen { }-Blockstruktur — Java, JavaScript, Go, C#, Kotlin, Rust und ähnliche. Vim erkennt die nächste Block-Öffnung als „Methoden-Start" und springt dorthin.
Buffer (JavaScript):
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}`;
}
farewell() {
return "Bye";
}
}
Cursor in constructor:
]m → Cursor auf "greet()" (Anfang der nächsten Methode)
]m → Cursor auf "farewell()"
[m → einen Schritt zurück
]M → Ende der aktuellen Methode (`}`)Für Sprachen ohne { }-Block-Struktur (Python, Ruby, Lua, Haskell, Lisp) funktionieren die eingebauten Method-Motions nicht zuverlässig — sie brauchen filetype-spezifische Plugins oder Tree-sitter-basierte Motions (siehe Plugin-Hinweis weiter unten).
% — die Match-Klammer-Motion
Eine verwandte, aber eigenständige Motion: % springt zwischen passenden Klammern:
| Cursor auf | Sprung mit % zu |
|---|---|
( | passendem ) |
) | passendem ( |
[ | passendem ] |
{ | passendem } |
/* … */ | Kommentar-Anfang / -Ende |
#if/#endif | passendem Präprozessor-Block (in C) |
% ist die schnellste Variante, um durch verschachtelte Strukturen zu navigieren: in einer JSON-Datei mit drei Ebenen Verschachtelung springt % von der äußeren { direkt zur passenden } am Ende — egal wie weit dazwischen.
Mit Operatoren ergibt das mächtige Edits:
" Cursor auf der äußeren { eines JSON-Objekts
d% " lösche das gesamte Objekt von { bis }
y% " kopiere die gesamte Klammer-Region
v% " markiere die gesamte Region für weitere OperationDas matchit-Plugin (in modernen Vim-Versionen Default) erweitert % auf zusätzliche Paare wie HTML-Tags, if/endif, do/end, def/end etc. — sprach-spezifisch und sehr nützlich.
Tree-sitter-basierte Funktions-Motions für Vim
Vims eingebaute Method-Motions sind C-artig und decken Python, Ruby, Lisp und Co. nicht ab. Für sprachbewusste Funktions-Sprünge gibt es zwei Plugin-Wege:
vim-textobj-function
vim-textobj-function definiert Text-Objects if und af (inner/around function), die das gesamte Funktions-Konstrukt als Bereich verstehen — egal in welcher Sprache (mit installierten Sprach-Definitionen). Damit funktionieren Befehle wie:
daf " delete around function (komplette Funktion)
cif " change inner function (Funktions-Körper)
yaf " yank around functioncoc-pyright / sprach-spezifische LSP-Plugins
Wer ohnehin coc.nvim für LSP nutzt, hat über <Plug>(coc-funcobj-i)/<Plug>(coc-funcobj-a) und ähnliche LSP-basierte Motions Zugriff auf semantische Funktions-Sprünge — auf Basis des LSP-Servers, also sprach-genau. Die Konfiguration:
" coc.nvim Funktions-Objekt-Mappings (klassisch i und a)
xmap if <Plug>(coc-funcobj-i)
omap if <Plug>(coc-funcobj-i)
xmap af <Plug>(coc-funcobj-a)
omap af <Plug>(coc-funcobj-a)Damit kann daf in Python eine Funktion löschen, in Ruby eine def/end-Region und in Lisp ein defun-Konstrukt — alles über dieselbe Tastenkombination.
Wann welche Motion
Eine Faustregel zur Wahl:
| Aufgabe | Beste Motion |
|---|---|
| In Prosa zum nächsten Satz | ) oder ( |
| In Markdown zum nächsten Absatz | } (oder { rückwärts) |
| Zur nächsten Methode in JavaScript/Go/Java | ]m |
| Zur nächsten Top-Level-Funktion in C (Klammer in Sp 1) | ]] |
Innerhalb eines Code-Blocks zur passenden } | % |
| In Python zur nächsten Methode | Plugin (coc-funcobj, treesitter-textobjects in Neovim) |
| Über mehrere Zeilen einen Bereich auswählen | vap (Absatz) oder vi{ (innerhalb Block) |
Wer in einer Sprache arbeitet, deren Method-Motions eingebaut funktionieren, hat in vier Tasten (]m, [m, ]], [[) eine schnelle Navigation. Für andere Sprachen lohnt sich die einmalige Plugin-Installation.
Praxis-Workflows
Drei typische Anwendungs-Szenarien:
Workflow 1: Markdown-Datei strukturell durchgehen
" Lange Markdown-Datei mit vielen Absätzen
gg " an den Anfang
} " zum Ende des ersten Absatzes (= Leerzeile)
} " zum nächsten Absatz-Ende
} " weiter
" ... oder direkt:
5} " fünf Absätze nach untenSchneller als <C-d> (halbe Seite) und präziser als j × 20.
Workflow 2: Eine Funktion löschen und woanders einfügen
" JavaScript-Datei: Funktion soll an eine andere Stelle
" Cursor irgendwo in der Funktion
[m " zum Anfang der Methode springen
v]M " visual bis ans Ende der Methode markieren
d " löschen (landet im Register)
" ... zum Ziel navigieren ...
p " einfügenVier Tasten zum Markieren der ganzen Funktion, ohne mit Visual-Block oder Zeilennummern zu hantieren.
Workflow 3: Klammer-Block reformatieren
" Cursor auf der öffnenden { eines Code-Blocks
v% " visual bis zur passenden }
= " auto-indent — Vim formatiert den Block neu
" oder als Single-Operator:
=% " auto-indent bis zur Match-Klammer (ohne Visual-Zwischenschritt)=% ist eine der unterschätztesten Vim-Kombinationen — formatiert einen ganzen verschachtelten Block in zwei Tasten.
Interessantes
Satz-Grenzen werden über Punctuation erkannt
Vims Definition: ein Satz endet an ., ! oder ?, gefolgt von einem oder mehreren Leerzeichen, einem Tab oder Zeilenende. Zwei Punkte hintereinander („…") oder ein Punkt direkt vor einem Wort (Abkürzung wie „z.B.") werden teilweise als Satz-Grenze erkannt. Die Option cpoptions (J-Flag) ändert das Verhalten leicht.
Absatz-Grenzen sind robuster als Satz-Grenzen
{/} arbeiten ausschließlich an Leerzeilen — eindeutig, ohne Punctuation-Heuristik. Das macht sie sehr zuverlässig, egal welche Sprache oder welcher Filetype. In Markdown, YAML, structured Plain-Text und sogar in vielen Code-Files (Leerzeilen zwischen Funktionen) sind sie die robusteste strukturelle Navigation.
`]]` braucht öffnende Klammer in Spalte 1
Vims Default für die Top-Level-Section-Motion ist eine geschweifte Klammer in der ersten Spalte. Moderne C/Java/Go-Stile, die function foo() { mit dem { am Ende der Signatur schreiben, brechen diese Heuristik. Für solche Stile sind ]m/[m die zuverlässigeren Alternativen.
`%` mit matchit-Plugin lernt sprach-spezifische Paare
Ohne matchit (in modernen Vim-Versionen Default-aktiv) erkennt % nur die Standard-Paare ()/[]/{}. Mit matchit zusätzlich HTML-Tags, if/endif, do/end, <script>/</script> und viele weitere. Wer prüfen will, ob matchit aktiv ist: :packadd matchit oder im neuesten Vim einfach % auf einer HTML-Tag-Klammer testen.
Counts auf semantische Motions
5} springt fünf Absätze, 3]m zur drittfolgenden Methode, 2[[ zwei Top-Level-Sections zurück. Counts auf semantischen Motions sind im Alltag sehr nützlich — sie erlauben Sprünge, die mit Zeichen- oder Wort-Motions umständlich wären.
Tree-sitter-Motions (in Neovim) sind die moderne Variante
Neovim mit nvim-treesitter-textobjects hat sprach-bewusste Funktions-, Klassen-, Argument- und Parameter-Motions, die in allen unterstützten Sprachen sauber funktionieren. In reinem Vim 9 sind Plugin-Lösungen wie vim-textobj-function oder coc-Funcobj-Mappings der Pfad — weniger universell, aber für die wichtigsten Sprachen ausreichend.
Weiterführende Ressourcen
Externe Quellen
- Vim Help: object-motions — semantische Motions in der Übersicht.
- Vim Help: sentence — Satz-Definition und -Motion.
- Vim Help: paragraph — Absatz-Motion.
- Vim Help: section —
[[und Co. - Vim Help: % — Match-Klammer-Motion.
- Vim Help: matchit — Plugin-Aktivierung.
- kana/vim-textobj-function — sprach-übergreifende Funktions-Text-Objects.