# `MingaEditor.ChangeRecorder`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/change_recorder.ex#L1)

Records editing changes as raw key sequences for dot repeat.

A pure functional module — no GenServer. The struct is embedded in
`MingaEditor.State` and threaded through the editor's key dispatch.

## Recording lifecycle

1. A change begins (insert mode entry, operator key, single-key edit) →
   `start_recording/1` clears the key buffer and sets `recording: true`.
2. Each key event during the change → `record_key/2` appends to the buffer.
3. The change ends (Escape back to Normal, or operator completes) →
   `stop_recording/1` copies the buffer into `last_change`.

During replay (`replaying: true`), the editor suppresses recording so
the replayed keys don't overwrite the stored change.

# `key`

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

A key event: `{codepoint, modifiers}`.

# `t`

```elixir
@type t() :: %MingaEditor.ChangeRecorder{
  keys: [key()],
  last_change: [key()] | nil,
  pending_keys: [key()],
  recording: boolean(),
  replaying: boolean()
}
```

# `buffer_pending_key`

```elixir
@spec buffer_pending_key(t(), key()) :: t()
```

Buffers a key as a potential part of a future change (e.g., count digits, `r` prefix).

# `cancel_recording`

```elixir
@spec cancel_recording(t()) :: t()
```

Cancels the current recording without saving.

Discards the key buffer and stops recording. `last_change` is preserved.

# `clear_pending`

```elixir
@spec clear_pending(t()) :: t()
```

Clears pending keys without saving them.

# `get_last_change`

```elixir
@spec get_last_change(t()) :: [key()] | nil
```

Returns the stored last-change key sequence, or `nil` if none.

# `new`

```elixir
@spec new() :: t()
```

Returns a fresh recorder with no recorded change.

# `record_key`

```elixir
@spec record_key(t(), key()) :: t()
```

Appends a key to the current recording.

No-op if not currently recording.

# `recording?`

```elixir
@spec recording?(t()) :: boolean()
```

Returns `true` if currently recording a change.

# `replace_count`

```elixir
@spec replace_count([key()], non_neg_integer() | nil) :: [key()]
```

Replaces the count prefix in a recorded key sequence.

Strips any leading digit keys (the original count) and prepends
digit keys for the new count. If `new_count` is `nil` or `1`,
returns the sequence with the original count stripped.

# `replaying?`

```elixir
@spec replaying?(t()) :: boolean()
```

Returns `true` if currently replaying a change.

# `start_recording`

```elixir
@spec start_recording(t()) :: t()
```

Begins recording a new change. Promotes any pending keys into the recording.

# `start_recording_if_not`

```elixir
@spec start_recording_if_not(t()) :: t()
```

Begins recording only if not already recording. Preserves existing keys.

# `start_replay`

```elixir
@spec start_replay(t()) :: t()
```

Sets the replaying flag. Recording is suppressed during replay.

# `stop_recording`

```elixir
@spec stop_recording(t()) :: t()
```

Finalizes the current recording into `last_change`.

The key buffer is moved to `last_change` and recording stops.

# `stop_replay`

```elixir
@spec stop_replay(t()) :: t()
```

Clears the replaying flag.

---

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