# `MingaEditor.State.Tab`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/state/tab.ex#L1)

A single tab in the tab bar.

Each tab has a unique id, a kind (`:file` or `:agent`), a display label,
and a context map that stores snapshotted per-tab state when the tab is
inactive. The active tab's context is "live" on EditorState; inactive
tabs carry a frozen snapshot that gets restored when you switch to them.

## Context format

The canonical context is a flat map with per-tab fields (buffers, windows,
vim state, viewport, etc.) stored directly. Legacy contexts with nested
structure are auto-migrated on first restore.

# `agent_status`

```elixir
@type agent_status() :: :idle | :thinking | :tool_executing | :error | nil
```

Agent tab status (nil for file tabs).

# `context`

```elixir
@type context() :: %{
  optional(:keymap_scope) =&gt; atom(),
  optional(:buffers) =&gt; term(),
  optional(:windows) =&gt; term(),
  optional(:file_tree) =&gt; term(),
  optional(:viewport) =&gt; term(),
  optional(:mouse) =&gt; term(),
  optional(:highlight) =&gt; term(),
  optional(:lsp_pending) =&gt; term(),
  optional(:completion) =&gt; term(),
  optional(:completion_trigger) =&gt; term(),
  optional(:injection_ranges) =&gt; term(),
  optional(:search) =&gt; term(),
  optional(:pending_conflict) =&gt; term(),
  optional(:editing) =&gt; MingaEditor.VimState.t(),
  optional(:vim) =&gt; MingaEditor.VimState.t(),
  optional(:document_highlights) =&gt; term(),
  optional(:agent_ui) =&gt; term(),
  optional(:mode) =&gt; atom(),
  optional(:mode_state) =&gt; term(),
  optional(:reg) =&gt; term(),
  optional(:marks) =&gt; term(),
  optional(:last_jump_pos) =&gt; term(),
  optional(:last_find_char) =&gt; term(),
  optional(:change_recorder) =&gt; term(),
  optional(:macro_recorder) =&gt; term()
}
```

Snapshotted per-tab state.

The context stores per-tab fields directly (buffers, windows, mode, etc.).
Empty context means a brand-new tab.

Legacy contexts with nested structure (old snapshot format) or
bare fields (oldest format) are auto-migrated on first restore.

# `group_id`

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

Workspace group id. 0 = manual/ungrouped workspace.

# `id`

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

Unique tab identifier.

# `kind`

```elixir
@type kind() :: :file | :agent
```

Tab kind.

# `t`

```elixir
@type t() :: %MingaEditor.State.Tab{
  agent_status: agent_status(),
  attention: boolean(),
  context: context(),
  group_id: group_id(),
  id: id(),
  kind: kind(),
  label: String.t(),
  session: pid() | nil
}
```

A tab.

# `agent?`

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

Returns true if this is an agent tab.

# `file?`

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

Returns true if this is a file tab.

# `new_agent`

```elixir
@spec new_agent(id(), String.t()) :: t()
```

Creates a new agent tab.

# `new_file`

```elixir
@spec new_file(id(), String.t()) :: t()
```

Creates a new file tab.

# `set_agent_status`

```elixir
@spec set_agent_status(t(), agent_status()) :: t()
```

Sets the agent status on a tab (for tab bar rendering).

# `set_attention`

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

Sets the attention flag (agent needs user input).

# `set_context`

```elixir
@spec set_context(t(), context()) :: t()
```

Stores a context snapshot into the tab.

# `set_group`

```elixir
@spec set_group(t(), group_id()) :: t()
```

Sets the workspace group id.

# `set_label`

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

Updates the tab's label.

# `set_session`

```elixir
@spec set_session(t(), pid() | nil) :: t()
```

Sets the session pid for an agent tab.

---

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