# `MingaEditor.Agent.UIState`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/agent/ui_state.ex#L1)

Unified agent UI state wrapping `Panel` and `View` sub-structs.

`Panel` holds prompt editing and chat display state (buffer, history,
scroll, model config, paste blocks). `View` holds layout, search,
preview, toasts, and diff baselines. Splitting into sub-structs keeps
each under 16 fields while providing a single access point on
`EditorState.agent_ui`.

Most callers use the functions on this module (routed through
`AgentAccess.update_agent_ui/2`). Input handlers and renderers that
need read-only field access use `AgentAccess.panel/1` to get the
`Panel` sub-struct directly.

# `focus`

> This type is deprecated. Use View.focus() instead.

```elixir
@type focus() :: MingaEditor.Agent.UIState.View.focus()
```

Which panel has keyboard focus. Deprecated: use View.focus().

# `input_mode`

```elixir
@type input_mode() :: :insert | :normal | :visual | :visual_line | :operator_pending
```

Vim mode for the input field when focused.

# `paste_block`

> This type is deprecated. Use Panel.paste_block() instead.

```elixir
@type paste_block() :: MingaEditor.Agent.UIState.Panel.paste_block()
```

A collapsed paste block. Deprecated: use Panel.paste_block().

# `prefix`

> This type is deprecated. Use View.prefix() instead.

```elixir
@type prefix() :: MingaEditor.Agent.UIState.View.prefix()
```

Active prefix key. Deprecated: use View.prefix().

# `search_match`

> This type is deprecated. Use View.search_match() instead.

```elixir
@type search_match() :: MingaEditor.Agent.UIState.View.search_match()
```

A search match. Deprecated: use View.search_match().

# `search_state`

> This type is deprecated. Use View.search_state() instead.

```elixir
@type search_state() :: MingaEditor.Agent.UIState.View.search_state()
```

Search state. Deprecated: use View.search_state().

# `t`

```elixir
@type t() :: %MingaEditor.Agent.UIState{
  panel: MingaEditor.Agent.UIState.Panel.t(),
  view: MingaEditor.Agent.UIState.View.t()
}
```

Agent UI state wrapping Panel and View sub-structs.

# `thinking_level`

```elixir
@type thinking_level() :: String.t()
```

Thinking level for models that support extended reasoning.

# `toast`

> This type is deprecated. Use View.toast() instead.

```elixir
@type toast() :: MingaEditor.Agent.UIState.View.toast()
```

A notification toast. Deprecated: use View.toast().

# `activate`

```elixir
@spec activate(t(), MingaEditor.State.Windows.t(), MingaEditor.State.FileTree.t()) ::
  t()
```

Activates the view, saving the current window layout.

# `cancel_search`

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

Cancels search.

# `clear_baselines`

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

Clears all diff baselines.

# `clear_display`

```elixir
@spec clear_display(t(), non_neg_integer()) :: t()
```

Clears the chat display without affecting conversation history.

Sets `display_start_index` to the given message count so the renderer
skips all messages before this point. Scrolls to bottom.

# `clear_input`

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

Clears the input (after submission). Saves current text to history first.

# `clear_input_and_scroll`

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

Clears the input and scrolls to the bottom.

# `clear_prefix`

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

Clears any pending prefix.

# `clear_toasts`

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

Clears all toasts.

# `confirm_search`

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

Confirms search (keeps matches for n/N navigation, disables input).

# `deactivate`

```elixir
@spec deactivate(t()) ::
  {t(), MingaEditor.State.Windows.t() | nil,
   MingaEditor.State.FileTree.t() | nil}
```

Deactivates the view and returns the restored window layout.

# `delete_char`

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

Deletes the character before the cursor.

At the start of a line (col 0), joins with the previous line.
At the start of the first line, no-op.

# `dismiss_help`

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

Dismisses the help overlay.

# `dismiss_toast`

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

Dismisses the current toast.

# `engage_auto_scroll`

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

Re-engages auto-scroll. Delegates to `Minga.Editing.Minga.Editing.pin_to_bottom/1`.

# `ensure_prompt_buffer`

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

Ensures a prompt Buffer.Server is running. Starts one if `prompt_buffer`
is nil or the process is dead.

# `get_baseline`

```elixir
@spec get_baseline(t() | MingaEditor.Agent.UIState.View.t(), String.t()) ::
  String.t() | nil
```

Returns the baseline content for a path, or nil if none recorded.

# `grow_chat`

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

Grows the chat panel width by one step (clamped at max).

# `history_next`

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

Recalls the next (more recent) prompt from history.

# `history_prev`

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

Recalls the previous prompt from history.

# `input_cursor`

```elixir
@spec input_cursor(t() | MingaEditor.Agent.UIState.Panel.t()) ::
  {non_neg_integer(), non_neg_integer()}
```

Returns the input cursor position as `{line, col}`.

# `input_empty?`

```elixir
@spec input_empty?(t() | MingaEditor.Agent.UIState.Panel.t()) :: boolean()
```

Returns true if the input is empty (single empty line).

# `input_line_count`

```elixir
@spec input_line_count(t() | MingaEditor.Agent.UIState.Panel.t()) :: pos_integer()
```

Returns the number of input lines.

# `input_lines`

```elixir
@spec input_lines(t() | MingaEditor.Agent.UIState.Panel.t()) :: [String.t()]
```

Returns the input lines as a list of strings.

# `input_text`

```elixir
@spec input_text(t() | MingaEditor.Agent.UIState.Panel.t()) :: String.t()
```

Returns the raw input text (with placeholders, not substituted).

# `insert_char`

```elixir
@spec insert_char(t(), String.t()) :: t()
```

Inserts a character at the cursor position.

# `insert_newline`

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

Inserts a newline at the cursor, splitting the current line.

# `insert_paste`

```elixir
@spec insert_paste(t(), String.t()) :: t()
```

Inserts pasted text into the input.

For short pastes (fewer than 3 lines), the text is
inserted directly into the buffer. For longer pastes, the text is
stored in `pasted_blocks` and a placeholder token is inserted at the cursor
position. The placeholder renders as a compact indicator (e.g. "󰆏 [pasted 23 lines]")
but `prompt_text/1` substitutes the full content when the prompt is submitted.

# `maybe_auto_scroll`

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

No-op. Streaming events call this; renderer handles pinning.

# `move_cursor_down`

```elixir
@spec move_cursor_down(t()) :: t() | :at_bottom
```

Moves cursor down within the input. Returns `:at_bottom` if already on the last line.

# `move_cursor_up`

```elixir
@spec move_cursor_up(t()) :: t() | :at_top
```

Moves cursor up within the input. Returns `:at_top` if already on the first line.

# `new`

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

Creates a new UIState with default sub-structs.

# `next_search_match`

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

Moves to the next search match.

# `paste_block_index`

```elixir
@spec paste_block_index(String.t()) :: non_neg_integer() | nil
```

Returns the paste block index for a placeholder line, or nil if not a placeholder.

# `paste_block_line_count`

```elixir
@spec paste_block_line_count(t() | [paste_block()], non_neg_integer()) ::
  non_neg_integer()
```

Returns the line count for a paste block at the given index.

# `paste_placeholder?`

```elixir
@spec paste_placeholder?(String.t()) :: boolean()
```

Returns true if the given line is a paste placeholder token.

# `prev_search_match`

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

Moves to the previous search match.

# `prompt_text`

```elixir
@spec prompt_text(t() | MingaEditor.Agent.UIState.Panel.t()) :: String.t()
```

Returns the prompt text with paste placeholders substituted.

This is the text submitted to the LLM. Placeholder tokens are replaced
with the full paste content from `pasted_blocks`.

# `push_toast`

```elixir
@spec push_toast(t(), String.t(), :info | :warning | :error) :: t()
```

Pushes a toast.

# `record_baseline`

```elixir
@spec record_baseline(t(), String.t(), String.t()) :: t()
```

Records the baseline content for a file path (first edit only).

# `reset_split`

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

Resets the chat panel width to the configured default.

# `save_to_history`

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

Saves the current input to prompt history (if non-empty).

# `scroll_down`

```elixir
@spec scroll_down(t(), non_neg_integer()) :: t()
```

Scrolls the content down. Delegates to `Minga.Editing.Minga.Editing.scroll_down/2`.

# `scroll_to_bottom`

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

Pins chat to bottom. Delegates to `Minga.Editing.Minga.Editing.pin_to_bottom/1`.

# `scroll_to_top`

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

Scrolls to top. Delegates to `Minga.Editing.Minga.Editing.scroll_to_top/1`.

# `scroll_up`

```elixir
@spec scroll_up(t(), non_neg_integer()) :: t()
```

Scrolls the content up. Delegates to `Minga.Editing.Minga.Editing.scroll_up/2`.

# `scroll_viewer_down`

```elixir
@spec scroll_viewer_down(t(), pos_integer()) :: t()
```

Scrolls the preview pane down by the given number of lines.

# `scroll_viewer_to_bottom`

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

Scrolls the preview pane to a large offset (renderer clamps to actual content).

# `scroll_viewer_to_top`

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

Scrolls the preview pane to the top (offset 0).

# `scroll_viewer_up`

```elixir
@spec scroll_viewer_up(t(), pos_integer()) :: t()
```

Scrolls the preview pane up by the given number of lines, clamped at 0.

# `search_input_active?`

```elixir
@spec search_input_active?(t() | MingaEditor.Agent.UIState.View.t()) :: boolean()
```

Returns true if search input is being typed.

# `search_query`

```elixir
@spec search_query(t() | MingaEditor.Agent.UIState.View.t()) :: String.t() | nil
```

Returns the search query, or nil if not searching.

# `search_saved_scroll`

```elixir
@spec search_saved_scroll(t() | MingaEditor.Agent.UIState.View.t()) ::
  non_neg_integer() | nil
```

Returns the saved scroll position from before search started.

# `searching?`

```elixir
@spec searching?(t() | MingaEditor.Agent.UIState.View.t()) :: boolean()
```

Returns true if search is active.

# `set_focus`

```elixir
@spec set_focus(t(), MingaEditor.Agent.UIState.View.focus()) :: t()
```

Switches focus to the given panel.

# `set_input_focused`

```elixir
@spec set_input_focused(t(), boolean()) :: t()
```

Sets the input focus state. Entering focus ensures the prompt buffer exists.

# `set_model_name`

```elixir
@spec set_model_name(t(), String.t()) :: t()
```

Sets the model name.

# `set_prefix`

```elixir
@spec set_prefix(t(), MingaEditor.Agent.UIState.View.prefix()) :: t()
```

Sets the pending prefix for multi-key sequences.

# `set_prompt_text`

```elixir
@spec set_prompt_text(t(), String.t()) :: t()
```

Replaces the input content with the given text. Does not save to history.

# `set_provider_name`

```elixir
@spec set_provider_name(t(), String.t()) :: t()
```

Sets the provider name.

# `set_scroll`

```elixir
@spec set_scroll(t(), non_neg_integer()) :: t()
```

Sets the scroll offset to an absolute value. Unpins from bottom.

# `set_search_matches`

```elixir
@spec set_search_matches(t(), [MingaEditor.Agent.UIState.View.search_match()]) :: t()
```

Sets search matches and resets current to 0.

# `set_thinking_level`

```elixir
@spec set_thinking_level(t(), String.t()) :: t()
```

Sets the thinking level.

# `shrink_chat`

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

Shrinks the chat panel width by one step (clamped at min).

# `start_search`

```elixir
@spec start_search(t(), non_neg_integer()) :: t()
```

Starts a search, saving the current scroll position.

# `tick_spinner`

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

Advances the spinner animation frame.

# `toast_visible?`

```elixir
@spec toast_visible?(t() | MingaEditor.Agent.UIState.View.t()) :: boolean()
```

Returns true if a toast is currently visible.

# `toggle`

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

Toggles panel visibility.

# `toggle_help`

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

Toggles the help overlay visibility.

# `toggle_paste_expand`

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

Toggles expand/collapse on the paste block at the current cursor line.

# `update_preview`

```elixir
@spec update_preview(t(), (MingaEditor.Agent.View.Preview.t() -&gt;
                       MingaEditor.Agent.View.Preview.t())) ::
  t()
```

Updates the preview state with the given function.

# `update_search_query`

```elixir
@spec update_search_query(t(), String.t()) :: t()
```

Updates the search query string.

---

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