# `Minga.Editing.TextObject`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/editing/text_object.ex#L1)

Text object selection for Vim operator-pending mode.

Each function takes a `Readable.t()` and a cursor `position()` and returns
a `{start_pos, end_pos}` range (both positions inclusive), or `nil` when no
matching text object exists around the cursor.

All positions use byte-indexed columns (`{line, byte_col}`).

## Word text objects

* `inner_word/2` (`iw`) — the word (or whitespace run) under the cursor,
  without surrounding whitespace.
* `a_word/2` (`aw`) — the word plus one surrounding whitespace run
  (trailing preferred; leading used when at end of line).

## Quote text objects

* `inner_quotes/3` (`i"`, `i'`) — the content between the nearest enclosing
  quote pair on the current line, excluding the quote characters themselves.
* `a_quotes/3` (`a"`, `a'`) — same range including the quote characters.

## Parenthesis / bracket text objects

* `inner_parens/4` (`i(`, `i{`, `i[`) — content between the nearest
  enclosing open/close delimiter pair, excluding the delimiters. Handles
  nesting: e.g. `i(` inside `(a (b) c)` with cursor on `b` selects `a (b) c`.
* `a_parens/4` (`a(`, `a{`, `a[`) — same range including the delimiters.

Delimiter search spans multiple lines.

# `position`

```elixir
@type position() :: {non_neg_integer(), non_neg_integer()}
```

A zero-indexed `{line, byte_col}` position.

# `range`

```elixir
@type range() :: {position(), position()} | nil
```

An inclusive `{start_pos, end_pos}` range, or `nil` when not found.

# `structural_type`

```elixir
@type structural_type() :: :function | :class | :parameter | :block | :comment | :test
```

Structural text object type.

# `tree_range`

```elixir
@type tree_range() ::
  {non_neg_integer(), non_neg_integer(), non_neg_integer(), non_neg_integer()}
  | nil
```

Raw tree-sitter textobject result: `{start_row, start_col, end_row, end_col}` or `nil`.

# `a_parens`

```elixir
@spec a_parens(Minga.Editing.Text.Readable.t(), position(), String.t(), String.t()) ::
  range()
```

Returns the range of text **including** the nearest enclosing delimiter pair
around the cursor.

Searches across multiple lines. Handles nesting.

Returns `nil` if no enclosing pair is found.

Corresponds to Vim's `a(`, `a{`, `a[`, etc.

# `a_quotes`

```elixir
@spec a_quotes(Minga.Editing.Text.Readable.t(), position(), String.t()) :: range()
```

Returns the range of text **including** the nearest enclosing quote pair on
the cursor's line.

Returns `nil` if no enclosing quote pair is found.

Corresponds to Vim's `a"` / `a'` motions.

# `a_word`

```elixir
@spec a_word(Minga.Editing.Text.Readable.t(), position()) :: {position(), position()}
```

Returns the range of the word under the cursor plus one adjacent whitespace
run (trailing preferred; leading used when the word is at the end of line).

Corresponds to Vim's `aw` motion in operator-pending mode.

# `inner_parens`

```elixir
@spec inner_parens(
  Minga.Editing.Text.Readable.t(),
  position(),
  String.t(),
  String.t()
) :: range()
```

Returns the range of text **inside** the nearest enclosing delimiter pair
around the cursor, not including the delimiters.

Searches across multiple lines. Handles nesting (the cursor's depth relative
to the nearest enclosing pair is tracked).

Returns `nil` if no enclosing pair is found.

Corresponds to Vim's `i(`, `i{`, `i[`, etc.

# `inner_quotes`

```elixir
@spec inner_quotes(Minga.Editing.Text.Readable.t(), position(), String.t()) :: range()
```

Returns the range of text **inside** the nearest enclosing quote pair on the
cursor's line, not including the quote characters.

Returns `nil` if no enclosing quote pair is found.

Corresponds to Vim's `i"` / `i'` motions.

# `inner_word`

```elixir
@spec inner_word(Minga.Editing.Text.Readable.t(), position()) ::
  {position(), position()}
```

Returns the range of the word (or whitespace / symbol run) under the cursor,
excluding any surrounding whitespace.

Corresponds to Vim's `iw` motion in operator-pending mode.

# `structural_around`

```elixir
@spec structural_around(tree_range()) :: range()
```

Converts a raw tree-sitter textobject range into an inclusive Vim-style
outer range.

Semantically identical to `structural_inner/1` (tree-sitter already
distinguishes inside vs around via the capture name). This function exists
so callers can express intent clearly.

# `structural_inner`

```elixir
@spec structural_inner(tree_range()) :: range()
```

Converts a raw tree-sitter textobject range into an inclusive Vim-style
inner range.

The caller is responsible for querying the parser (via
`Parser.Manager.request_textobject/4`) and passing the result here.
Returns `nil` when `tree_data` is `nil` (no match found by the parser).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
