Packages
Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.
Current section
Files
Jump to
Current section
Files
lib/raxol/plugins/examples/terminal_multiplexer/window_manager.ex
defmodule Raxol.Plugins.Examples.TerminalMultiplexer.WindowManager do
@moduledoc """
Window operations for the TerminalMultiplexerPlugin.
Handles window creation, navigation, and session management.
"""
alias Raxol.Core.Runtime.Log
alias Raxol.Plugins.Examples.TerminalMultiplexer.PaneManager
alias Raxol.Plugins.Examples.TerminalMultiplexerPlugin.{Session, Window}
@compile {:no_warn_undefined,
Raxol.Plugins.Examples.TerminalMultiplexer.PaneManager}
@compile {:no_warn_undefined,
Raxol.Plugins.Examples.TerminalMultiplexerPlugin.Session}
@compile {:no_warn_undefined,
Raxol.Plugins.Examples.TerminalMultiplexerPlugin.Window}
@doc "Creates a new window and adds it to the active session."
def create_new_window(state) do
session = get_active_session(state)
window =
create_window(
"shell-#{length(session.windows) + 1}",
state.config.default_shell
)
updated_session = %{
session
| # credo:disable-for-next-line Credo.Check.Refactor.AppendSingleItem
windows: session.windows ++ [window],
active_window: window.id
}
new_state = update_session(state, updated_session)
{:ok, new_state}
end
@doc "Switches to the next window in the active session."
def next_window(state) do
session = get_active_session(state)
current_index = find_window_index(session, session.active_window)
next_index = rem(current_index + 1, length(session.windows))
next_w = Enum.at(session.windows, next_index)
updated_session = %{session | active_window: next_w.id}
new_state = update_session(state, updated_session)
{:ok, new_state}
end
@doc "Switches to the previous window in the active session."
def previous_window(state) do
session = get_active_session(state)
current_index = find_window_index(session, session.active_window)
prev_index =
rem(current_index - 1 + length(session.windows), length(session.windows))
prev_w = Enum.at(session.windows, prev_index)
updated_session = %{session | active_window: prev_w.id}
new_state = update_session(state, updated_session)
{:ok, new_state}
end
@doc "Switches to the window at the given index."
def switch_to_window(state, index) do
session = get_active_session(state)
case Enum.at(session.windows, index) do
nil ->
{:ok, state}
window ->
updated_session = %{session | active_window: window.id}
new_state = update_session(state, updated_session)
{:ok, new_state}
end
end
@doc "Detaches from the current session."
def detach_session(state) do
Log.info("Detaching from session")
{:ok, state}
end
@doc "Shows the session list overlay."
def show_sessions(state) do
Log.info("Showing sessions")
sessions = Map.values(state.sessions)
Log.info("Sessions: #{inspect(sessions)}")
{:ok, state}
end
@doc "Shows the window list overlay."
def show_windows(state) do
Log.info("Showing windows")
session = get_active_session(state)
Log.info("Windows: #{inspect(session.windows)}")
{:ok, state}
end
@doc "Creates a new Session struct."
def create_session(name) do
%Session{
id: generate_id(),
name: name,
windows: [],
active_window: nil,
created_at: DateTime.utc_now()
}
end
@doc "Creates a new Window struct with a single pane."
def create_window(name, shell) do
pane = PaneManager.create_pane(shell)
%Window{
id: generate_id(),
name: name,
panes: [pane],
active_pane: pane.id,
layout: :single,
index: 0
}
end
# --- Private helpers ---
defp find_window_index(session, window_id) do
Enum.find_index(session.windows, &(&1.id == window_id)) || 0
end
defp generate_id do
:crypto.strong_rand_bytes(8) |> Base.encode16(case: :lower)
end
defp get_active_session(state),
do: Map.get(state.sessions, state.active_session)
defp update_session(state, session) do
%{state | sessions: Map.put(state.sessions, session.id, session)}
end
end