BEAM-side display list: a styled text run intermediate representation.
Sits between editor state and protocol encoding. The renderer produces
a Frame struct containing all visual content, then to_commands/1
converts it to protocol command binaries for the TUI frontend. Other
frontends (GUI, headless) can consume the frame directly.
Coordinate system
All coordinates within a WindowFrame are window-relative: row 0,
col 0 is the top-left of the window's content rect. The rect field
carries the absolute screen position; to_commands/1 adds the rect
offset when generating protocol commands.
Other frame sections (file_tree, agent_panel, minibuffer, overlays) use absolute screen coordinates since they're not scoped to a window.
Types
draw()— a pending draw:{row, col, text, style}. This is the return type of all renderer modules after the display list refactor.text_run()— column + text + style (no row; row is the map key).display_line()— a list of text runs for one screen row.render_layer()— rows mapped to their display lines.
Summary
Types
RGB color as a 24-bit integer (e.g. 0xFF6C6B).
All text runs on one screen row.
A pending draw command: {row, col, text, Face.t()}.
Screen rows mapped to their display lines.
Style: a resolved Face struct.
A single styled text span at a specific column.
Functions
Compares two render layers line-by-line and returns the set of changed rows.
Creates a draw tuple with a Face style.
Converts a list of draw tuples to protocol command binaries.
Groups a list of draws by row into a render layer.
Converts draw tuples to grayscale (luminance-weighted).
Flattens a render layer back into a list of draw tuples.
Offsets draw tuples by the given row and column amounts.
Converts a frame into a list of protocol command binaries.
Types
@type color() :: non_neg_integer()
RGB color as a 24-bit integer (e.g. 0xFF6C6B).
@type display_line() :: [text_run()]
All text runs on one screen row.
@type draw() :: {non_neg_integer(), non_neg_integer(), String.t(), Minga.Core.Face.t()}
A pending draw command: {row, col, text, Face.t()}.
This is the intermediate representation that renderer modules produce.
@type render_layer() :: %{required(non_neg_integer()) => display_line()}
Screen rows mapped to their display lines.
@type style() :: Minga.Core.Face.t()
Style: a resolved Face struct.
@type text_run() :: {col :: non_neg_integer(), text :: String.t(), style :: Minga.Core.Face.t()}
A single styled text span at a specific column.
Functions
@spec changed_rows(render_layer(), render_layer()) :: MapSet.t(non_neg_integer())
Compares two render layers line-by-line and returns the set of changed rows.
This enables incremental rendering: only rows that differ between frames need to be re-sent to the frontend.
@spec draw(non_neg_integer(), non_neg_integer(), String.t(), Minga.Core.Face.t()) :: draw()
Creates a draw tuple with a Face style.
Examples
iex> DisplayList.draw(0, 5, "hello")
{0, 5, "hello", %Face{name: "_"}}
iex> DisplayList.draw(0, 5, "hello", Face.new(fg: 0xFF0000, bold: true))
{0, 5, "hello", %Face{name: "_", fg: 0xFF0000, bold: true}}
Converts a list of draw tuples to protocol command binaries.
Uses encode_draw_smart/4 which automatically selects the compact
draw_text opcode for simple styles (fg/bg/bold/italic/underline/reverse)
or the extended draw_styled_text opcode when the style includes
strikethrough, underline_style, underline_color, or blend.
@spec draws_to_layer([draw()]) :: render_layer()
Groups a list of draws by row into a render layer.
Each draw's row becomes the map key; the draw is converted to a text_run (col, text, style) within that row's display_line.
Converts draw tuples to grayscale (luminance-weighted).
@spec layer_to_draws(render_layer()) :: [draw()]
Flattens a render layer back into a list of draw tuples.
@spec offset_draws([draw()], non_neg_integer(), non_neg_integer()) :: [draw()]
Offsets draw tuples by the given row and column amounts.
@spec to_commands( MingaEditor.DisplayList.Frame.t(), keyword() ) :: [binary()]
Converts a frame into a list of protocol command binaries.
Produces the same output that the old renderer sent to the port: clear, regions, content draws, cursor, batch_end.
Options:
batch_end: false— omit the trailingbatch_endcommand. Used by the GUI emit path which appends Metal-critical chrome commands before sendingbatch_endto ensure atomic frame delivery.