vim

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package vim is the modal input model, as a pure state machine.

It knows nothing about editors, terminals or SQL: keys go in, commands come out. Keeping it that way is what makes the interesting part — which half-typed sequences mean what — testable without a screen.

The scope is deliberately the practical subset: normal, insert and visual modes with the common motions, operators and edits. Counts (3dd), marks, named registers and dot-repeat are out.

Search is here only as far as the key that starts it. The pattern is typed into the interface, which owns both the field it goes in and the text it is looked for in; carrying it through Feed would put every keystroke of a search term past the arrow-key and operator handling below, where it would be read as a motion. That also means "d/foo" is not supported — searching moves the cursor, it does not give an operator something to reach.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Command

type Command struct {
	Kind   Kind
	Motion Motion
	// At is where an insert or a put lands.
	At Place
	// Linewise means whole lines: dd, yy, V.
	Linewise bool
	// Selection means the operator applies to the visual selection already on
	// screen rather than to a motion from the cursor.
	Selection bool
	// Backward reverses a search: "?" rather than "/".
	Backward bool
	// Count is how many times the motion applies, and is never zero — an
	// untyped count is one, so the caller can multiply without checking.
	Count int
	// Target is the character a find motion was given.
	Target rune
	// Object is the region an operator applies to, and Around says whether
	// its delimiters go with it: "i" is inside them, "a" takes them too.
	Object Object
	Around bool
}

func (Command) Changes added in v0.3.0

func (c Command) Changes() bool

Changes reports whether a command altered the buffer, and is therefore what "." would repeat.

The rule is vim's rather than the interface's, so it lives here: a yank copies without changing, a motion moves, and an undo is not a change to be done again. Repeating the repeat is excluded because recording it would lose the original it stands for.

type Entry

type Entry struct {
	// Keys is the sequence exactly as it is typed, so that the reference can
	// be checked against the state machine rather than trusted.
	Keys        string
	Description string
}

Entry is one line of the key reference.

type Group

type Group struct {
	Title   string
	Entries []Entry
}

Group is a titled section of the reference.

func Reference

func Reference() []Group

Reference lists the modal commands for the help screen and `dv keys`.

It lives beside the state machine on purpose. A reference kept anywhere else drifts, and a key reference that lies is worse than none — it is consulted precisely when something has already stopped working.

type Kind

type Kind int

Kind is what a command does.

const (
	// KindNone is the zero command, returned alongside any outcome that is
	// not OutcomeExecute.
	KindNone Kind = iota
	KindMove
	KindDelete
	KindChange
	KindYank
	KindPaste
	KindUndo
	KindRedo
	// KindInsert enters insert mode at At.
	KindInsert
	// KindVisual starts or ends a selection; Linewise says which kind.
	KindVisual
	// KindEscape returns to normal mode, collapsing any selection.
	KindEscape
	// KindSearch asks for a pattern; Backward says which way from the cursor.
	KindSearch
	// KindSearchNext repeats the last search the way it was going, and
	// KindSearchPrev repeats it the other way.
	KindSearchNext
	KindSearchPrev
	// KindRepeat asks for the last change to be carried out again.
	//
	// It names no command of its own on purpose. A change that entered insert
	// mode includes the text that was typed, and insert-mode keys go straight
	// to the widget without this package seeing them — so what to replay is
	// known only to whoever ran the change.
	KindRepeat
)

type Mode

type Mode int

Mode is the input mode.

const (
	ModeNormal Mode = iota
	ModeInsert
	ModeVisual
	ModeVisualLine
)

func (Mode) String

func (m Mode) String() string

String names the mode as the status bar shows it.

type Motion

type Motion int

Motion is where a command reaches.

const (
	MotionNone Motion = iota
	MotionLeft
	MotionRight
	MotionUp
	MotionDown
	MotionWordForward
	MotionWordBackward
	MotionWordEnd
	MotionLineStart
	MotionFirstNonBlank
	MotionLineEnd
	MotionFileStart
	MotionFileEnd
	// The find motions carry the character they were given in Command.Target.
	// MotionTill stops one short of it, which is what makes "ct," change up to
	// a comma and leave the comma in place.
	MotionFindForward
	MotionFindBackward
	MotionTillForward
	MotionTillBackward
)

type Object added in v0.3.0

type Object int

Command is a completed instruction for the editor.

It is a comparable value with no pointers, so tests can state the whole expected command in one literal. Object is a region an operator can act on without a motion reaching it: the word under the caret, or whatever a pair of brackets or quotes encloses.

These are what a SQL editor is reached for most — ci( replaces an IN list, ci' a string literal — because the interesting region is almost always delimited rather than a number of words away.

const (
	// ObjectNone means the operator took a motion instead.
	ObjectNone Object = iota
	ObjectWord
	ObjectParen
	ObjectBracket
	ObjectBrace
	ObjectAngle
	ObjectSingleQuote
	ObjectDoubleQuote
	ObjectBacktick
)

type Outcome

type Outcome int

Outcome says what the state machine did with a key.

Three outcomes rather than a bool: "the editor should type this" and "I am waiting for the rest of a sequence" are different things, and collapsing them is how a half-typed operator ends up inserting a letter.

const (
	// OutcomePass hands the key to the editor. Only insert mode does this.
	OutcomePass Outcome = iota
	// OutcomePending consumes the key while a sequence is incomplete.
	OutcomePending
	// OutcomeExecute consumes the key and yields a command.
	OutcomeExecute
)

func (Outcome) String

func (o Outcome) String() string

type Place

type Place int

Place is where an insertion or a put happens.

const (
	PlaceNone Place = iota
	PlaceBefore
	PlaceAfter
	PlaceLineStart
	PlaceLineEnd
	PlaceOpenBelow
	PlaceOpenAbove
)

type State

type State struct {
	// contains filtered or unexported fields
}

State is the modal input state: the current mode and any half-typed sequence.

It is not safe for concurrent use, which is fine — keys arrive one at a time on the interface's own goroutine.

func New

func New() *State

New returns a state in normal mode, which is where vim starts.

func (*State) Feed

func (s *State) Feed(ev *tcell.EventKey) (Command, Outcome)

Feed offers a key to the state machine.

The outcome says whether the editor should type the key, keep waiting, or run the returned command.

func (*State) Mode

func (s *State) Mode() Mode

Mode reports the current input mode.

func (*State) Pending

func (s *State) Pending() string

Pending renders the half-typed sequence for the status bar.

Showing it is not a nicety: an operator that silently waits for a motion is indistinguishable from a keyboard that has stopped working, and that is the single most likely way a new user concludes the application is broken.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL