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. When no whitespace precedes the word (the first word of a line, where a leading run would be indentation, or a word that directly follows punctuation), they cover its trailing whitespace instead. This means deleting a word never leaves a double space behind. Use :set global word-selects-whitespace=after (or per buffer) to prefer the whitespace after the word instead, or =off to select just the bare word. 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, with 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, with 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 reports it and leaves your last search as it was. Pressing Enter on a pattern that matches nothing shows "no match"; the pattern still becomes the current search.

Flags ​

Start a pattern typed at /, ?, or s with one or more of these letters followed by / to change how it's matched:

FlagEffect
mMove (or extend) every selection to its own next match, instead of only the primary. No effect at s, which already applies to every selection.
vMatch the pattern literally: none of its characters are treated as regex syntax.

Flags combine in any order: mv/.rs moves every selection to its own next literal .rs. n and N keep repeating with whichever flags were last used, until you search again.

A pattern that starts with a leading / of its own (a path, say) is read as plain text, not as an empty flag prefix: /usr/bin searches for /usr/bin. Only text that starts with m and/or v followed by / is read as flags; reach that text literally with v/, so v/m/s searches for the literal text m/s.

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.