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/scroll_ops.ex
defmodule Raxol.Terminal.ScreenBuffer.ScrollOps do
@moduledoc """
Scroll operations for ScreenBuffer: region management and scroll up/down.
"""
alias Raxol.Terminal.Cell
alias Raxol.Terminal.ScreenBuffer.Operations
# ========================================
# Region management
# ========================================
def scroll_to(buffer, top, bottom, line) do
Operations.scroll_to(buffer, top, bottom, line)
end
def reset_scroll_region(buffer), do: clear_scroll_region(buffer)
def get_scroll_top(buffer) do
case buffer.scroll_region do
nil -> 0
{top, _} -> top
end
end
def get_scroll_bottom(buffer) do
case buffer.scroll_region do
nil -> buffer.height - 1
{_, bottom} -> bottom
end
end
def set_scroll_region(buffer, {top, bottom}) do
Operations.set_region(buffer, top, bottom)
end
def set_scroll_region(buffer, top, bottom)
when is_integer(top) and is_integer(bottom) do
Operations.set_region(buffer, top, bottom)
end
def clear_scroll_region(buffer), do: %{buffer | scroll_region: nil}
def get_scroll_region_boundaries(buffer) do
case buffer.scroll_region do
nil -> {0, buffer.height - 1}
{top, bottom} -> {top, bottom}
end
end
def get_scroll_position(buffer), do: buffer.scroll_position || 0
def get_scroll_region(buffer), do: Operations.get_region(buffer)
def shift_region_to_line(buffer, region, target_line) do
Operations.shift_region_to_line(buffer, region, target_line)
end
def scroll_down_with_count(buffer, lines, count)
when is_integer(lines) and is_integer(count) do
Raxol.Terminal.Commands.Scrolling.scroll_down(
buffer,
lines,
buffer.scroll_region,
%{}
)
end
def scroll_down_with_count(buffer, _lines, count) when is_integer(count) do
scroll_down(buffer, count)
end
# ========================================
# Scroll content (formerly in Scrolling)
# ========================================
@doc """
Scrolls the buffer content up by the specified number of lines within the scroll region.
Returns {buffer, scrolled_lines}.
"""
def scroll_up(buffer, lines) when lines > 0 do
{top, bottom} = get_effective_scroll_region(buffer)
if top < bottom do
cells = buffer.cells || []
{before_region, region_and_after} = Enum.split(cells, top)
{region, after_region} = Enum.split(region_and_after, bottom - top + 1)
lines_to_scroll = min(lines, length(region))
scrolled_out = Enum.take(region, lines_to_scroll)
remaining_region = Enum.drop(region, lines_to_scroll)
empty_lines = List.duplicate(create_empty_line(buffer.width), lines_to_scroll)
scrolled_region = remaining_region ++ empty_lines
new_cells = before_region ++ scrolled_region ++ after_region
{%{buffer | cells: new_cells}, scrolled_out}
else
{buffer, []}
end
end
def scroll_up(buffer, _), do: {buffer, []}
@doc """
Scrolls the buffer content down by the specified number of lines within the scroll region.
"""
def scroll_down(buffer, lines) when lines > 0 do
{top, bottom} = get_effective_scroll_region(buffer)
if top < bottom do
cells = buffer.cells || []
{before_region, region_and_after} = Enum.split(cells, top)
{region, after_region} = Enum.split(region_and_after, bottom - top + 1)
lines_to_scroll = min(lines, length(region))
empty_lines = List.duplicate(create_empty_line(buffer.width), lines_to_scroll)
kept_region = Enum.take(region, length(region) - lines_to_scroll)
scrolled_region = empty_lines ++ kept_region
new_cells = before_region ++ scrolled_region ++ after_region
%{buffer | cells: new_cells}
else
buffer
end
end
def scroll_down(buffer, _), do: buffer
@doc """
Scrolls up within an explicit top/bottom region.
"""
def scroll_up(buffer, top, bottom, lines) do
{effective_top, effective_bottom} = normalize_scroll_region(buffer, top, bottom)
cells = buffer.cells || []
if effective_top < effective_bottom and lines > 0 do
{before_region, region_and_after} = Enum.split(cells, effective_top)
{region, after_region} = Enum.split(region_and_after, effective_bottom - effective_top + 1)
lines_to_scroll = min(lines, length(region))
kept_region = Enum.drop(region, lines_to_scroll)
empty_lines = List.duplicate(create_empty_line(buffer.width), lines_to_scroll)
scrolled_region = kept_region ++ empty_lines
new_cells = before_region ++ scrolled_region ++ after_region
%{buffer | cells: new_cells}
else
buffer
end
end
@doc """
Scrolls down within an explicit top/bottom region.
"""
def scroll_down(buffer, top, bottom, lines) do
{effective_top, effective_bottom} = normalize_scroll_region(buffer, top, bottom)
cells = buffer.cells || []
if effective_top < effective_bottom and lines > 0 do
{before_region, region_and_after} = Enum.split(cells, effective_top)
{region, after_region} = Enum.split(region_and_after, effective_bottom - effective_top + 1)
lines_to_scroll = min(lines, length(region))
empty_lines = List.duplicate(create_empty_line(buffer.width), lines_to_scroll)
kept_region = Enum.take(region, length(region) - lines_to_scroll)
scrolled_region = empty_lines ++ kept_region
new_cells = before_region ++ scrolled_region ++ after_region
%{buffer | cells: new_cells}
else
buffer
end
end
# Private helpers
defp get_effective_scroll_region(buffer) do
case buffer.scroll_region do
nil -> {0, buffer.height - 1}
{top, bottom} -> {top, min(bottom, buffer.height - 1)}
end
end
defp normalize_scroll_region(buffer, top, bottom) do
{max(0, top), min(buffer.height - 1, bottom)}
end
defp create_empty_line(width) when is_integer(width) and width > 0 do
List.duplicate(Cell.new(), width)
end
defp create_empty_line(_width), do: []
end