# `Minga.Buffer.Lines`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga/buffer/lines.ex#L1)

Presents document content as editor lines.

This module owns line-oriented questions: fetching visible line text,
taking line ranges, maintaining the cached line index, and measuring
how inserted text changes the current line.

## Line index representation

The line index (`line_offsets` on `Document`) has three states:

- **Clean tuple** `{0, 6, 12, ...}`: accurate line-start byte offsets.
- **Pending delta** `{:pending, starts, adjust_after, delta}`: the tuple
  `starts` is stale; lines after `adjust_after` are shifted by `delta`.
  Queries apply the delta on the fly in O(1).
- **`nil`**: needs a full rebuild from content.

Single-character inserts and deletes (the hot path) produce pending
deltas in O(1). Newline insertion/deletion flushes the delta and
splices entries, which is O(line_count) but rare relative to
non-newline edits.

# `line_count`

```elixir
@type line_count() :: pos_integer()
```

# `line_index`

```elixir
@type line_index() :: non_neg_integer()
```

# `line_span`

```elixir
@type line_span() :: {start :: non_neg_integer(), length :: non_neg_integer()}
```

# `line_starts`

```elixir
@type line_starts() :: tuple()
```

# `snapshot`

```elixir
@type snapshot() :: {line_starts(), String.t()}
```

# `break_count`

```elixir
@spec break_count(String.t()) :: non_neg_integer()
```

Returns how many line breaks appear in `text`.

# `build_index`

```elixir
@spec build_index(String.t()) :: line_starts()
```

Builds a line-start index from a complete text.

# `count`

```elixir
@spec count(String.t()) :: line_count()
```

Returns how many editor lines `text` occupies.

# `fetch`

```elixir
@spec fetch(Minga.Buffer.Document.t(), line_index()) :: String.t() | nil
```

Returns the content of one editor line without its trailing newline.

# `flush_to_tuple`

```elixir
@spec flush_to_tuple(line_starts(), non_neg_integer(), integer()) :: line_starts()
```

Applies the pending delta to produce a clean tuple.

# `last_line_width`

```elixir
@spec last_line_width(String.t()) :: non_neg_integer()
```

Returns the cursor column at the end of the final line in `text`.

# `slice`

```elixir
@spec slice(Minga.Buffer.Document.t(), line_index(), non_neg_integer()) :: [
  String.t()
]
```

Returns up to `count` editor lines starting at `first_line`.

# `snapshot`

```elixir
@spec snapshot(Minga.Buffer.Document.t()) :: snapshot()
```

Returns indexed document text so callers can answer multiple line questions without rebuilding the line index.

# `span`

```elixir
@spec span(line_starts(), line_index(), non_neg_integer()) :: line_span() | nil
```

Returns the content span for one editor line.

# `start`

```elixir
@spec start(line_starts(), line_index()) :: non_neg_integer()
```

Returns where one editor line starts in the document text.

# `update_after_delete_at`

```elixir
@spec update_after_delete_at(
  Minga.Buffer.Document.line_offsets(),
  non_neg_integer(),
  non_neg_integer(),
  boolean()
) :: Minga.Buffer.Document.line_offsets()
```

Updates line_offsets after deleting one character at the cursor (forward delete).

# `update_after_delete_before`

```elixir
@spec update_after_delete_before(
  Minga.Buffer.Document.line_offsets(),
  non_neg_integer(),
  non_neg_integer(),
  boolean()
) :: Minga.Buffer.Document.line_offsets()
```

Updates line_offsets after deleting one character before the cursor.

# `update_after_insert`

```elixir
@spec update_after_insert(
  Minga.Buffer.Document.line_offsets(),
  non_neg_integer(),
  non_neg_integer(),
  String.t()
) :: Minga.Buffer.Document.line_offsets()
```

Updates line_offsets after inserting `text` at the cursor. O(1) when text has no newlines.

---

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