TermUI.Renderer.Buffer (TermUI v0.2.0)

View Source

ETS-based screen buffer for storing cells.

The buffer uses an ETS :ordered_set table keyed by {row, col} tuples for O(log n) access and efficient row-major iteration. This enables fast cell lookup and sequential rendering.

Usage

{:ok, buffer} = Buffer.new(24, 80)
Buffer.set_cell(buffer, 1, 1, Cell.new("A", fg: :red))
cell = Buffer.get_cell(buffer, 1, 1)
Buffer.destroy(buffer)

Coordinates

Rows and columns are 1-indexed to match terminal conventions.

Summary

Functions

Clears the entire buffer.

Clears a single column.

Clears a rectangular region, filling it with empty cells.

Clears a single row.

Destroys the buffer and frees ETS table.

Returns buffer dimensions as {rows, cols}.

Iterates over all cells in row-major order.

Gets the cell at the given position.

Gets a row as a list of cells.

Checks if a position is within buffer bounds.

Returns the maximum allowed columns.

Returns the maximum allowed rows.

Creates a new buffer with the given dimensions.

Resizes the buffer, preserving content where possible.

Sets the cell at the given position.

Sets multiple cells at once for efficiency.

Gets all cells as a list of {row, col, cell} tuples in row-major order.

Writes a string starting at the given position.

Types

t()

@type t() :: %TermUI.Renderer.Buffer{
  cols: pos_integer(),
  rows: pos_integer(),
  table: :ets.tid()
}

Functions

clear(buffer)

@spec clear(t()) :: :ok

Clears the entire buffer.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> Buffer.clear(buffer)
:ok

clear_col(buffer, col)

@spec clear_col(t(), pos_integer()) :: :ok

Clears a single column.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> Buffer.clear_col(buffer, 1)
:ok

clear_region(buffer, start_row, start_col, width, height)

@spec clear_region(t(), pos_integer(), pos_integer(), pos_integer(), pos_integer()) ::
  :ok

Clears a rectangular region, filling it with empty cells.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> Buffer.clear_region(buffer, 1, 1, 5, 5)
:ok

clear_row(buffer, row)

@spec clear_row(t(), pos_integer()) :: :ok

Clears a single row.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> Buffer.clear_row(buffer, 1)
:ok

destroy(buffer)

@spec destroy(t()) :: :ok

Destroys the buffer and frees ETS table.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> Buffer.destroy(buffer)
:ok

dimensions(buffer)

@spec dimensions(t()) :: {pos_integer(), pos_integer()}

Returns buffer dimensions as {rows, cols}.

each(buffer, fun)

@spec each(t(), ({pos_integer(), pos_integer(), TermUI.Renderer.Cell.t()} -> any())) ::
  :ok

Iterates over all cells in row-major order.

Calls the function with {row, col, cell} for each cell.

Examples

iex> {:ok, buffer} = Buffer.new(2, 2)
iex> Buffer.each(buffer, fn {row, col, cell} -> IO.inspect({row, col}) end)
:ok

get_cell(buffer, row, col)

@spec get_cell(t(), pos_integer(), pos_integer()) :: TermUI.Renderer.Cell.t()

Gets the cell at the given position.

Returns empty cell if position is out of bounds.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> cell = Buffer.get_cell(buffer, 1, 1)
iex> cell.char
" "

get_row(buffer, row)

@spec get_row(t(), pos_integer()) :: [TermUI.Renderer.Cell.t()]

Gets a row as a list of cells.

Uses a single ETS match operation for efficiency instead of individual cell lookups.

in_bounds?(buffer, row, col)

@spec in_bounds?(t(), pos_integer(), pos_integer()) :: boolean()

Checks if a position is within buffer bounds.

max_cols()

@spec max_cols() :: pos_integer()

Returns the maximum allowed columns.

max_rows()

@spec max_rows() :: pos_integer()

Returns the maximum allowed rows.

new(rows, cols)

@spec new(pos_integer(), pos_integer()) :: {:ok, t()} | {:error, term()}

Creates a new buffer with the given dimensions.

Initializes all cells to empty (space with default colors).

Maximum dimensions are 500 rows x 1000 cols to prevent resource exhaustion.

Examples

iex> {:ok, buffer} = Buffer.new(24, 80)
iex> buffer.rows
24
iex> buffer.cols
80

resize(buffer, new_rows, new_cols)

@spec resize(t(), pos_integer(), pos_integer()) :: {:ok, t()} | {:error, term()}

Resizes the buffer, preserving content where possible.

Content that fits in the new dimensions is preserved. New areas are filled with empty cells.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> {:ok, new_buffer} = Buffer.resize(buffer, 20, 20)
iex> new_buffer.rows
20

set_cell(buffer, row, col, cell)

@spec set_cell(t(), pos_integer(), pos_integer(), TermUI.Renderer.Cell.t()) ::
  :ok | {:error, :out_of_bounds}

Sets the cell at the given position.

Returns :ok if successful, {:error, :out_of_bounds} if position is invalid.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> Buffer.set_cell(buffer, 1, 1, Cell.new("X"))
:ok
iex> Buffer.get_cell(buffer, 1, 1).char
"X"

set_cells(buffer, cells)

@spec set_cells(t(), [{pos_integer(), pos_integer(), TermUI.Renderer.Cell.t()}]) ::
  :ok

Sets multiple cells at once for efficiency.

Cells is a list of {row, col, cell} tuples.

Examples

iex> {:ok, buffer} = Buffer.new(10, 10)
iex> cells = [{1, 1, Cell.new("A")}, {1, 2, Cell.new("B")}]
iex> Buffer.set_cells(buffer, cells)
:ok

to_list(buffer)

@spec to_list(t()) :: [{pos_integer(), pos_integer(), TermUI.Renderer.Cell.t()}]

Gets all cells as a list of {row, col, cell} tuples in row-major order.

write_string(buffer, row, col, string, opts \\ [])

@spec write_string(t(), pos_integer(), pos_integer(), String.t(), keyword()) ::
  non_neg_integer()

Writes a string starting at the given position.

Returns the number of columns written.

Examples

iex> {:ok, buffer} = Buffer.new(10, 80)
iex> Buffer.write_string(buffer, 1, 1, "Hello")
5