ETee (e_tee v0.1.0)

Copy Markdown View Source

A terminal emulator: bytes in, cell grid out.

Feed the byte stream a program writes to a terminal, and read back what that program drew — grid, cursor, styles, modes, scrollback.

iex> ETee.new(20, 3) |> ETee.feed("\e[1;31mred\e[0m and plain") |> ETee.line(0)
"red and plain"

Nothing here opens a terminal or performs a syscall, so the bytes may come from a pty, a socket, a file, or a recorded session.

Feeding

feed/2 accepts bytes however they were chopped. Partial state — a half-read parameter list, an unterminated OSC payload, a UTF-8 character split mid-codepoint — is carried in the returned terminal, so a sequence split across calls behaves as one whole call.

Damage

damage/1 returns the rows whose content changed since the last clear_damage/1. Feeding does not paint anything; a consumer chooses when to read damage and clear it.

Summary

Functions

True while the alternate screen is in use.

Forget which rows are dirty, after painting them.

True once the program has erased the whole display.

The cursor position as {row, col}, zero-based.

True unless the program has hidden the cursor.

Rows whose content changed since the last clear_damage/1.

Feed bytes to the terminal.

True when the program has been painting a screen rather than printing output.

The visible grid.

The text of one row, trailing blanks removed.

Whether a mode the program can set is currently on.

A blank terminal of the given size.

Resize the terminal, clamping the cursor into the new bounds.

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

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

The whole screen as text, one string per row, trailing blanks removed.

Rows that have scrolled off the top of the primary screen.

The rows that have scrolled off the top, oldest first, as {text, style} runs.

How many rows that scrolled off the top are still held.

The style subsequent text will be written with.

The window title last set by the program.

How many rows of the screen the program has written.

Types

t()

@type t() :: ETee.Emulator.t()

Functions

alt_screen?(terminal)

@spec alt_screen?(t()) :: boolean()

True while the alternate screen is in use.

clear_damage(terminal)

@spec clear_damage(t()) :: t()

Forget which rows are dirty, after painting them.

cleared?(terminal)

@spec cleared?(t()) :: boolean()

True once the program has erased the whole display.

cursor(terminal)

@spec cursor(t()) :: {non_neg_integer(), non_neg_integer()}

The cursor position as {row, col}, zero-based.

cursor_visible?(terminal)

@spec cursor_visible?(t()) :: boolean()

True unless the program has hidden the cursor.

damage(terminal)

@spec damage(t()) :: MapSet.t(non_neg_integer())

Rows whose content changed since the last clear_damage/1.

feed(terminal, bytes)

@spec feed(t(), binary()) :: t()

Feed bytes to the terminal.

full_screen?(terminal)

@spec full_screen?(t()) :: boolean()

True when the program has been painting a screen rather than printing output.

True while the alternate screen is in use, and true once the whole display has been erased provided nothing has scrolled off the top.

grid(terminal)

@spec grid(t()) :: ETee.Grid.t()

The visible grid.

line(terminal, row)

@spec line(t(), non_neg_integer()) :: String.t()

The text of one row, trailing blanks removed.

mode?(terminal, mode)

@spec mode?(t(), ETee.Emulator.mode()) :: boolean()

Whether a mode the program can set is currently on.

new(cols, rows, opts \\ [])

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

A blank terminal of the given size.

Options:

  • :scrollback — rows of history to retain, default 1000

resize(terminal, cols, rows)

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

Resize the terminal, clamping the cursor into the new bounds.

row_cells(terminal, row)

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

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

row_runs(terminal, row)

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

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

Each run is a span of adjacent columns sharing one style. Runs cover the full width of the row, blanks included.

screen_text(terminal)

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

The whole screen as text, one string per row, trailing blanks removed.

scrollback(terminal)

@spec scrollback(t()) :: ETee.Scrollback.t()

Rows that have scrolled off the top of the primary screen.

scrollback_runs(terminal)

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

The rows that have scrolled off the top, oldest first, as {text, style} runs.

Scrollback is held outside the grid, so erasing the display leaves it intact. Only ESC[3J discards it. Rows are retained up to the :scrollback limit given to new/3.

scrolled(terminal)

@spec scrolled(t()) :: non_neg_integer()

How many rows that scrolled off the top are still held.

style(terminal)

@spec style(t()) :: ETee.Style.t()

The style subsequent text will be written with.

title(terminal)

@spec title(t()) :: String.t()

The window title last set by the program.

used_rows(terminal)

@spec used_rows(t()) :: pos_integer()

How many rows of the screen the program has written.