screen API reference
Terminal user interfaces: an explicit screen, not a GUI framework. Two layers. The output-only layer is pure strings over ANSI control sequences - a cell Buffer you draw into (text / box / fill) and paint with render, plus diff for a flicker-free update loop (dashboards, progress, self-updating tables); it needs no host capability and runs on both binaries. The interactive layer decodes a raw byte stream into Key events (decodeKey, pure and testable) and drives an event loop over the term library's raw mode (begin / nextKey / end) for menus, forms, and key navigation; that layer needs term, so it works on the default jennifer (a friendly error on jennifer-tiny, which stubs term).
Coordinates are 0-based with the origin at the top-left (0, 0); x is the column, y the row. Drawing that runs past an edge is clipped, not an error.
Import with import "screen.j" as screen;. See the screen guide for prose and examples.
Functions
screen.begin()
Enter full-screen interactive mode: put the terminal in raw mode and switch to the alternate screen with the cursor hidden and the screen cleared. Pair with end, ideally via defer screen.end($state);. Requires the term library (default binary).
Returns {term.State} - the raw-mode handle to pass to end
screen.box(buf as Buffer, x as int, y as int, w as int, h as int)
A copy of buf with a single-line box border drawn at (x, y) of outer size w by h, using Unicode box-drawing glyphs. The interior is untouched.
Parameters
buf{Buffer}- the source bufferx{int}- the left column (0-based)y{int}- the top row (0-based)w{int}- the outer width in columns (>= 2)h{int}- the outer height in rows (>= 2)
Returns {Buffer} - the updated buffer
screen.clear()
The sequence that clears the whole screen and homes the cursor.
Returns {string} - the clear-screen escape sequence
screen.clearBuffer(buf as Buffer)
A copy of buf with every cell reset to a space.
Parameters
buf{Buffer}- the source buffer
Returns {Buffer} - the cleared buffer
screen.clearLine()
The sequence that clears the current line.
Returns {string} - the clear-line escape sequence
screen.decodeKey(seq as list of int)
Decode one raw key byte sequence into a Key. Pure and total: seq is the bytes of a single key press ([65] for A, [27, 91, 65] for Up, [27, 91, 51, 126] for Delete, [195, 182] for a two-byte UTF-8 character). A multi-byte UTF-8 sequence decodes to a "char" key holding the full rune. Unrecognized input decodes to "unknown"; an empty sequence to "eof". This is what nextKey calls after reading the bytes, exposed separately so key handling is testable without a terminal.
Parameters
seq{list of int}- the raw byte values of one key event
Returns {Key} - the decoded key
screen.diff(old as Buffer, new as Buffer)
The minimal escape string that turns the terminal showing old into new - only the changed cells are repositioned and rewritten, in row runs. When the two buffers differ in size it falls back to a full render(new). This is the flicker-free update path: keep the previous buffer, diff against the next.
Parameters
old{Buffer}- the buffer currently on screennew{Buffer}- the buffer to display
Returns {string} - the minimal-update escape string
screen.down(n as int)
The sequence that moves the cursor down n rows.
Parameters
n{int}- the number of rows
Returns {string} - the cursor-down escape sequence
screen.end(state as term.State)
Leave interactive mode: show the cursor, leave the alternate screen, and restore the terminal from the handle begin returned.
Parameters
state{term.State}- the handle returned bybegin
Returns {null} - nothing
screen.enterAlt()
The sequence that switches to the alternate screen buffer (so the app's output does not scroll the user's shell history).
Returns {string} - the enter-alternate-screen escape sequence
screen.exitAlt()
The sequence that leaves the alternate screen buffer, restoring the prior terminal contents.
Returns {string} - the leave-alternate-screen escape sequence
screen.fill(buf as Buffer, x as int, y as int, w as int, h as int, ch as string)
A copy of buf with the rectangle at (x, y) of size w by h filled with the glyph ch. Clipped to the buffer.
Parameters
buf{Buffer}- the source bufferx{int}- the left column (0-based)y{int}- the top row (0-based)w{int}- the width in columnsh{int}- the height in rowsch{string}- the fill glyph (one column)
Returns {Buffer} - the updated buffer
screen.get(buf as Buffer, x as int, y as int)
The contents of the cell at (x, y), or an empty string if out of range.
Parameters
buf{Buffer}- the bufferx{int}- the column (0-based)y{int}- the row (0-based)
Returns {string} - the cell contents
screen.hasKey(input as Input)
Whether a decoded key is waiting (non-blocking): true when pollKey would return a real key rather than the "none" sentinel.
Parameters
input{Input}- the live input handle (fromstartInput)
Returns {bool} - true if a key is buffered
screen.hideCursor()
The sequence that hides the text cursor.
Returns {string} - the hide-cursor escape sequence
screen.hline(buf as Buffer, x as int, y as int, n as int, ch as string)
A copy of buf with a horizontal line of n cells of ch from (x, y).
Parameters
buf{Buffer}- the source bufferx{int}- the starting column (0-based)y{int}- the row (0-based)n{int}- the length in columnsch{string}- the line glyph (one column)
Returns {Buffer} - the updated buffer
screen.home()
The sequence that homes the cursor to the top-left.
Returns {string} - the cursor-home escape sequence
screen.left(n as int)
The sequence that moves the cursor left n columns.
Parameters
n{int}- the number of columns
Returns {string} - the cursor-back escape sequence
screen.moveTo(x as int, y as int)
The sequence that moves the cursor to (x, y) (0-based; origin top-left).
Parameters
x{int}- the target column (0-based)y{int}- the target row (0-based)
Returns {string} - the cursor-position escape sequence
screen.newScreen(rows as int, cols as int)
A new blank Buffer of rows by cols cells, every cell a space.
Parameters
rows{int}- the number of rows (must be positive)cols{int}- the number of columns (must be positive)
Returns {Buffer} - the blank buffer
Throws
{Error}- whenrowsorcolsis not positive
screen.nextKey()
Read and decode the next key from the terminal (blocking). Reads raw bytes through the term library, assembling a full escape sequence before decoding, and returns the Key. At end of input the name is "eof". Requires raw mode (see begin) and the term library (default binary).
Caveat: a lone Escape is not just delayed, it is merged with the next key and both are consumed together, because term.readByte has no timeout to tell a bare Escape from the start of an escape sequence. After Escape, the key the user presses next is read into the sequence: ESC then q decodes as alt-q (the q is gone), and ESC then an arrow steers off the merged bytes. An ESC-merged control key is at least recovered - ESC then Ctrl-C yields ctrl-c, ESC then Escape yields escape - so a quit always works; but an application cannot rely on Escape, or on Alt-combinations, immediately after an Escape. Advertise a named key (q, Ctrl-C) rather than Escape to leave a loop. A timed read that delivers a lone Escape cleanly is planned (milestones M28.2).
Returns {Key} - the next key event
screen.pollKey(input as Input)
The next decoded key if one is waiting, else a "none" sentinel key (non-blocking) - the poll a free-running loop calls each tick.
Parameters
input{Input}- the live input handle (fromstartInput)
Returns {Key} - the next key, or Key{name: "none", char: ""} when none is ready
screen.render(buf as Buffer)
The escape string that paints the whole buf to the terminal (positions the cursor at the start of each row and writes its cells). Print it with io.printf; usually preceded once by clear.
Parameters
buf{Buffer}- the buffer to paint
Returns {string} - the full-repaint escape string
screen.right(n as int)
The sequence that moves the cursor right n columns.
Parameters
n{int}- the number of columns
Returns {string} - the cursor-forward escape sequence
screen.set(buf as Buffer, x as int, y as int, cell as string)
A copy of buf with the single cell at (x, y) set to cell (one column). Out-of-range coordinates are clipped (returns buf unchanged).
Parameters
buf{Buffer}- the source bufferx{int}- the column (0-based)y{int}- the row (0-based)cell{string}- the cell contents (one visible column)
Returns {Buffer} - the updated buffer
screen.showCursor()
The sequence that shows the text cursor.
Returns {string} - the show-cursor escape sequence
screen.size()
The terminal size as a term.Size ({rows, cols}), a convenience passthrough to term.size so an app stays in one namespace. Requires the term library.
Returns {term.Size} - the terminal dimensions
screen.startInput()
Start a background keyboard reader for a free-running loop (a game, a live dashboard, anything that must keep ticking without a keypress). It spawns a task that reads and decodes keys through nextKey into a buffered channel; poll it with hasKey / pollKey (non-blocking) or drain it with waitKey (blocking) while the loop renders. Requires raw mode (begin) and the term library (default binary).
The reader task is deliberately discarded: it blocks in term.readByte and cannot be interrupted mid-read (neither task.cancel nor closing the channel reaches a syscall read), so it runs until end of input or program exit, when the OS reaps it. Discarding it is what lets the program exit instead of hanging on the never-returning reader. One reader owns stdin; do not also call nextKey while it runs.
Returns {Input} - the live input handle
screen.text(buf as Buffer, x as int, y as int, s as string)
A copy of buf with s written left-to-right starting at (x, y), one rune per cell, clipped at the row's right edge (no wrapping).
Parameters
buf{Buffer}- the source bufferx{int}- the starting column (0-based)y{int}- the row (0-based)s{string}- the text to write
Returns {Buffer} - the updated buffer
screen.textColor(buf as Buffer, x as int, y as int, s as string, color as string)
A copy of buf with s written from (x, y) in the named foreground colour, one rune per cell, clipped at the row's right edge.
Parameters
buf{Buffer}- the source bufferx{int}- the starting column (0-based)y{int}- the row (0-based)s{string}- the text to writecolor{string}- the colour name (e.g."red","cyan")
Returns {Buffer} - the updated buffer
Throws
{Error}- whencoloris not a known colour
screen.up(n as int)
The sequence that moves the cursor up n rows.
Parameters
n{int}- the number of rows
Returns {string} - the cursor-up escape sequence
screen.vline(buf as Buffer, x as int, y as int, n as int, ch as string)
A copy of buf with a vertical line of n cells of ch from (x, y).
Parameters
buf{Buffer}- the source bufferx{int}- the column (0-based)y{int}- the starting row (0-based)n{int}- the length in rowsch{string}- the line glyph (one column)
Returns {Buffer} - the updated buffer
screen.waitKey(input as Input)
Block until the next decoded key and return it - the buffered equivalent of nextKey, for a loop that waits rather than spins.
Parameters
input{Input}- the live input handle (fromstartInput)
Returns {Key} - the next key event
Structs
screen.Buffer
A rectangular grid of character cells, drawn into then painted to the terminal. cells is row-major (y * cols + x); each cell is a one-column string, optionally wrapped in an SGR colour sequence. Value-semantic like any struct: the drawing functions return a fresh Buffer.
| Field | Type | Description |
|---|---|---|
rows | int | the number of rows (height) |
cols | int | the number of columns (width) |
cells | list of string | row-major cell contents, length rows * cols |
screen.Input
A live keyboard reader for a free-running event loop. A background task drains the terminal into a buffered channel of decoded Key events, so the loop can poll for input (hasKey / pollKey) without blocking the way nextKey does. Build one with startInput.
| Field | Type | Description |
|---|---|---|
keys | channel of Key | the buffered decoded-key stream |
screen.Key
A decoded key event from nextKey / decodeKey. name is a symbolic key name: a printable key is "char" (with the character in char); the rest are named - "up" / "down" / "left" / "right", "enter" / "tab" / "escape" / "backspace" / "delete" / "insert", "home" / "end" / "pageup" / "pagedown", "f1".."f12", "ctrl-a".."ctrl-z", "alt-<c>", "eof" at end of input, and "unknown".
| Field | Type | Description |
|---|---|---|
name | string | the symbolic key name |
char | string | the character for a "char" / "alt-" key, else empty |