Packages

Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.

Current section

Files

Jump to
raxol lib raxol terminal emulator emulator_buffer.ex
Raw

lib/raxol/terminal/emulator/emulator_buffer.ex

defmodule Raxol.Terminal.Emulator.Buffer do
@moduledoc """
Provides buffer management functionality for the terminal emulator.
"""
alias Raxol.Terminal.ScreenBuffer
alias Raxol.Terminal.Emulator.Struct, as: EmulatorStruct
@doc """
Switches between main and alternate screen buffers.
Returns {:ok, updated_emulator} or {:error, reason}.
"""
@spec switch_buffer(EmulatorStruct.t(), :main | :alternate) ::
{:ok, EmulatorStruct.t()} | {:error, String.t()}
def switch_buffer(%EmulatorStruct{} = emulator, :main) do
{:ok, %{emulator | active_buffer_type: :main}}
end
def switch_buffer(%EmulatorStruct{} = emulator, :alternate) do
{:ok, %{emulator | active_buffer_type: :alternate}}
end
def switch_buffer(%EmulatorStruct{} = _emulator, invalid_type) do
{:error, "Invalid buffer type: #{inspect(invalid_type)}"}
end
@doc """
Sets the scroll region for the active buffer.
Returns {:ok, updated_emulator} or {:error, reason}.
"""
@spec set_scroll_region(
EmulatorStruct.t(),
non_neg_integer(),
non_neg_integer()
) ::
{:ok, EmulatorStruct.t()} | {:error, String.t()}
def set_scroll_region(%EmulatorStruct{} = emulator, top, bottom)
when top < bottom do
{:ok, %{emulator | scroll_region: {top, bottom}}}
end
def set_scroll_region(%EmulatorStruct{} = _emulator, top, bottom) do
{:error,
"Invalid scroll region: top (#{top}) must be less than bottom (#{bottom})"}
end
@doc """
Clears the scroll region, allowing scrolling of the entire screen.
Returns {:ok, updated_emulator}.
"""
@spec clear_scroll_region(EmulatorStruct.t()) :: {:ok, EmulatorStruct.t()}
def clear_scroll_region(%EmulatorStruct{} = emulator) do
{:ok, %{emulator | scroll_region: nil}}
end
@doc """
Scrolls the buffer up by the specified number of lines.
"""
def scroll_up_emulator(emulator, lines) do
{updated_emulator, _scrolled_lines} =
ScreenBuffer.scroll_up(emulator, lines)
%{updated_emulator | active_buffer: updated_emulator.active_buffer}
end
@doc """
Scrolls the buffer down by the specified number of lines.
"""
def scroll_down(emulator, lines) do
buffer = get_active_buffer(emulator)
updated_buffer = ScreenBuffer.scroll_down(buffer, lines)
update_active_buffer(emulator, updated_buffer)
end
defp get_active_buffer(emulator) do
case emulator.active_buffer_type do
:main -> emulator.main_screen_buffer
:alternate -> emulator.alternate_screen_buffer
_ -> emulator.main_screen_buffer
end
end
defp update_active_buffer(emulator, buffer) do
case emulator.active_buffer_type do
:main -> %{emulator | main_screen_buffer: buffer}
:alternate -> %{emulator | alternate_screen_buffer: buffer}
_ -> %{emulator | main_screen_buffer: buffer}
end
end
@doc """
Clears the entire buffer.
"""
def clear_buffer(emulator) do
updated_emulator = ScreenBuffer.clear(emulator)
%{updated_emulator | cursor: %{updated_emulator.cursor | x: 0, y: 0}}
end
@doc """
Clears from cursor to end of screen.
"""
def clear_from_cursor_to_end(emulator) do
updated_emulator = ScreenBuffer.clear(emulator)
%{updated_emulator | cursor: %{updated_emulator.cursor | x: 0}}
end
@doc """
Clears from start of screen to cursor.
"""
def clear_from_cursor_to_start(emulator) do
updated_emulator = ScreenBuffer.clear(emulator)
%{updated_emulator | cursor: %{updated_emulator.cursor | x: 0}}
end
@doc """
Clears the current line.
"""
def clear_line(emulator) do
ScreenBuffer.clear_line(emulator, 2)
end
end