etui/buffer

Types

pub opaque type Buffer

A diff operation: move cursor to position, write a run of cells.

pub type BufferOp {
  Patch(position: geometry.Position, cells: List(Cell))
}

Constructors

One cell in the terminal grid: a grapheme + its style + optional hyperlink.

The style is resolved (see style.resolve): whatever it turns off has already been taken off, so two cells that look the same compare equal and the diff leaves them alone.

pub type Cell {
  Cell(content: CellContent, style: style.Style, link: String)
}

Constructors

  • Cell(content: CellContent, style: style.Style, link: String)

    Arguments

    link

    OSC 8 hyperlink URI. Empty string = no link. Emitted on render.

pub type CellArray

Content variant for a terminal cell.

pub type CellContent {
  Content(symbol: String, width: Int)
  Continuation
}

Constructors

  • Content(symbol: String, width: Int)

    A normal or wide grapheme. width = 1 or 2.

  • Continuation

    Marker for the second cell of a wide grapheme. Never drawn directly.

A run of writes.

The JavaScript store has to copy the cell array to keep an old buffer intact, so writing a cell at a time makes filling a buffer quadratic in its size: a 200x50 fill cost about 35 ms, more than a whole 60 fps frame. A draft copies once and writes many times. Erlang’s array is a persistent trie already, so there a draft is the array itself.

A draft must not escape the loop that made it. Every use below takes one, writes, and commits within a single function.

pub type Draft

Values

pub fn area(buf: Buffer) -> geometry.Rect

The rect this buffer covers.

pub fn blit(
  dst: Buffer,
  src: Buffer,
  src_rect: geometry.Rect,
  dst_pos: geometry.Position,
) -> Buffer

Copy src_rect out of src into dst, placing its top-left at dst_pos. Clipped against both buffers; anything outside either is skipped.

Use to composite an off-screen buffer (a scroll canvas, a cached panel) into the frame without going cell by cell from the caller.

pub fn buffer_new(area: geometry.Rect) -> Buffer

New buffer with given area. All cells start as empty_cell().

pub fn buffer_new_filled(
  area: geometry.Rect,
  row_text: String,
  s: style.Style,
) -> Buffer

Create a buffer with every row pre-filled with row_text. Uses bulk array construction: one pass instead of buffer_new followed by a set_string for every row.

pub fn cell_bg(cell: Cell) -> style.Color

Background color of a cell.

pub fn cell_fg(cell: Cell) -> style.Color

Foreground color of a cell.

pub fn cell_link(cell: Cell) -> String

Accessor: OSC 8 hyperlink URI of a cell (empty = no link).

pub fn cell_modifier(cell: Cell) -> style.Modifier

Text modifier of a cell.

pub fn cell_style(cell: Cell) -> style.Style

Whole style of a cell.

pub fn cell_symbol(cell: Cell) -> String

Symbol string of a cell. Returns “ “ for Continuation cells.

pub fn cell_underline_color(cell: Cell) -> style.Color

Underline color of a cell.

pub fn clear(buffer: Buffer, rect: geometry.Rect) -> Buffer

Clear all cells in a rect (reset to empty_cell). The rect is clipped to the buffer first, so the inner loop needs no per-cell bounds check and the Buffer record is rebuilt once, not per cell.

pub fn continuation_cell(s: style.Style) -> Cell

Continuation cell (second column of a wide grapheme).

pub fn diff(prev: Buffer, next: Buffer) -> List(BufferOp)

Compute minimal diff between two buffers as a list of patches.

pub fn diff_to_ansi(prev: Buffer, curr: Buffer) -> String

Diff prev against curr and return the minimal ANSI to bring the terminal from prev’s state to curr’s state. On the first frame (or after resize) pass an empty buffer as prev.

pub fn empty_cell() -> Cell

Empty cell (space, default style, no link).

pub fn get_cell(buffer: Buffer, pos: geometry.Position) -> Cell

Get cell at position. Returns empty_cell() for out-of-bounds.

pub fn height(buf: Buffer) -> Int

Height in rows.

pub fn is_continuation(cell: Cell) -> Bool

True if this cell is the second column of a wide grapheme (never rendered directly).

pub fn patches_to_ansi(ops: List(BufferOp)) -> String

Convert a list of BufferOp patches to an ANSI string. Each patch moves the cursor once, then writes a run of cells. Style is tracked across the entire patch list, cursor moves do not reset terminal style, so we avoid redundant escape sequences. Cheaper than to_ansi when only a small fraction of cells changed.

pub fn set_cell(
  buffer: Buffer,
  pos: geometry.Position,
  cell: Cell,
) -> Buffer

Set cell at position. Out-of-bounds writes are ignored.

The cell’s style is resolved on the way in, like every other write path, so a hand-built Cell cannot smuggle an unspent sub_modifier into the grid and make an identical-looking cell compare unequal.

pub fn set_string(
  buffer: Buffer,
  pos: geometry.Position,
  str: String,
  s: style.Style,
) -> Buffer

Set cells from a string starting at pos. No hyperlink. Wide graphemes (width=2) take one Cell + one Continuation cell.

pub fn set_string_linked(
  buffer: Buffer,
  pos: geometry.Position,
  str: String,
  s: style.Style,
  link: String,
) -> Buffer

Set cells from a string with an OSC 8 hyperlink URI. Pass "" for no link (same as set_string).

pub fn set_style(
  buffer: Buffer,
  rect: geometry.Rect,
  s: style.Style,
) -> Buffer

Restyle every cell in rect, keeping its content. Use to tint a region (selection highlight, disabled panel) after the content has been drawn.

pub fn to_ansi(buf: Buffer) -> String

Full-buffer render to an ANSI string. Emits a MoveCursor for every row, then each cell with style transitions only when the style actually changes between adjacent cells. Use for the first frame or after a terminal resize.

pub fn width(buf: Buffer) -> Int

Width in cells.

✨ Search Document