Ascii.Render.ANSI (Ascii v0.3.0)

Copy Markdown View Source

A frame for a terminal: text with ANSI colour escapes.

Coloured frames take each cell's palette colour, as 24-bit colour (:truecolor, the default), the nearest of xterm's 256 (:ansi256), or none at all (:mono). Escapes are emitted once a run of one colour, and spaces never start a run, so a frame costs little more than its text. A piece with a ground gets it as the background, unless ground: false. Each line ends by resetting the colours, so nothing bleeds past the picture.

Frames without colours (text pieces, or color: false) are plain text in every mode, in the terminal's own colours. A nil in a palette (cells in no coloured part of a piece, see Ascii.Parts) is the terminal's own foreground too, and a CSS variable (see Ascii.Ink) is its fallback colour, or the terminal's own without one.

To animate in place, move the cursor home before each frame:

IO.write([ANSI.hide_cursor(), ANSI.clear()])
IO.write([ANSI.home(), ANSI.render(frame)])
# ...
IO.write([ANSI.reset(), ANSI.show_cursor()])

Ascii.Player and mix ascii.play do this for you.

Summary

Functions

What changed from prev to frame, as iodata that moves the cursor to each run of cells that changed and writes it (see Ascii.Frame.changes/3); nothing at all when the picture did not change. With prev nil, the whole frame, each row placed.

Clears the screen.

Hides the cursor.

Moves the cursor to the top left.

Moves the cursor to row, column, counting from 1.

The frame as iodata.

Resets colours.

Shows the cursor.

The xterm-256 colour nearest an RGB colour: a step of the 6×6×6 cube or of the grey ramp.

Types

mode()

@type mode() :: :truecolor | :ansi256 | :mono

Functions

changes(prev, frame, opts \\ [])

@spec changes(
  prev :: Ascii.Frame.t() | nil,
  frame :: Ascii.Frame.t(),
  opts :: [mode: mode(), ground: boolean(), at: {pos_integer(), pos_integer()}]
) :: iodata()

What changed from prev to frame, as iodata that moves the cursor to each run of cells that changed and writes it (see Ascii.Frame.changes/3); nothing at all when the picture did not change. With prev nil, the whole frame, each row placed.

A terminal that already shows prev needs only this, which for most pieces is a few cells in a hundred: over SSH or a serial console, far less to send than render/2 every frame.

Options

  • :mode, :ground - as for render/2.
  • :at - {row, column} of the screen where the frame's top left cell is, counting from 1 (default {1, 1}).

clear()

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

Clears the screen.

hide_cursor()

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

Hides the cursor.

home()

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

Moves the cursor to the top left.

move(row, column)

@spec move(row :: pos_integer(), column :: pos_integer()) :: String.t()

Moves the cursor to row, column, counting from 1.

render(frame, opts \\ [])

@spec render(frame :: Ascii.Frame.t(), opts :: [mode: mode(), ground: boolean()]) ::
  iodata()

The frame as iodata.

Options

  • :mode - :truecolor (default), :ansi256 or :mono.
  • :ground - paint the piece's ground behind it (default true).

reset()

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

Resets colours.

show_cursor()

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

Shows the cursor.

xterm256(arg)

@spec xterm256({byte(), byte(), byte()}) :: 16..255

The xterm-256 colour nearest an RGB colour: a step of the 6×6×6 cube or of the grey ramp.