Pure cursor-motion functions for the Minga editor.
Each function takes a Readable.t() and a current position(), and
returns the new position() after applying the motion. No buffer state
is mutated — the caller is responsible for moving the buffer cursor via
Document.move_to/2 or Buffer.Server.move_to/2.
This module is a facade over focused sub-modules:
Motion.Word—w/b/e/W/B/Eword motionsMotion.Line—0/$/^line motionsMotion.Document—gg/G/{/}document & paragraph motionsMotion.Char—f/F/t/Tfind-char and%bracket match
Word boundary rules
A word character is any alphanumeric character or underscore
([a-zA-Z0-9_]). This matches Vim's lowercase w/b/e motions.
Whitespace (space, tab, newline) acts as word separator.
Line and document motions
| Function | Vim key | Description |
|---|---|---|
line_start/2 | 0 | First column of the current line |
line_end/2 | $ | Last column of the current line |
first_non_blank/2 | ^ | First non-whitespace column on the line |
document_start/1 | gg | First character of the buffer |
document_end/1 | G | Last character of the last line |
Summary
Types
A zero-indexed {line, col} cursor position.
Functions
Move to the last character of the last line (like Vim's G).
Move to the very start of the buffer (like Vim's gg).
Always returns {0, 0}.
Move backward to the previous occurrence of char on the current line (Vim's F).
Returns the original position if char is not found.
Move forward to the next occurrence of char on the current line (Vim's f).
Returns the original position if char is not found.
Move to the first non-blank character on the current line (like Vim's ^).
Falls back to {line, 0} when the line is entirely blank.
Move to the last column of the current line (like Vim's $).
Returns the position of the last grapheme on the line.
For an empty line, returns {line, 0}.
Move to the first column of the current line (like Vim's 0).
Jump to the matching bracket/paren/brace (Vim's %).
Move to the previous blank line (Vim's {).
Move to the next blank line (Vim's }).
Move to one after the previous occurrence of char on the current line (Vim's T).
Returns the original position if char is not found.
Move to one before the next occurrence of char on the current line (Vim's t).
Returns the original position if char is not found.
Move backward to the start of the previous word (like Vim's b).
Move backward to the start of the previous WORD (Vim's B).
Move to the end of the current or next word (like Vim's e).
Move to the end of the current or next WORD (Vim's E).
Move forward to the start of the next word (like Vim's w).
Move forward to the start of the next WORD (Vim's W).
Types
@type position() :: {non_neg_integer(), non_neg_integer()}
A zero-indexed {line, col} cursor position.
Functions
@spec document_end(Minga.Editing.Text.Readable.t()) :: position()
Move to the last character of the last line (like Vim's G).
Examples
iex> buf = Minga.Buffer.Document.new("hello\nworld")
iex> Minga.Editing.Motion.document_end(buf)
{1, 4}
@spec document_start(Minga.Editing.Text.Readable.t()) :: position()
Move to the very start of the buffer (like Vim's gg).
Always returns {0, 0}.
Examples
iex> Minga.Editing.Motion.document_start(Minga.Buffer.Document.new("hello\nworld"))
{0, 0}
@spec find_char_backward(Minga.Editing.Text.Readable.t(), position(), String.t()) :: position()
Move backward to the previous occurrence of char on the current line (Vim's F).
Returns the original position if char is not found.
Examples
iex> buf = Minga.Buffer.Document.new("hello world")
iex> Minga.Editing.Motion.find_char_backward(buf, {0, 7}, "o")
{0, 4}
@spec find_char_forward(Minga.Editing.Text.Readable.t(), position(), String.t()) :: position()
Move forward to the next occurrence of char on the current line (Vim's f).
Returns the original position if char is not found.
Examples
iex> buf = Minga.Buffer.Document.new("hello world")
iex> Minga.Editing.Motion.find_char_forward(buf, {0, 0}, "o")
{0, 4}
@spec first_non_blank(Minga.Editing.Text.Readable.t(), position()) :: position()
Move to the first non-blank character on the current line (like Vim's ^).
Falls back to {line, 0} when the line is entirely blank.
Examples
iex> buf = Minga.Buffer.Document.new(" hello")
iex> Minga.Editing.Motion.first_non_blank(buf, {0, 0})
{0, 2}
@spec line_end(Minga.Editing.Text.Readable.t(), position()) :: position()
Move to the last column of the current line (like Vim's $).
Returns the position of the last grapheme on the line.
For an empty line, returns {line, 0}.
Examples
iex> buf = Minga.Buffer.Document.new("hello\nworld")
iex> Minga.Editing.Motion.line_end(buf, {0, 0})
{0, 4}
@spec line_start(Minga.Editing.Text.Readable.t(), position()) :: position()
Move to the first column of the current line (like Vim's 0).
Examples
iex> buf = Minga.Buffer.Document.new(" hello")
iex> Minga.Editing.Motion.line_start(buf, {0, 4})
{0, 0}
@spec match_bracket(Minga.Editing.Text.Readable.t(), position()) :: position()
Jump to the matching bracket/paren/brace (Vim's %).
Examples
iex> buf = Minga.Buffer.Document.new("(hello)")
iex> Minga.Editing.Motion.match_bracket(buf, {0, 0})
{0, 6}
@spec paragraph_backward(Minga.Editing.Text.Readable.t(), position()) :: position()
Move to the previous blank line (Vim's {).
Examples
iex> buf = Minga.Buffer.Document.new("hello\nworld\n\nfoo")
iex> Minga.Editing.Motion.paragraph_backward(buf, {3, 0})
{2, 0}
@spec paragraph_forward(Minga.Editing.Text.Readable.t(), position()) :: position()
Move to the next blank line (Vim's }).
Examples
iex> buf = Minga.Buffer.Document.new("hello\nworld\n\nfoo")
iex> Minga.Editing.Motion.paragraph_forward(buf, {0, 0})
{2, 0}
@spec till_char_backward(Minga.Editing.Text.Readable.t(), position(), String.t()) :: position()
Move to one after the previous occurrence of char on the current line (Vim's T).
Returns the original position if char is not found.
Examples
iex> buf = Minga.Buffer.Document.new("hello world")
iex> Minga.Editing.Motion.till_char_backward(buf, {0, 7}, "o")
{0, 5}
@spec till_char_forward(Minga.Editing.Text.Readable.t(), position(), String.t()) :: position()
Move to one before the next occurrence of char on the current line (Vim's t).
Returns the original position if char is not found.
Examples
iex> buf = Minga.Buffer.Document.new("hello world")
iex> Minga.Editing.Motion.till_char_forward(buf, {0, 0}, "o")
{0, 3}
@spec word_backward(Minga.Editing.Text.Readable.t(), position()) :: position()
Move backward to the start of the previous word (like Vim's b).
Examples
iex> buf = Minga.Buffer.Document.new("hello world")
iex> Minga.Editing.Motion.word_backward(buf, {0, 6})
{0, 0}
@spec word_backward_big(Minga.Editing.Text.Readable.t(), position()) :: position()
Move backward to the start of the previous WORD (Vim's B).
Examples
iex> buf = Minga.Buffer.Document.new("foo.bar baz")
iex> Minga.Editing.Motion.word_backward_big(buf, {0, 8})
{0, 0}
@spec word_end(Minga.Editing.Text.Readable.t(), position()) :: position()
Move to the end of the current or next word (like Vim's e).
Examples
iex> buf = Minga.Buffer.Document.new("hello world")
iex> Minga.Editing.Motion.word_end(buf, {0, 0})
{0, 4}
@spec word_end_big(Minga.Editing.Text.Readable.t(), position()) :: position()
Move to the end of the current or next WORD (Vim's E).
Examples
iex> buf = Minga.Buffer.Document.new("foo.bar baz")
iex> Minga.Editing.Motion.word_end_big(buf, {0, 0})
{0, 6}
@spec word_forward(Minga.Editing.Text.Readable.t(), position()) :: position()
Move forward to the start of the next word (like Vim's w).
Examples
iex> buf = Minga.Buffer.Document.new("hello world")
iex> Minga.Editing.Motion.word_forward(buf, {0, 0})
{0, 6}
@spec word_forward_big(Minga.Editing.Text.Readable.t(), position()) :: position()
Move forward to the start of the next WORD (Vim's W).
Examples
iex> buf = Minga.Buffer.Document.new("foo.bar baz")
iex> Minga.Editing.Motion.word_forward_big(buf, {0, 0})
{0, 8}