MingaEditor.State.TabBar (Minga v0.1.0)

Copy Markdown View Source

Ordered list of open tabs with an active tab pointer.

The tab bar is the primary navigation structure. Each tab (file or agent) carries a context snapshot of per-tab editor state. Buffer processes live in a shared pool, not inside individual tabs.

Invariants

  • There is always at least one tab.
  • active_id always refers to an existing tab.
  • Tab ids are unique and monotonically increasing.

Summary

Types

t()

Tab bar state.

Functions

Returns the active tab.

Returns the active agent group.

Returns the active agent group id, derived from the active tab.

Returns the index of the active tab (0-based).

Adds a new tab after the active tab and makes it active.

Adds an agent agent group and returns {updated_tab_bar, agent group}.

Returns true if any tab has its attention flag set.

Returns the number of tabs.

Returns the progressive disclosure tier (0-3) based on agent group count.

Returns all tabs matching the given kind.

Returns the first tab matching the given kind, or nil.

Returns the agent tab whose session matches the given pid, or nil.

Returns the agent group matching the given session pid, or nil.

Returns an agent tab that has no session assigned, or nil.

Returns the tab with the given id, or nil.

Returns the agent group with the given id, or nil.

Returns true if any agent agent_groups exist.

Returns true if a tab with the given id exists.

Inserts a new tab next to the active tab without switching to it.

Returns the most recently used tab of the given kind that is NOT the active tab. Useful for "switch back to previous file/agent" commands.

Moves a tab to a different agent group.

Creates a tab bar with a single initial tab.

Switches to the next tab, wrapping around.

Switches to the next agent group, wrapping around. No-op if no groups.

Cycles to the next tab of the given kind, wrapping around. If the active tab is already of that kind, jumps to the next one. If the active tab is a different kind, jumps to the first of the requested kind. Returns unchanged if no tabs of that kind exist.

Switches to the previous tab, wrapping around.

Switches to the previous agent group, wrapping around. No-op if no groups.

Removes the tab with the given id.

Removes a agent group and migrates its tabs to ungrouped (group_id 0).

Sets the attention flag on the tab matching the given session pid.

Switches the active tab to the one with the given id.

Switches to the given agent group by activating its first tab.

Returns the tab at the given 1-based position index, or nil.

Returns all tabs belonging to the given agent group.

Updates the context of the tab with the given id.

Updates a agent group by applying fun to it.

Updates the label of the tab with the given id.

Applies fun to the tab with id, replacing it in the list.

Types

t()

@type t() :: %MingaEditor.State.TabBar{
  active_id: MingaEditor.State.Tab.id(),
  agent_groups: [MingaEditor.State.AgentGroup.t()],
  next_group_id: pos_integer(),
  next_id: MingaEditor.State.Tab.id(),
  tabs: [MingaEditor.State.Tab.t()]
}

Tab bar state.

Functions

active(tab_bar)

@spec active(t()) :: MingaEditor.State.Tab.t() | nil

Returns the active tab.

active_group(tb)

@spec active_group(t()) :: MingaEditor.State.AgentGroup.t() | nil

Returns the active agent group.

Derived from the active tab's group_id, not stored separately. The active agent group is always the agent group of the tab you're looking at.

active_group_id(tb)

@spec active_group_id(t()) :: non_neg_integer()

Returns the active agent group id, derived from the active tab.

active_index(tab_bar)

@spec active_index(t()) :: non_neg_integer()

Returns the index of the active tab (0-based).

add(tb, kind, label \\ "")

Adds a new tab after the active tab and makes it active.

Returns {updated_tab_bar, new_tab} so the caller can use the tab's id.

add_agent_group(tb, label, session \\ nil)

@spec add_agent_group(t(), String.t(), pid() | nil) ::
  {t(), MingaEditor.State.AgentGroup.t()}

Adds an agent agent group and returns {updated_tab_bar, agent group}.

The agent group is appended to the agent groups list. The session pid is stored so we can track which agent owns the agent group.

any_attention?(tab_bar)

@spec any_attention?(t()) :: boolean()

Returns true if any tab has its attention flag set.

count(tab_bar)

@spec count(t()) :: pos_integer()

Returns the number of tabs.

disclosure_tier(tb)

@spec disclosure_tier(t()) :: 0 | 1 | 2 | 3

Returns the progressive disclosure tier (0-3) based on agent group count.

filter_by_kind(tab_bar, kind)

@spec filter_by_kind(t(), MingaEditor.State.Tab.kind()) :: [MingaEditor.State.Tab.t()]

Returns all tabs matching the given kind.

find_by_kind(tab_bar, kind)

@spec find_by_kind(t(), MingaEditor.State.Tab.kind()) ::
  MingaEditor.State.Tab.t() | nil

Returns the first tab matching the given kind, or nil.

find_by_session(tab_bar, session_pid)

@spec find_by_session(t(), pid()) :: MingaEditor.State.Tab.t() | nil

Returns the agent tab whose session matches the given pid, or nil.

find_group_by_session(tab_bar, session_pid)

@spec find_group_by_session(t(), pid()) :: MingaEditor.State.AgentGroup.t() | nil

Returns the agent group matching the given session pid, or nil.

find_sessionless_agent(tab_bar)

@spec find_sessionless_agent(t()) :: MingaEditor.State.Tab.t() | nil

Returns an agent tab that has no session assigned, or nil.

Used by start_agent_session to find the correct tab to bind a new session to, avoiding ambiguity when multiple agent tabs exist. Falls back to the active tab if it's an agent tab.

get(tab_bar, id)

Returns the tab with the given id, or nil.

get_group(tab_bar, id)

@spec get_group(t(), non_neg_integer()) :: MingaEditor.State.AgentGroup.t() | nil

Returns the agent group with the given id, or nil.

has_agent_groups?(tab_bar)

@spec has_agent_groups?(t()) :: boolean()

Returns true if any agent agent_groups exist.

has_tab?(tab_bar, id)

@spec has_tab?(t(), MingaEditor.State.Tab.id()) :: boolean()

Returns true if a tab with the given id exists.

insert(tb, kind, label \\ "")

Inserts a new tab next to the active tab without switching to it.

Returns {updated_tab_bar, new_tab}. The caller is responsible for calling switch_to/2 or EditorState.switch_tab/2 to activate it. This is the primitive that add/3 and EditorState.add_buffer/2 build on.

most_recent_of_kind(tab_bar, kind)

@spec most_recent_of_kind(t(), MingaEditor.State.Tab.kind()) ::
  MingaEditor.State.Tab.t() | nil

Returns the most recently used tab of the given kind that is NOT the active tab. Useful for "switch back to previous file/agent" commands.

Tabs are searched right-to-left from the active position (wrapping), so the nearest neighbor of the requested kind is returned.

move_tab_to_group(tb, tab_id, group_id)

@spec move_tab_to_group(t(), MingaEditor.State.Tab.id(), non_neg_integer()) :: t()

Moves a tab to a different agent group.

new(tab)

@spec new(MingaEditor.State.Tab.t()) :: t()

Creates a tab bar with a single initial tab.

next(tb)

@spec next(t()) :: t()

Switches to the next tab, wrapping around.

next_agent_group(tb)

@spec next_agent_group(t()) :: t()

Switches to the next agent group, wrapping around. No-op if no groups.

next_of_kind(tb, kind)

@spec next_of_kind(t(), MingaEditor.State.Tab.kind()) :: t()

Cycles to the next tab of the given kind, wrapping around. If the active tab is already of that kind, jumps to the next one. If the active tab is a different kind, jumps to the first of the requested kind. Returns unchanged if no tabs of that kind exist.

prev(tb)

@spec prev(t()) :: t()

Switches to the previous tab, wrapping around.

prev_agent_group(tb)

@spec prev_agent_group(t()) :: t()

Switches to the previous agent group, wrapping around. No-op if no groups.

remove(tb, id)

@spec remove(t(), MingaEditor.State.Tab.id()) :: {:ok, t()} | :last_tab

Removes the tab with the given id.

If the removed tab was active, switches to the nearest neighbor (prefer right, then left). Returns {:ok, updated_tab_bar} or :last_tab if this is the only tab (can't remove the last one).

remove_group(tb, group_id)

@spec remove_group(t(), non_neg_integer()) :: t()

Removes a agent group and migrates its tabs to ungrouped (group_id 0).

Cannot remove group_id 0 (ungrouped tabs).

set_attention_by_session(tb, session_pid, value)

@spec set_attention_by_session(t(), pid(), boolean()) :: t()

Sets the attention flag on the tab matching the given session pid.

switch_to(tb, id)

@spec switch_to(t(), MingaEditor.State.Tab.id()) :: t()

Switches the active tab to the one with the given id.

switch_to_group(tb, group_id)

@spec switch_to_group(t(), non_neg_integer()) :: t()

Switches to the given agent group by activating its first tab.

Returns unchanged if the agent group doesn't exist or has no tabs.

tab_at(arg1, index)

@spec tab_at(t(), pos_integer()) :: MingaEditor.State.Tab.t() | nil

Returns the tab at the given 1-based position index, or nil.

tabs_in_group(tab_bar, group_id)

@spec tabs_in_group(t(), non_neg_integer()) :: [MingaEditor.State.Tab.t()]

Returns all tabs belonging to the given agent group.

update_context(tb, id, context)

@spec update_context(t(), MingaEditor.State.Tab.id(), MingaEditor.State.Tab.context()) ::
  t()

Updates the context of the tab with the given id.

update_group(tb, id, fun)

Updates a agent group by applying fun to it.

Returns unchanged tab bar if no agent group matches.

update_label(tb, id, label)

@spec update_label(t(), MingaEditor.State.Tab.id(), String.t()) :: t()

Updates the label of the tab with the given id.

update_tab(tb, id, fun)

Applies fun to the tab with id, replacing it in the list.

Returns the updated tab bar. If no tab matches, returns unchanged.