defmodule Raxol.Terminal.StateManager do @moduledoc """ Manages terminal state transitions and state stack operations. This module is responsible for maintaining and manipulating the terminal's state. This module implements the StateManager behavior for consistent state management patterns across the codebase while maintaining its specific terminal functionality. """ # Using consolidated StateManager for functional state operations alias Raxol.Core.StateManager # Delegate common state operations to consolidated StateManager def init, do: {:ok, %{}} def init(opts), do: {:ok, Keyword.get(opts, :initial_state, %{})} defdelegate get(state, key), to: StateManager defdelegate get(state, key, default), to: StateManager defdelegate put(state, key, value), to: StateManager defdelegate update(state, key, func), to: StateManager defdelegate delete(state, key), to: StateManager defdelegate clear(state), to: StateManager defdelegate validate(state), to: StateManager defdelegate merge(state1, state2), to: StateManager alias Raxol.Terminal.Emulator require Raxol.Core.Runtime.Log @doc """ Saves the current terminal state. Returns {:ok, updated_emulator}. """ @spec save_state(Emulator.t()) :: {:ok, Emulator.t()} def save_state(emulator) do current_state = %{ cursor: get_cursor_state(emulator), screen: get_screen_state(emulator), modes: get_mode_state(emulator) } new_stack = [current_state | emulator.state_stack] {:ok, %{emulator | state_stack: new_stack}} end @doc """ Restores the most recently saved terminal state. Returns {:ok, updated_emulator}. """ @spec restore_state(Emulator.t()) :: {:ok, Emulator.t()} def restore_state(emulator) do case emulator.state_stack do [state | new_stack] -> emulator = apply_saved_state(emulator, state) {:ok, %{emulator | state_stack: new_stack}} [] -> {:error, "No saved state to restore"} end end @doc """ Clears all saved states. Returns {:ok, updated_emulator}. """ @spec clear_states(Emulator.t()) :: {:ok, Emulator.t()} def clear_states(emulator) do {:ok, %{emulator | state_stack: []}} end @doc """ Gets the current terminal state. Returns the current state map. """ @spec get_current_state(Emulator.t()) :: map() def get_current_state(emulator) do %{ cursor: get_cursor_state(emulator), screen: get_screen_state(emulator), modes: get_mode_state(emulator) } end @doc """ Updates the current terminal state. Returns {:ok, updated_emulator}. """ @spec update_current_state(Emulator.t(), map()) :: {:ok, Emulator.t()} def update_current_state(emulator, new_state) do emulator = apply_saved_state(emulator, new_state) {:ok, emulator} end # Private helper functions defp get_cursor_state(emulator) do %{ position: emulator.cursor.position, visible: emulator.cursor.visible, style: emulator.cursor.style, blink_state: emulator.cursor.blink_state } end defp get_screen_state(emulator) do %{ buffer: emulator.active_buffer, scroll_region: emulator.scroll_region, charset_state: emulator.charset_state } end defp get_mode_state(emulator) do %{ insert_mode: emulator.mode_manager.insert_mode, origin_mode: emulator.mode_manager.origin_mode, auto_wrap: emulator.mode_manager.auto_wrap, cursor_visible: emulator.mode_manager.cursor_visible } end defp apply_saved_state(emulator, state) do emulator |> apply_cursor_state(state.cursor) |> apply_screen_state(state.screen) |> apply_mode_state(state.modes) end defp apply_cursor_state(emulator, cursor_state) do %{emulator | cursor: Map.merge(emulator.cursor, cursor_state)} end defp apply_screen_state(emulator, screen_state) do emulator |> Map.put(:active_buffer, screen_state.buffer) |> Map.put(:scroll_region, screen_state.scroll_region) |> Map.put(:charset_state, screen_state.charset_state) end defp apply_mode_state(emulator, mode_state) do %{emulator | mode_manager: Map.merge(emulator.mode_manager, mode_state)} end end