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
raxol_terminal lib raxol terminal commands cursor_utils.ex
Raw

lib/raxol/terminal/commands/cursor_utils.ex

defmodule Raxol.Terminal.Commands.CursorUtils do
@moduledoc """
Shared utility functions for cursor handling commands.
Eliminates code duplication between CursorHandler and CSIHandler.
"""
@doc """
Calculates new cursor position based on direction and movement amount.
Ensures the new position is within the emulator bounds.
## Parameters
- current_pos: Current {row, col} position
- direction: Direction to move (:up, :down, :left, :right)
- amount: Number of positions to move
- width: Emulator width for boundary checking
- height: Emulator height for boundary checking
## Returns
New {row, col} position clamped to bounds
"""
@spec calculate_new_cursor_position(
{non_neg_integer(), non_neg_integer()},
atom(),
non_neg_integer(),
pos_integer(),
pos_integer()
) :: {non_neg_integer(), non_neg_integer()}
def calculate_new_cursor_position(
{row, col},
direction,
amount,
width,
height
) do
case direction do
:up -> {max(0, row - amount), col}
:down -> {min(height - 1, row + amount), col}
:left -> {row, max(0, col - amount)}
:right -> {row, min(width - 1, col + amount)}
end
end
@doc """
Saves the current cursor position into the emulator state.
"""
def save_cursor_position(emulator) do
cursor = emulator.cursor
updated_cursor = %{
cursor
| saved_row: cursor.row,
saved_col: cursor.col,
saved_position: {cursor.row, cursor.col}
}
saved_cursor = cursor
%{emulator | cursor: updated_cursor, saved_cursor: saved_cursor}
end
@doc """
Restores a previously saved cursor position from the emulator state.
"""
def restore_cursor_position(emulator) do
case Map.get(emulator, :saved_cursor) do
nil ->
cursor = emulator.cursor
{new_row, new_col} =
case {cursor.saved_row, cursor.saved_col} do
{nil, nil} -> {cursor.row, cursor.col}
{row, col} -> {row, col}
end
updated_cursor = %{
cursor
| row: new_row,
col: new_col,
position: {new_row, new_col}
}
%{emulator | cursor: updated_cursor}
saved_cursor ->
row = saved_cursor.row
col = saved_cursor.col
updated_cursor = %{
emulator.cursor
| row: row,
col: col,
position: {row, col},
shape: Map.get(saved_cursor, :shape, emulator.cursor.shape),
visible: Map.get(saved_cursor, :visible, emulator.cursor.visible)
}
%{emulator | cursor: updated_cursor}
end
end
end