vi Key Binding Support Reference

This document describes the vi key binding support implemented in BBEdit, starting with version 16.0.
It is a reference for the current implementation, not a promise of complete vi/vim
compatibility.

General Model

Area Current behavior
Feature switch Vi handling is active only when the global key binding emulation is set to vi in BBEdit’s Keyboard preferences.
Initial enabled state The first vi-handled key changes Disabled to Normal.
Host shortcuts Cmd modified keystrokes bypass vi handling.
Host key bindings Default key binding selectors and normal menu commands are separate from the vi parser; this table focuses on vi-parsed input.
Control keys In command modes, control keys bypass vi handling except Esc/Ctrl-[, Ctrl-R, and Ctrl-V.
Counts Digits build a command count. 0 is a motion when there is no pending count/operator; otherwise it extends the count.
Unknown command Beeps and resets pending vi input/state.
Repeat model . replays the stored repeatable vi input sequence. This is simpler than full Vim repeat semantics.

Modes

Mode Entered by Leaves by Caret kind
Normal Esc from insert/visual/replace, or vi initialization i, a, I, A, o, O, R, v, V, Ctrl-V, :, /, ? Block
Insert i, a, I, A, o, O, c/visual change, C, cc Esc or Ctrl-[ Insertion point
Replace R Esc or Ctrl-[ Underline
Visual v v, Esc, visual operation, mode switch Block
Visual Line V V, Esc, visual operation, mode switch Block
Visual Block Ctrl-V Ctrl-V, Esc, visual operation, mode switch Block
Command-line :, /, ? Return/Enter to execute, Esc to cancel Existing mode caret

Normal Mode Motions

Most motions accept a count. In Visual modes, the same motion subset extends or
adjusts the active visual selection.

Key Action
h, Left Arrow Move left one character.
j, Down Arrow Move down one line.
k, Up Arrow Move up one line.
l, Right Arrow Move right one character.
w Move forward by word using the host Option-Right behavior.
b Move backward by word using the host Option-Left behavior.
e Move to the end of the current/next word.
0 Move to hard line start.
^ Move to first non-blank character on the hard line.
$ Move to hard line end.
gg Move to the first line, or to [count] line.
G Move to the last line when no count is supplied, or to [count] line.
( Move to previous sentence start using BBEdit’s vi sentence heuristic.
) Move to next sentence start using BBEdit’s vi sentence heuristic.
% Jump to a matching delimiter for (), [], {}, curly quotes, and single curly quotes.

Motion Notes

Topic Note
Hard vs soft lines Line-number motions use hard lines unless soft wrapping line numbers are configured otherwise.
G with operators Operator motions preserve a missing count as zero, so dG/cG mean “to end of file” while d1G/c1G mean “to line 1”.
Sentence motions ( and ) use punctuation/whitespace heuristics. They are useful, but not a full clone of Vim’s sentence parser.
Visual Line horizontal motion h/l move the hidden visual cursor within the current hard line. They do not wrap across hard line boundaries.

Find And Search

Key or command Action
f<char> Find <char> forward on the current hard line.
F<char> Find <char> backward on the current hard line.
t<char> Find forward until just before <char> on the current hard line.
T<char> Find backward until just after <char> on the current hard line.
; Repeat the last f/F/t/T in the same direction.
, Repeat the last f/F/t/T in the opposite direction.
/pattern<Return> Run a forward literal find through BBEdit’s find system.
?pattern<Return> Run a backward literal find through BBEdit’s find system.
n Find again.
N Find again backwards.

Normal Mode Edits

Key Action
i Enter Insert mode at the current caret.
a Move right one character, then enter Insert mode.
I Move to first non-blank on the hard line, then enter Insert mode.
A Move to hard line end, then enter Insert mode.
o Move to hard line end, insert a line break below, then enter Insert mode.
O Move to hard line start, insert a line break above, then enter Insert mode.
R Enter Replace mode.
x Forward delete, repeated by count.
X Backspace/delete backward, repeated by count.
r<char> Replace up to count non-line-ending characters with <char>.
p Paste, repeated by count.
P Move left, then paste, repeated by count.
J Join lines when count is greater than one. Plain J is currently accepted but does not join.
u Undo through BBEdit’s undo command.
Ctrl-R Redo through BBEdit’s redo command.
. Replay the last stored repeatable vi input sequence.

Operators

Operators enter a pending state and apply to the next supported motion or
special operator command.

Operator With motion Repeated key form Visual selection form
d Cut text covered by the motion. Examples: dw, d$, dG, dg. dd cuts current line, repeated by count. d cuts selection and returns to Normal.
c Cut text covered by the motion, then enter Insert. Examples: cw, c$, cG, cg. cc cuts current line, then enters Insert. c cuts selection, then enters Insert.
y Copy text covered by the motion. Examples: yw, y$, yG, yg. yy copies current line, repeated by count. y copies selection and returns to Normal.
> Shift right/indent text covered by the motion. >> shifts current line/right selection, repeated by count. > shifts selection right.
< Shift left/outdent text covered by the motion. << shifts current line/left selection, repeated by count. < shifts selection left.

Operator Shortcuts

Key Action
D Delete from caret to hard line end. If at an empty line end, delete the line break when possible.
C Delete from caret to hard line end, then enter Insert mode.
Y Copy the current line.

Visual Modes

Key Visual Visual Line Visual Block
Esc, Ctrl-[ Return to Normal and collapse selection. Same. Same.
v Toggle back to Normal. Switch to characterwise Visual. Switch to characterwise Visual.
V Switch to Visual Line. Toggle back to Normal. Switch to Visual Line.
Ctrl-V Switch to Visual Block. Switch to Visual Block. Toggle back to Normal.
Motions Characterwise selection. Whole hard-line selection. Rectangular selection range.
d Cut selection, return to Normal. Same. Same, using rectangular selection ranges.
c Cut selection, enter Insert. Same. Same, using rectangular selection ranges.
y Copy selection, return to Normal. Same. Same, using rectangular selection ranges.
> Shift selection right. Same. Same command on active selection.
< Shift selection left. Same. Same command on active selection.
p, P Paste over selection, return to Normal. Same. Same command on active selection.

Visual Mode Notes

Topic Note
Visual Line cursor The implementation tracks a hidden visual cursor separately from the whole-line selection.
Visual Block cursor The implementation tracks both text offset and horizontal column, so block selections can cross shorter or empty lines.
Visual Block range list Rectangular selections are applied through existing support.
Block insert/append Vim-style block I/A is not implemented.

Command-line And Ex Commands

Command-line mode is entered by :, /, or ?. Printable characters append
to pending vi input; Backspace removes the last pending character; Return or
Enter executes; Esc cancels.

Command Action
:w Save.
:q Close document.
:q! Close without saving when possible.
:wq Save, then close.
:x Save, then close.
:noh Clear quick-search and live-match highlights.
:<line> Go to one-based line number.
:$ Go to last line.
:+N Move forward N lines, clamped to document bounds. :+ means :+1.
:-N Move backward N lines, clamped to document bounds. :- means :-1.
/pattern Literal forward search.
?pattern Literal backward search.

Replace Mode

Key Action
Printable character Replace the character at the caret when not on a line ending. At line end, insert before the line break.
Esc, Ctrl-[ Return to Normal and remember the replace input as repeatable.
Other keys Passed through to the existing text-view key handling.

Counts

Form Current behavior
[count]motion Repeats the motion or uses the count as a line number for G/gg.
[count]edit Repeats simple edits such as x, X, p, P, and ..
[count]operator motion The pending operator uses the stored count when no separate motion count is present.
operator [motion-count] motion Digits after an operator and are used by the motion/operator.
Missing count Most commands normalize missing count to 1; G motions preserve missing count as “last line”.
Operator g In operator-pending mode, a single g is the first-line motion. Normal mode still requires gg.

Known Non-goals And Gaps

Area Status
Registers Not implemented.
Marks Not implemented.
Macros/recording Not implemented.
Remapping Not implemented.
Text objects Not implemented.
Full Vim search language Search entry uses BBEdit literal find setup.
Full Vim sentence parser Not implemented; practical heuristics are used.
Full Vim repeat semantics Not implemented; repeat replays stored vi input.
Block insert/append Not implemented.
Operator gg spelling Not implemented as a two-key operator motion; use g for the first-line operator motion.
Plain J behavior Accepted but currently no-op unless a count greater than one is supplied.
Plug-ins/extensions Not planned.

Back to Technical Notes