Packages
Terminal emulation and driver infrastructure for Raxol. ANSI parsing, screen buffers, command processing, cursor management, input handling, session management, and termbox2 NIF integration.
Current section
Files
Jump to
Current section
Files
lib/raxol/terminal/cursor/cursor_state.ex
defmodule Raxol.Terminal.Cursor.CursorState do
@moduledoc """
Handles cursor state management operations for the terminal cursor.
Extracted from Raxol.Terminal.Cursor.Manager to reduce file size.
"""
alias Raxol.Terminal.Cursor.Manager
@doc """
Saves the current cursor state.
"""
def save_state(%Manager{} = state) do
%{
state
| saved_row: state.row,
saved_col: state.col,
saved_style: state.style,
saved_visible: state.visible,
saved_blinking: state.blinking,
saved_color: state.color,
saved_position: {state.row, state.col}
}
end
@doc """
Restores the saved cursor state.
"""
def restore_state(%Manager{} = state) do
%{
state
| row: state.saved_row || state.row,
col: state.saved_col || state.col,
style: state.saved_style || state.style,
visible: state.saved_visible || state.visible,
blinking: state.saved_blinking || state.blinking,
color: state.saved_color || state.color,
position: state.saved_position || {state.row, state.col}
}
end
@doc """
Resets the cursor state to default values.
"""
def reset(%Manager{} = state) do
%{
state
| row: 0,
col: 0,
position: {0, 0},
visible: true,
blinking: true,
style: :block,
color: nil,
saved_row: nil,
saved_col: nil,
saved_style: nil,
saved_visible: nil,
saved_blinking: nil,
saved_color: nil
}
end
@doc """
Sets the cursor state based on a state atom.
Supported states: :visible, :hidden, :blinking
"""
def set_state(%Manager{} = state, state_atom),
do: do_set_state(state, state_atom)
defp do_set_state(state, :visible),
do: %{state | visible: true, state: :visible}
defp do_set_state(state, :hidden),
do: %{state | visible: false, state: :hidden}
defp do_set_state(state, :blinking),
do: %{state | blinking: true, blink: true, state: :blinking}
@doc """
Saves the current cursor position.
"""
def save_position(%Manager{} = state) do
%{
state
| saved_row: state.row,
saved_col: state.col,
saved_position: {state.row, state.col}
}
end
@doc """
Restores the saved cursor position.
"""
def restore_position(%Manager{} = state) do
case {state.saved_row, state.saved_col} do
{nil, _} ->
state
{_, nil} ->
state
{row, col} ->
%{
state
| row: row,
col: col,
position: {row, col}
}
end
end
@doc """
Adds the current cursor state to history.
"""
def add_to_history(%Manager{} = state) do
history_entry = %{
row: state.row,
col: state.col,
style: state.style,
visible: state.visible,
blinking: state.blinking,
state: state.state,
position: {state.row, state.col}
}
%{
state
| history: [history_entry | state.history],
history_index: state.history_index + 1
}
end
@doc """
Restores cursor state from history.
"""
def restore_from_history(%Manager{} = state) do
case state.history do
[entry | rest] ->
%{
state
| row: entry.row,
col: entry.col,
style: entry.style,
visible: entry.visible,
blinking: entry.blinking,
state: entry.state,
position: {entry.row, entry.col},
history: rest
}
[] ->
state
end
end
@doc """
Gets the cursor state atom (:visible, :hidden, :blinking).
"""
def get_state(%Manager{state: state}), do: state
@doc """
Sets the cursor margins.
"""
def set_margins(cursor, top, bottom) do
%{cursor | top_margin: top, bottom_margin: bottom}
end
@doc """
Gets the cursor margins.
"""
def get_margins(cursor) do
{cursor.top_margin, cursor.bottom_margin}
end
@doc """
Sets a custom cursor shape.
"""
def set_custom_shape(%Manager{} = state, shape, params),
do: %{
state
| style: :custom,
custom_shape: shape,
custom_dimensions: params,
shape: params
}
@doc """
Updates cursor position based on text input.
"""
def update_position_from_text(%Manager{} = cursor, text)
when is_binary(text) do
# Calculate new position based on text length
new_col = cursor.col + String.length(text)
%{cursor | col: new_col, position: {cursor.row, new_col}}
end
@doc """
Updates the cursor blink state.
"""
def update_blink(%Manager{state: :visible} = state), do: {state, true}
def update_blink(%Manager{state: :hidden} = state), do: {state, false}
def update_blink(%Manager{state: :blinking, blink: blink} = state) do
new_blink = !blink
{%{state | blink: new_blink}, new_blink}
end
end