Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Editing styles

Greed comes with three ways to edit, two with modes and one without, and you can switch between them while it runs. They’re equals: each is a plugin with its own modes, written against the same API, and each follows the editor it comes from closely, so what your hands know works here: Helix’s selections and motions, Vim’s operators, text objects, registers, macros and visual modes, the usual shortcuts of modeless editors. Where one still differs from the original, its section below says so.

StyleHow it worksLike
helixSelect text, then say what to do with itHelix, Kakoune
vimSay what to do, then where: d w, c i w, y yVim
vscodeNo modes, VS Code’s keys: typing inserts, shift and the arrows selectVS Code, most editors
:style vim        switch now
:style            pick one from a list

The status line shows the style’s name, dim, on the right; clicking it opens the same list. The mode on the left reads the way the style’s editor says it: NORMAL, INSERT, SELECT in Helix’s, VISUAL in Vim’s.

The first time you start Greed it asks which you’d like (:setup asks again), and :tutor teaches your style’s keys with lines to practise on. To start in a style every time, set it in ~/.config/greed/init.luau (with none set, Greed starts in Helix’s):

require("@greed").option.set("editing-style", "vim")

The keys that aren’t about editing live in the leader, which every style opens its own way: space in Helix and Vim, ctrl-space in the vscode style, where typing a letter inserts it. So space f finds files and space / searches the project, and in the vscode style ctrl-space f and ctrl-space / do the same; after the leader a hint lists what can follow. Helix and Vim also share : for commands, g d to go to a definition and ] d to the next problem. Prompts and pickers work the same in all three.

Keys in every style

Bind keys for the leader or for a role, and they work in whichever style you use, styles added later included:

local greed = require("@greed")

greed.keymap.bind({ layer = "leader" }, { W = "save-all" })      -- space W, or ctrl-space W
greed.keymap.bind({ role = "typing" }, { ["ctrl-s"] = "save" })   -- insert mode, or vscode's mode
greed.keymap.bind({ style = "vim", role = "command" }, { ["g h"] = "line-start" })

The roles are command (Helix’s and Vim’s normal mode), typing (insert mode, vscode’s mode) and selecting (Helix’s select mode, Vim’s visual mode). A binding for one style’s role wins over the style’s own keys, and those win over a binding for every style’s role. Keys has the whole order.

Helix

Normal mode is for moving and selecting, and every movement selects: w selects to the next word, x the line, % the whole file. Then a command acts on what’s selected: d deletes it, c changes it, y copies it.

x d        select the line, delete it
x x d      select two lines, delete them
% s foo    select every "foo" in the file; typing now edits them all

The cursor sits on a character, as in Helix, and is part of what you select: v l l selects three characters, ; leaves the cursor on the character it was on, and d on a bare cursor deletes that character. w, b and e move as Helix’s do.

With :set motion-hints true (off by default), a word motion (w b e and their WORD forms) numbers the next nine places doing it again would take you, and typing a number goes there in one key: w 3 instead of w w w w. In select mode it extends the selection. Right after such a motion a digit is then a number to jump to rather than the start of a count; any other key drops the numbers. Vim’s style has the same option for w b e W B E g e g E, in normal and visual mode. The nearest three numbers use the theme’s ui.motion.hint style and the rest the quieter ui.motion.hint.far; in the window both are drawn as badges, like key caps. A number sits on the space beside its place when the place is a letter, so it hides none of the text.

Why it’s here: you see what a command will act on before you run it, and many selections are part of the model rather than a separate feature. s, S, C and alt-s make selections, and every edit then happens at each one, which covers most of what macros and search-and-replace are used for. Using Greed lists the keys. The style is the helix plugin, and its modes are helix, helix-insert and helix-select.

Vim

Vim’s normal mode works the other way round: an operator first, then a motion saying how far. d w deletes to the next word, c i w changes the word under the cursor, 3 j moves three lines down. The cursor sits on a character, and v starts a visual mode for selecting by hand.

Keys
h j k l w b e W B E g e 0 ^ $ g _ g g G %Move, with counts: 3 w; % to the matching bracket (of the next one on the line, off a bracket), 50 % halfway down
{ } ( ) H M L - + _ |Paragraphs, sentences, the top, middle or bottom of the screen, lines, a column
f t F T + a character, ; ,To the next or previous character on the line; again, or back
d c y + a motion or text objectDelete, change or copy; doubled (d d) for whole lines
i w a w i W i ( a " i s i p i t …Text objects: words, brackets (b B too), quotes, sentences, paragraphs, tags, and the rest of the objects Helix’s m i takes (i f a function, i d a number, i n ( the next parens…)
> < g c + a motionIndent, dedent, comment; > > < < g c c for the line
g ~ g u g U g ? + a motionSwitch case, lowercase, uppercase, rot13 (~ u U in visual mode)
g q g w = ! + a motionRewrap to the text-width option (g w keeps the cursor), reindent, pipe through a command
x X D C s SThe usual shortcuts for deleting and changing
r ~ J g JReplace a character, switch case, join lines (g J without adding or removing spaces)
ctrl-a ctrl-xAdd to or subtract from the number at or after the cursor, with counts
p PPaste after or before
i a I A o O, g iInsert; with a count (3 i) what you type goes in that many times; g i where you last stopped typing
u ctrl-r UUndo, redo, put back the last changed line
g - g +Back or on through every state of the text, across undo branches (space u t shows them all)
v V ctrl-vVisual mode, by character, line or block; i/a there select a text object
o r J p in visual modeGo to the other end, replace every character, join the lines, paste over the selection
g v g nSelect the last visual selection again, or the next search match (c g n then . changes match after match)
y s + a motion or object + a character, d s c s, S in visual modeSurround, as vim-surround does: ysiw) wraps the word in brackets (( with spaces inside), ds" takes the quotes away, cs"' changes them, yss wraps the line
alt-o alt-iSelect the syntax node around the cursor, growing it in visual mode, or shrink it back
alt-shift-right alt-shift-leftMove the selected syntax node past the next or previous one
K, g r n g r a g r r g r i g r t, g OAs in Neovim: hover, rename, code actions, references, implementations, type definition, symbols in the file
g sLabel the words on screen and jump to the one you type
ctrl-nSelect the word under the cursor, then add its next match each time, as vim-visual-multi does; c d y i a I A act on every selection, ctrl-x skips a match, ctrl-p drops the last; esc after typing keeps a cursor in each place, and esc then goes back to one
Z Z Z QSave and close, close without saving; in a split, like :wq and :q, they close just that window
ctrl-^The file you were in before, like :b#
I A in visual block modeType before or after the block on every line ($ takes it to each line’s end)
* #Search for the word under the cursor, forward or back
ctrl-f ctrl-b ctrl-d ctrl-u ctrl-e ctrl-yPage, half page and a line down and up
z z z t z b, z a z c z o z R z M z f z j z k z d z ECenter the view, cursor line to the top or bottom; folds
RType over the text; backspace puts back what it replaced
g ; g ,Back and forward through the places you changed
ctrl-o ctrl-t ctrl-d ctrl-n ctrl-p in insert modeOne normal mode command, indent, dedent, complete from words in open files
ctrl-o ctrl-iBack and forward through where you jumped from
m + a letter, ' ` + a letterSet a mark (a–z in the file, A–Z across files), go to its line or to it
.Repeat the last change, with what it typed
q + a letter, qRecord a macro into that register, stop
@ + a letter, @ @Play a macro, play the last one again
" + a letterUse that register for the next yank, delete or paste; an uppercase letter appends; "0 holds the last yank, "1–"9 the last line deletes, "- a small one

Why it’s here: Vim’s keys are in a lot of people’s hands, and switching editors shouldn’t mean relearning them. It also shows how far a plugin can go: the Vim style is plain Luau against the same API any plugin uses, with its own modes (vim, vim-insert, vim-visual, vim-visual-line, vim-visual-block, vim-replace, vim-multi) beside Helix’s.

The unnamed register is the system clipboard, so p pastes what you copied in another program too; "+ is the same and "_ keeps nothing. Text from another program pastes as it is, even when it ends in a line break. Panels like the file tree and help keep their own keys.

Line commands with ranges (:%s/a/b/g, :g/regex/d, :'<,'>norm A;) are on the command line; Using Greed lists them. Some of Vim is still missing: a copied block pastes as plain text (one piece per line), and Vim’s own regex syntax (\(, \<) since patterns are the same regexes search uses.

VS Code

No modes, VS Code’s keys. Typing inserts text, replacing a selection if there is one, and the keys are the ones VS Code and most editors use.

Keys
arrows, home end, ctrl-left ctrl-rightMove; home goes to the first non-blank, then the line’s start
pageup pagedown, ctrl-home ctrl-endA screen up or down, the start or end of the file
shift + arrows, home end, ctrl-left ctrl-rightSelect
ctrl-a, ctrl-lSelect all, select the line (again for the next one)
ctrl-c ctrl-x ctrl-vCopy, cut, paste; with nothing selected, copy and cut take the line
ctrl-z ctrl-yUndo, redo (ctrl-shift-z redoes too, where the terminal can tell it from ctrl-z)
tab shift-tab, ctrl-]Indent or dedent the selected lines; tab alone types a level of indent
ctrl-backspace ctrl-deleteDelete a word back or forward
alt-up alt-down, alt-shift-up alt-shift-downMove the line up or down, copy it up or down
ctrl-shift-k, ctrl-enter ctrl-shift-enterDelete the line, start a new line below or above
ctrl-d, ctrl-shift-lSelect the word, then add its next match as another cursor; select every match
ctrl-alt-up ctrl-alt-down, alt-clickAdd a cursor above or below, or where you click
ctrl-/Comment or uncomment the lines
ctrl-fFind as you type, in any case, with the matches counted (2 of 5); enter and shift-enter go to the next and previous match with the find bar open, esc closes it and leaves the match selected
f3 shift-f3The next or previous match
ctrl-hReplace in the file: type what to find (its matches light up and are counted), enter, then what to put instead; enter replaces them all as one change
ctrl-gGo to a line: type its number
f12 shift-f12 f2 ctrl-.Go to the definition, find references, rename, code actions
f8 shift-f8, ctrl-shift-mThe next or previous problem, all problems
ctrl-shift-o ctrl-tGo to a symbol in the file, in the project
alt-left alt-rightBack and forward through where you jumped from
ctrl-u ctrl-shift-uBack to the cursors before the last command, and forward again
ctrl-p ctrl-b, ctrl-wFind a file, switch to an open file, close the file (the one you were in before takes its place)
ctrl-\Split the pane to the right
ctrl-k then a keyVS Code’s chords: ctrl-k ctrl-0 and ctrl-k ctrl-j fold and unfold everything, ctrl-k ctrl-l folds or unfolds the block, ctrl-k ctrl-i shows what’s under the cursor, ctrl-k ctrl-q goes to the last change, ctrl-k ctrl-t picks a theme, ctrl-k s saves every file
ctrl-P, alt-xPick a command to run from a list; open the command line (: in the other styles)
ctrl-spaceThe leader: ctrl-space f finds a file, ctrl-space / searches the project, the rest as space in Helix and Vim
ctrl-s, ctrl-qSave; quit, asking first whether to save unsaved files

Keys with ctrl-shift need a terminal that reports them, such as one with the kitty keyboard protocol (kitty, WezTerm, foot, Ghostty).

Why it’s here: for people who don’t want modes, or don’t want them yet, and for the odd edit where modes get in the way. Everything else in Greed still works, through the leader, ctrl-P and the command line (alt-x). Completion comes up as you type; ctrl-space is the leader here. The style is the vscode plugin: VS Code’s keys over core’s editing without modes, which another modeless keymap can use the same way (see below).

Making your own

A style is a few modes with keys bound in them, registered with the core plugin. It says which of its modes plays each role and which keys open the leader, and everything bound for those comes with it, with no plugin having to know the style exists:

local greed = require("@greed")

greed.keymap.bind("mine", { j = "move-down", k = "move-up", i = "insert-mode" })
greed.keymap.fallback("mine-insert", "insert-char")

require("@core").style.define({
	name = "mine",
	doc = "My own keys",
	mode = "mine",
	-- Which mode plays each role; insert-mode goes to the typing one.
	roles = { command = "mine", typing = "mine-insert" },
	-- What the status line shows for each mode.
	labels = { mine = "normal", ["mine-insert"] = "insert" },
	-- The keys that open the leader, where `space f` and the rest live.
	leader = "space",
})

That’s enough for :style mine to switch to it and for it to show in the :style list and the setup page. The leader opens with space, with the same hint after it; keys plugins bind for the command role (:, g d, ] d) work in mine, and the typing keys every style shares (enter, backspace, the arrows, esc back to mine) in mine-insert. The file tree, pickers, help and other panels keep their keys in it. Completion, signature help and Markdown shown as written while typing follow the typing mode; a style without modes makes its own mode the typing one (roles = { typing = "mine" }). . works in any style: it types the keys of the last change again; require("@core").commands.tag("no-repeat", { "my-undo" }) leaves out commands that shouldn’t count as one. The vim plugin, which is the Vim style, is a full example to read.

A style without modes, like a JetBrains keymap, is shorter still: bind its keys in its one mode, and core’s editing without modes (the vscode style’s) does the typing, replacing the selection, and the rest:

local greed = require("@greed")

greed.keymap.bind("jetbrains", {
	["ctrl-c"] = "copy-or-line",
	["ctrl-v"] = "paste-over",
	["ctrl-d"] = "copy-lines-down",
	["ctrl-y"] = "delete-lines-at-cursor",
	["ctrl-shift-up"] = "move-lines-up",
})

require("@core").modeless.define({
	name = "jetbrains",
	doc = "No modes, JetBrains' keys",
	leader = "ctrl-space",
})

Roles decide where keys live, not what commands mean, so two styles still differ in what d does. And Vim’s operators read the motion after them straight from the keyboard, so leader and role keys don’t apply between d and its motion.