Alaja.Cell (Alaja v1.0.0)

Copy Markdown View Source

Atomic visual unit for the terminal buffer.

A cell holds a single character, optional foreground/background RGB colours, and a list of text effects (bold, italic, underline, etc.).

All operations return new cells — no mutation. Colours can be RGB tuples, Pote theme atoms (resolved at ANSI-build time), or nil.

Summary

Functions

Applies an additional effect to a cell, returning a new cell.

Creates an empty cell (space, no color, no effects).

Compares two cells for visual equality.

Merges two cells, with the overlay cell taking precedence over the base.

Creates a new cell with the given character and optional colors.

Converts a cell to its ANSI escape sequence representation.

Returns the ANSI prefix for a cell without the character or reset.

Returns the visual display width of the cell's character.

Types

color()

@type color() :: {0..255, 0..255, 0..255} | atom() | nil

effect()

@type effect() ::
  :bold
  | :italic
  | :underline
  | :strikethrough
  | :reverse
  | :blink
  | :hidden
  | :dim

effects()

@type effects() :: [effect()]

t()

@type t() :: %Alaja.Cell{
  bg: color(),
  char: String.t(),
  effects: effects(),
  fg: color()
}

Functions

apply_effect(cell, effect)

@spec apply_effect(t(), effect()) :: t()

Applies an additional effect to a cell, returning a new cell.

Examples

iex> cell = Cell.new("A", {255, 0, 0})
iex> Cell.apply_effect(cell, :bold)
%Cell{char: "A", fg: {255, 0, 0}, bg: nil, effects: [:bold]}

empty()

@spec empty() :: t()

Creates an empty cell (space, no color, no effects).

Examples

iex> Cell.empty()
%Cell{char: " ", fg: nil, bg: nil, effects: []}

equal?(a, b)

@spec equal?(t(), t()) :: boolean()

Compares two cells for visual equality.

Two cells are equal if they would produce identical terminal output. Effects are compared as sets (order-independent).

merge(base, overlay)

@spec merge(t(), t()) :: t()

Merges two cells, with the overlay cell taking precedence over the base.

  • If overlay has a non-space char, it replaces base.char
  • If overlay has a non-nil color, it replaces base color
  • Effects are merged (overlay first, unique)

Examples

iex> base = Cell.new("A", {255, 0, 0})
iex> overlay = Cell.new("B", {0, 255, 0})
iex> Cell.merge(base, overlay)
%Cell{char: "B", fg: {0, 255, 0}, bg: nil, effects: []}

new(char \\ " ", fg_or_opts \\ nil, bg \\ nil, opts \\ [])

@spec new(String.t(), color() | keyword(), color(), keyword()) :: t()

Creates a new cell with the given character and optional colors.

Parameters

  • char - The character to display (default: " ")
  • opts - Optional keyword list for foreground, background and effects.
  • fg - Foreground color as {r, g, b} tuple or atom (default: nil)
  • bg - Background color as {r, g, b} tuple or atom (default: nil)

Examples

iex> Cell.new("A", {255, 0, 0}, {0, 255, 0})
%Cell{char: "A", fg: {255, 0, 0}, bg: {0, 255, 0}, effects: []}

iex> Cell.new("★", {255, 215, 0}, nil, effects: [:bold])
%Cell{char: "★", fg: {255, 215, 0}, bg: nil, effects: [:bold]}

to_ansi(cell)

@spec to_ansi(t()) :: iodata()

Converts a cell to its ANSI escape sequence representation.

Produces true-color (24-bit) ANSI sequences for RGB colors. Always resets formatting after the character.

Examples

iex> Cell.to_ansi(Cell.new("X", {255, 0, 0}))
"X"

iex> Cell.to_ansi(Cell.empty())
" "

to_ansi_prefix(cell)

@spec to_ansi_prefix(t()) :: iodata()

Returns the ANSI prefix for a cell without the character or reset.

Enables run-length encoding in the renderer: consecutive cells with identical styling share a single prefix and reset.

visual_width(cell)

@spec visual_width(t()) :: 0 | 1 | 2

Returns the visual display width of the cell's character.

ASCII characters have width 1. Wide characters (CJK, emoji) have width 2. Control characters have width 0.

Examples

iex> Cell.visual_width(Cell.new("A"))
1

iex> Cell.visual_width(Cell.new("中"))
2