class Termisu::Testing::Screen

Overview

A minimal terminal emulator: feed it the byte stream a Termisu program writes and it maintains a 2D grid of Termisu::Cell plus a cursor, so tests can assert on what's rendered (get_by_text, cursor, #to_s snapshot).

Scope: it decodes the subset Termisu emits (absolute cursor positioning, erase, SGR colors/attrs, printable text with wide-char placement) and recognizes-and-skips the rest (DEC private modes, mouse, kitty, OSC). It is NOT a full VT525 — it does not implement scroll regions, tab stops, or insert mode, which Termisu never emits. The grapheme/width logic reuses Termisu::UnicodeWidth so columns match the program's own cursor tracking.

#feed is incremental and keeps parser state across calls, so PTY reads that split an escape sequence mid-stream are handled correctly.

Defined in:

termisu/testing/screen.cr

Constructors

Instance Method Summary

Constructor Detail

def self.new(cols : Int32, rows : Int32) #

[View source]

Instance Method Detail

def cell(x : Int32, y : Int32) : Cell #

Cell at (x, y). Raises IndexError if out of bounds.


[View source]
def cols : Int32 #

[View source]
def cursor_visible? : Bool #

[View source]
def cursor_x : Int32 #

[View source]
def cursor_y : Int32 #

[View source]
def feed(bytes : Bytes) : Nil #

Feed a chunk of output bytes. Safe to call repeatedly with partial data.


[View source]
def feed(str : String) : Nil #

[View source]
def includes?(pattern : String | Regex) : Bool #

True if pattern appears anywhere on screen (row-wise match).


[View source]
def locate(pattern : String | Regex) : Tuple(Int32, Int32) | Nil #

First {x, y} where pattern starts, or nil. x is the cell column of the match start. Crystal string offsets are character-based, but a row may hold wide (2-column) glyphs, so we map the matched character index back to its column via row_columns rather than returning the offset directly.


[View source]
def row_text(y : Int32) : String #

The visible text of row y (continuation cells contribute nothing).


[View source]
def rows : Int32 #

[View source]
def to_s(io : IO) : Nil #

Whole screen as text, one row per line (trailing blanks stripped per line).


[View source]
def to_styled_s(mask : Array(Regex) = [] of Regex) : String #

A deterministic snapshot capturing the glyph grid AND per-cell style (fg/bg/attr), run-length compressed — richer than glyph-only snapshots, so color/attribute regressions are caught. mask blanks volatile regions (matched against each row's text) at the cell level, so animated screens snapshot deterministically.


[View source]