ETee.Grid (e_tee v0.1.0)

Copy Markdown View Source

The character grid: a fixed cols by rows rectangle of cells.

A row is a list of segments, each covering a span of columns:

{:text, span, binary, style}   span single-width graphemes sharing one style
{:wide, grapheme, style}       one double-width grapheme, spanning two columns

The spans of a row always sum to exactly cols. There is no unwritten column: a blank is a space, and a blank row is a single segment.

Writing splits the row at the target columns, drops the columns being replaced, and splices the new segments in. Splitting inside a :wide segment yields a blank on each side, so overwriting either half of a double-width grapheme blanks the other. Adjacent segments sharing a style are coalesced when the incoming segment spans eight columns or fewer.

Rows are held in a map keyed by an absolute index. origin is the absolute index of the top visible row: scrolling the whole screen changes origin and drops the rows that left, while a scroll region narrower than the screen shuffles its own rows.

Row and column indices are zero-based screen positions; origin appears in no argument or return value. Scroll regions are given as top inclusive and bottom exclusive.

Summary

Functions

Remove cells at col, pulling the rest of the row left.

Remove rows at row, pulling the rest of the region up.

Blank cells in place, without shifting the rest of the row.

Blank part or all of the screen, relative to a cursor position.

The cell at a position, or a blank cell when the position is off-grid.

Open blank cells at col, pushing the rest of the row right.

Open blank rows at row, pushing the rest of the region down.

A stored line as {text, style} runs, for rows held outside the grid.

A blank grid of the given size.

Write a single cell.

Write a run of graphemes starting at col, given as {grapheme, width} pairs.

Write a run of single-width printable ASCII starting at col.

Resize the grid.

The cells of a row as a dense list, cols long.

A row as a list of {text, style} runs, left to right.

The text of a row, with spacers omitted and blanks rendered as spaces.

Scroll a region down, discarding rows pushed off the bottom of it.

Scroll a region up, returning the grid and the rows that left the top of it.

Every row's text, top to bottom.

Types

erase_mode()

@type erase_mode() :: :to_end | :to_start | :all

line()

@type line() :: [segment()]

segment()

@type segment() ::
  {:text, pos_integer(), binary(), ETee.Style.t()}
  | {:wide, String.t(), ETee.Style.t()}

t()

@type t() :: %ETee.Grid{
  blank_row: line(),
  cols: non_neg_integer(),
  lines: %{required(integer()) => line()},
  origin: integer(),
  rows: non_neg_integer()
}

Functions

delete_chars(grid, row, col, count, style \\ %Style{})

@spec delete_chars(t(), integer(), integer(), pos_integer(), ETee.Style.t()) :: t()

Remove cells at col, pulling the rest of the row left.

delete_lines(grid, row, top, bottom, count, style \\ %Style{})

@spec delete_lines(
  t(),
  integer(),
  integer(),
  integer(),
  pos_integer(),
  ETee.Style.t()
) :: t()

Remove rows at row, pulling the rest of the region up.

erase_chars(grid, row, col, count, style \\ %Style{})

@spec erase_chars(t(), integer(), integer(), pos_integer(), ETee.Style.t()) :: t()

Blank cells in place, without shifting the rest of the row.

erase_display(grid, row, col, mode, style \\ %Style{})

@spec erase_display(t(), integer(), integer(), erase_mode(), ETee.Style.t()) :: t()

Blank part or all of the screen, relative to a cursor position.

erase_line(grid, row, col, mode, style \\ %Style{})

@spec erase_line(t(), integer(), integer(), erase_mode(), ETee.Style.t()) :: t()

Blank part or all of a row.

get(grid, row, col)

@spec get(t(), integer(), integer()) :: ETee.Cell.t()

The cell at a position, or a blank cell when the position is off-grid.

insert_chars(grid, row, col, count, style \\ %Style{})

@spec insert_chars(t(), integer(), integer(), pos_integer(), ETee.Style.t()) :: t()

Open blank cells at col, pushing the rest of the row right.

insert_lines(grid, row, top, bottom, count, style \\ %Style{})

@spec insert_lines(
  t(),
  integer(),
  integer(),
  integer(),
  pos_integer(),
  ETee.Style.t()
) :: t()

Open blank rows at row, pushing the rest of the region down.

line_runs(line)

@spec line_runs(line()) :: [{String.t(), ETee.Style.t()}]

A stored line as {text, style} runs, for rows held outside the grid.

new(cols, rows)

@spec new(pos_integer(), pos_integer()) :: t()

A blank grid of the given size.

put(grid, row, col, cell)

@spec put(t(), integer(), integer(), ETee.Cell.t()) :: t()

Write a single cell.

A double-width grapheme spans two columns; one written at the last column becomes a blank instead.

put_graphemes(grid, row, col, pairs, style)

@spec put_graphemes(t(), integer(), integer(), [{String.t(), 1..2}], ETee.Style.t()) ::
  t()

Write a run of graphemes starting at col, given as {grapheme, width} pairs.

Runs of single-width graphemes coalesce into one segment; each double-width grapheme becomes its own. The caller must ensure col plus the summed widths fits within cols.

put_run(grid, row, col, text, style)

@spec put_run(t(), integer(), integer(), binary(), ETee.Style.t()) :: t()

Write a run of single-width printable ASCII starting at col.

The binary is stored as given, without copying. The caller must ensure the bytes are printable ASCII and that col plus the run length fits within cols.

resize(grid, cols, rows)

@spec resize(t(), pos_integer(), pos_integer()) :: t()

Resize the grid.

Growing pads with blank rows at the bottom and blank columns at the right. Shrinking drops rows from the top and columns from the right.

row_cells(grid, row)

@spec row_cells(t(), integer()) :: [ETee.Cell.t()]

The cells of a row as a dense list, cols long.

row_runs(grid, row)

@spec row_runs(t(), integer()) :: [{String.t(), ETee.Style.t()}]

A row as a list of {text, style} runs, left to right.

Runs cover the full width of the row, blanks included. A double-width grapheme is returned as a run of its own whose text is that single grapheme.

row_text(grid, row)

@spec row_text(t(), integer()) :: String.t()

The text of a row, with spacers omitted and blanks rendered as spaces.

scroll_down(grid, top, bottom, count, style \\ %Style{})

@spec scroll_down(t(), integer(), integer(), pos_integer(), ETee.Style.t()) :: t()

Scroll a region down, discarding rows pushed off the bottom of it.

scroll_up(grid, top, bottom, count, style \\ %Style{})

@spec scroll_up(t(), integer(), integer(), pos_integer(), ETee.Style.t()) ::
  {t(), [line()]}

Scroll a region up, returning the grid and the rows that left the top of it.

Evicted rows are returned oldest first. Scrolling by more than the region height returns at most one region's worth.

to_text(grid)

@spec to_text(t()) :: [String.t()]

Every row's text, top to bottom.