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/screen_buffer/operations/erasing.ex
defmodule Raxol.Terminal.ScreenBuffer.Operations.Erasing do
@moduledoc """
Erasing operations for the screen buffer.
This module handles various erasing operations including
erase in display and erase in line with different modes.
"""
alias Raxol.Terminal.Cell
alias Raxol.Terminal.ScreenBuffer
@doc """
Erases in display based on mode.
Mode values:
- 0: From cursor to end of display
- 1: From start to cursor
- 2: Entire display
- 3: Entire display including scrollback
"""
@spec erase_in_display(ScreenBuffer.t(), non_neg_integer(), map()) ::
ScreenBuffer.t()
def erase_in_display(buffer, mode, cursor_pos \\ %{x: 0, y: 0})
def erase_in_display(buffer, 0, cursor_pos) do
# Erase from cursor to end of display
erase_from_cursor_to_end(buffer, cursor_pos)
end
def erase_in_display(buffer, 1, cursor_pos) do
# Erase from start to cursor
erase_from_start_to_cursor(buffer, cursor_pos)
end
def erase_in_display(buffer, 2, _cursor_pos) do
# Erase entire display
clear_display(buffer)
end
def erase_in_display(buffer, 3, _cursor_pos) do
# Erase entire display including scrollback
clear_display_with_scrollback(buffer)
end
def erase_in_display(buffer, _, _), do: buffer
@doc """
Erases in line based on mode.
Mode values:
- 0: From cursor to end of line
- 1: From start of line to cursor
- 2: Entire line
"""
@spec erase_in_line(ScreenBuffer.t(), non_neg_integer(), map()) ::
ScreenBuffer.t()
def erase_in_line(buffer, mode, cursor_pos \\ %{x: 0, y: 0})
def erase_in_line(buffer, 0, cursor_pos) do
# Erase from cursor to end of line
erase_line_from_cursor_to_end(buffer, cursor_pos)
end
def erase_in_line(buffer, 1, cursor_pos) do
# Erase from start of line to cursor
erase_line_from_start_to_cursor(buffer, cursor_pos)
end
def erase_in_line(buffer, 2, cursor_pos) do
# Erase entire line
clear_line(buffer, cursor_pos.y)
end
def erase_in_line(buffer, _, _), do: buffer
# Private helper functions
defp erase_from_cursor_to_end(buffer, %{x: x, y: y}) do
cells = buffer.cells || []
new_cells =
cells
|> Enum.with_index()
|> Enum.map(fn {row, row_idx} ->
cond do
row_idx < y -> row
row_idx == y -> erase_row_from(row, x)
true -> create_empty_row(buffer.width)
end
end)
%{buffer | cells: new_cells}
end
defp erase_from_start_to_cursor(buffer, %{x: x, y: y}) do
cells = buffer.cells || []
new_cells =
cells
|> Enum.with_index()
|> Enum.map(fn {row, row_idx} ->
cond do
row_idx < y -> create_empty_row(buffer.width)
row_idx == y -> erase_row_to(row, x)
true -> row
end
end)
%{buffer | cells: new_cells}
end
defp erase_line_from_cursor_to_end(buffer, %{x: x, y: y}) do
cells = buffer.cells || []
new_cells =
cells
|> Enum.with_index()
|> Enum.map(fn {row, row_idx} ->
if row_idx == y do
erase_row_from(row, x)
else
row
end
end)
%{buffer | cells: new_cells}
end
defp erase_line_from_start_to_cursor(buffer, %{x: x, y: y}) do
cells = buffer.cells || []
new_cells =
cells
|> Enum.with_index()
|> Enum.map(fn {row, row_idx} ->
if row_idx == y do
erase_row_to(row, x)
else
row
end
end)
%{buffer | cells: new_cells}
end
defp clear_display(buffer) do
empty_cells =
for _ <- 0..(buffer.height - 1) do
create_empty_row(buffer.width)
end
%{buffer | cells: empty_cells}
end
defp clear_display_with_scrollback(buffer) do
buffer
|> clear_display()
|> Map.put(:scrollback, [])
end
defp clear_line(buffer, y) when y >= 0 and y < buffer.height do
cells = buffer.cells || []
new_cells =
cells
|> Enum.with_index()
|> Enum.map(fn {row, row_idx} ->
if row_idx == y do
create_empty_row(buffer.width)
else
row
end
end)
%{buffer | cells: new_cells}
end
defp clear_line(buffer, _), do: buffer
defp create_empty_row(width) do
List.duplicate(Cell.new(), width)
end
defp erase_row_from(row, x) do
row
|> Enum.with_index()
|> Enum.map(fn {cell, idx} ->
if idx >= x, do: Cell.new(), else: cell
end)
end
defp erase_row_to(row, x) do
row
|> Enum.with_index()
|> Enum.map(fn {cell, idx} ->
if idx <= x, do: Cell.new(), else: cell
end)
end
end