TermUI.Renderer.Buffer (TermUI v0.2.0)
View SourceETS-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
@type t() :: %TermUI.Renderer.Buffer{ cols: pos_integer(), rows: pos_integer(), table: :ets.tid() }
Functions
@spec clear(t()) :: :ok
Clears the entire buffer.
Examples
iex> {:ok, buffer} = Buffer.new(10, 10)
iex> Buffer.clear(buffer)
:ok
@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
@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
@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
@spec destroy(t()) :: :ok
Destroys the buffer and frees ETS table.
Examples
iex> {:ok, buffer} = Buffer.new(10, 10)
iex> Buffer.destroy(buffer)
:ok
@spec dimensions(t()) :: {pos_integer(), pos_integer()}
Returns buffer dimensions as {rows, cols}.
@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
@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
" "
@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.
@spec in_bounds?(t(), pos_integer(), pos_integer()) :: boolean()
Checks if a position is within buffer bounds.
@spec max_cols() :: pos_integer()
Returns the maximum allowed columns.
@spec max_rows() :: pos_integer()
Returns the maximum allowed rows.
@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
@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
@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"
@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
@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.
@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