State struct and pure navigation logic for the Ash TUI explorer.
All state transitions are pure functions: handle_key(state, key) -> state.
No side effects, no processes — just data transformation.
Summary
Functions
Returns the breadcrumb trail from the navigation stack.
Returns the items for the currently active detail tab.
Processes a key press and returns the updated state.
Returns the list of items shown in the navigation panel.
Creates a new state from introspection data.
Types
@type t() :: %AshTui.State{ current_domain: AshTui.Introspection.DomainInfo.t() | nil, current_resource: AshTui.Introspection.ResourceInfo.t() | nil, current_tab: tab(), detail_overlay: AshTui.Introspection.AttributeInfo.t() | nil, detail_selected: non_neg_integer(), domains: [AshTui.Introspection.DomainInfo.t()], focus: :nav | :detail, nav_selected: non_neg_integer(), nav_stack: [{atom(), atom(), tab()}], search_input: reference() | nil, searching: boolean(), show_help: boolean() }
@type tab() :: :attributes | :actions | :relationships
Functions
Returns the breadcrumb trail from the navigation stack.
Examples
iex> domains = AshTui.Introspection.from_data([
...> %{
...> name: MyApp.Accounts,
...> resources: [
...> %{
...> name: MyApp.Accounts.User,
...> attributes: [%{name: :id, type: :uuid, primary_key?: true}],
...> actions: [],
...> relationships: []
...> }
...> ]
...> }
...> ])
iex> state = AshTui.State.new(domains)
iex> AshTui.State.breadcrumb(state)
"User"
iex> AshTui.State.breadcrumb(AshTui.State.new([]))
""
@spec detail_items(t()) :: [ AshTui.Introspection.AttributeInfo.t() | AshTui.Introspection.ActionInfo.t() | AshTui.Introspection.RelationshipInfo.t() ]
Returns the items for the currently active detail tab.
Examples
iex> domains = AshTui.Introspection.from_data([
...> %{
...> name: MyApp.Accounts,
...> resources: [
...> %{
...> name: MyApp.Accounts.User,
...> attributes: [%{name: :id, type: :uuid, primary_key?: true}],
...> actions: [%{name: :read, type: :read, primary?: true}],
...> relationships: []
...> }
...> ]
...> }
...> ])
iex> state = AshTui.State.new(domains)
iex> [attr] = AshTui.State.detail_items(state)
iex> attr.name
:id
iex> AshTui.State.detail_items(%AshTui.State{current_resource: nil})
[]
Processes a key press and returns the updated state.
Handles vim-style navigation (j/k/h/l), tab switching (tab, 1/2/3),
enter/esc for selection and back-navigation, ? for help, and / for search.
Examples
iex> domains = AshTui.Introspection.from_data([
...> %{
...> name: MyApp.Accounts,
...> resources: [
...> %{
...> name: MyApp.Accounts.User,
...> attributes: [%{name: :id, type: :uuid, primary_key?: true}],
...> actions: [],
...> relationships: []
...> }
...> ]
...> }
...> ])
iex> state = AshTui.State.new(domains)
iex> state = AshTui.State.handle_key(state, "?")
iex> state.show_help
true
iex> state = AshTui.State.handle_key(state, "any")
iex> state.show_help
false
iex> domains = AshTui.Introspection.from_data([
...> %{
...> name: MyApp.Accounts,
...> resources: [
...> %{
...> name: MyApp.Accounts.User,
...> attributes: [%{name: :id, type: :uuid, primary_key?: true}],
...> actions: [],
...> relationships: []
...> }
...> ]
...> }
...> ])
iex> state = AshTui.State.new(domains)
iex> state = AshTui.State.handle_key(state, "l")
iex> state.focus
:detail
iex> state = AshTui.State.handle_key(state, "h")
iex> state.focus
:nav
@spec new([AshTui.Introspection.DomainInfo.t()]) :: t()
Creates a new state from introspection data.
Examples
iex> domains = AshTui.Introspection.from_data([
...> %{
...> name: MyApp.Accounts,
...> resources: [
...> %{
...> name: MyApp.Accounts.User,
...> attributes: [%{name: :id, type: :uuid, primary_key?: true}],
...> actions: [],
...> relationships: []
...> }
...> ]
...> }
...> ])
iex> state = AshTui.State.new(domains)
iex> state.current_domain.name
MyApp.Accounts
iex> state.current_resource.name
MyApp.Accounts.User
iex> state.current_tab
:attributes
iex> state = AshTui.State.new([])
iex> state.current_domain
nil