Skip to content

Moving Around

Getting the cursor where you want it is most of editing. HUME's motions are built so the common jumps — a word, a character on this line, a matching bracket, the line you were on a minute ago — are one or two keystrokes away.

All movement happens in Normal mode. Motions move the cursor and change the current selection.

Basic movement

KeyMovement
hOne character left
lOne character right
jOne line down
kOne line up
w/WSelect next word/WORD
b/BSelect previous word/WORD

A word breaks at punctuation, so don't is three words. A WORD only breaks at spaces, so don't is one WORD. Set word-chars (see Configuration) to widen what counts as a word — e.g. - makes foo-bar one word instead of three.

By default, w/W/b/B also cover the whitespace before the destination word — except the first word of a line, which takes its trailing whitespace instead, since a leading run there would be indentation. This means deleting a word never leaves a double space behind. Turn it off with :set global word-selects-whitespace=false (or per buffer) to select just the bare word instead — see Configuration.

Cursor on the first character, press w
default   Lorem ipsum dolor sit
off       Lorem ipsum dolor sit

Character find

Search within the current line for a specific character:

KeyMovement
f + charJump forward to next occurrence of char (inclusive)
F + charJump backward to previous occurrence of char (inclusive)
t + charJump forward to just before next occurrence of char (exclusive)
T + charJump backward to just after previous occurrence of char (exclusive)
=Repeat last find forward
-Repeat last find backward

After pressing f, F, t, or T, HUME waits for the target character. Tab counts as a target character.

Both are jumps, not extends — the selection collapses to a single character at the landing spot, not a span from where the cursor started:

Cursor on the first character, press f i
Lorem ipsum dolor sit

Cursor on the first character, press t i
Lorem ipsum dolor sit

Line movement

The idiomatic line movements live under the g prefix:

KeyMovement
g gFirst line of file
g eLast line of file
g hStart of line
g lEnd of line (last character)
g sFirst non-whitespace character on the line
HomeStart of line
EndEnd of line

Matching pairs

KeyMovement
#Jump to the matching bracket or tag

For a bracket on a single line, # looks at the whole selection, not just where the cursor sits — so it still finds ( ) [ ] { } after a selecting motion leaves the cursor just past one. A selection spanning multiple lines only looks at the character the cursor sits on, same as a tag. For an HTML/XML/JSX tag, the cursor itself must be inside the tag's own markup — its <, its >, the name, or an attribute — not just anywhere in the selection. Anywhere else, # does nothing. From an opening bracket or tag it jumps to the closing one, and back again from the closing side. A count has no effect — # always jumps to the immediate partner.

Structural navigation

For a language whose grammar ships a textobjects.scm (PLUM installs one alongside highlights where the upstream grammar has one), these commands jump to the next/previous instance of a structural kind and select it as a whole — cursor (head) on its first character:

KeyCommandSelects
g f / g Fgoto-next-function / goto-prev-functionThe next/previous function
g t / g Tgoto-next-class / goto-prev-classThe next/previous class or type
g a / g Agoto-next-argument / goto-prev-argumentThe next/previous argument
g c / g Cgoto-next-comment / goto-prev-commentThe next/previous comment
g u / g Ugoto-next-test / goto-prev-testThe next/previous unit test
g v / g Vgoto-next-value / goto-prev-valueThe next/previous array/tuple/struct value

Lowercase jumps forward, uppercase jumps backward — the same letter each kind uses as its text object key. Each also runs from the command mode prompt, e.g. :goto-next-function. They stop at either end of the buffer instead of wrapping, and each records a jump-list entry, so Ctrl+o returns to where you jumped from. Without a matching grammar, every one of these commands is a silent no-op.

Jump to a line by number

Type : then a line number and press Enter to jump there:

CommandMovement
:<n>Jump to line <n> (e.g. :42)
:goto <n>Same, full form

Line numbers are 1-based. A number past the end of the file lands on the last line. The jump is recorded, so Ctrl+o brings you back.

Paragraph movement

KeySelects
{The previous paragraph
}The next paragraph

A paragraph is a block of non-empty lines delimited by empty lines. Both keys select the whole paragraph they land on, plus the empty-line gap below it, if it has one. The jump is recorded, so Ctrl+o brings you back. Pressing {/} past the first/last paragraph does nothing. See Text objects for m i p, which selects just the paragraph without moving.

Scrolling

KeyEffect
PageDownScroll one viewport down
PageUpScroll one viewport up
Ctrl+dScroll half a viewport down
Ctrl+uScroll half a viewport up

View prefix (z)

Press z followed by a second key to reposition the view (the cursor itself stays put):

KeyEffect
z kScroll cursor to top of screen
z zCenter view on cursor
z jScroll cursor to bottom of screen

k is up and j is down, the same axis the motion keys use.

Search navigation

KeyEffect
/patternSearch forward
?patternSearch backward
nNext match
NPrevious match
*Search the whole word under the cursor, ignoring any current selection. Words are wrapped in word boundaries (\b…\b); punctuation is searched literally. Does nothing on whitespace or a blank line. With word-chars configured, a match can still bleed into a longer run sharing the same edge character (e.g. searching foo-bar inside foo-bar-baz also matches there)
m /Turn every search match in the buffer into a selection
Ctrl+/Use the primary selection's text, literally, as the search pattern — no word expansion, no boundaries (kitty only). Does nothing when the selection is just a line ending

m / precondition

m / uses the buffer's live search pattern if one is active; otherwise it falls back to the search register s (the last pattern submitted to / or ?, or set by *). If neither is available it is a silent no-op — no error, selections unchanged. It runs from Normal or Extend mode. See Register prefix for the full list of registers.

Regex syntax

/, ?, s (sift-within), and * all use Rust regex syntax. Notable points:

  • Smart case. A pattern with no uppercase letter matches case-insensitively; a single uppercase letter anywhere makes it case-sensitive. Note that this looks at the raw pattern text, so an escape like \W or \S counts as uppercase and will quietly make the search case-sensitive. Override with (?i) or (?-i).
  • Other inline flags(?m) multiline ^/$, (?s) dot-matches-newline, (?x) extended (whitespace ignored), (?U) swap greedy/non-greedy.
  • . does not match newlines by default; use (?s) if you need it to.
  • No backreferences, no lookaround, no possessive quantifiers. No Vim-style \c / \C case toggles either — they'd match the literal letters c / C.
  • Invalid patterns do nothing during live preview: the cursor stays put. Pressing Enter on one still stores it, so n and N will do nothing until you search for something valid again.

Search and replace

HUME has no :s/foo/bar/g substitute command. Find-and-replace is done with multi-cursor selection:

  1. Search for the pattern with /foo (or * on a word to match it).
  2. Press m / to turn every match in the buffer into a selection.
  3. Press c to change them all at once — type the replacement once and every selected instance updates together.
  4. Esc returns you to Normal.

To replace within a single region instead of the whole buffer, select the region first (e.g. x for a line, or m i { for a block), then use s (sift-within) with a regex instead of m /.

Jump list

HUME maintains a jump list of recent cursor positions.

KeyEffect
Ctrl+oJump to previous position
Ctrl+iJump to next position
TabJump to next position (except under the kitty protocol, where Tab moves between panes)

To get back to the buffer you were last in, use :b #. :e # does the same but only for buffers that have a file on disk.

Released under the MIT License.