API Terminal
picocalc.terminal provides a full-featured terminal emulator widget. Each terminal has its own cell grid, scrollback buffer, cursor, and colour state. Multiple terminals can be created but only one should render to the display at a time.
Creating a terminal
Section titled “Creating a terminal”local term = picocalc.terminal.new([cols [, rows [, scrollback]]])cols(number, default 53): grid width in characters, 1-53rows(number, default 26): grid height in characters, 1-26
Out-of-range sizes raise an error.
scrollback(number, default 1000): number of lines kept in scrollback history
Returns a terminal object. Raises an error if allocation fails (PSRAM OOM).
-- Full-screen terminal with default sizelocal term = picocalc.terminal.new()
-- Smaller terminal, 500-line scrollbacklocal term = picocalc.terminal.new(40, 20, 500)Writing and clearing
Section titled “Writing and clearing”term:write(str)
Section titled “term:write(str)”Write a string to the terminal at the current cursor position. Supports ANSI escape sequences (cursor movement, colour codes, erase sequences, etc.). The cursor advances automatically; lines wrap and the display scrolls when the bottom row is reached.
term:write("Hello, world!\n")term:write("\27[31mRed text\27[0m\n") -- ANSI colourterm:clear()
Section titled “term:clear()”Clear all cells and reset the cursor to (0, 0).
Cursor
Section titled “Cursor”term:setCursor(x, y)
Section titled “term:setCursor(x, y)”Move the cursor to column x, row y (0-based).
term:getCursor() → x, y
Section titled “term:getCursor() → x, y”Return the current cursor column and row (0-based).
term:setCursorVisible(visible)
Section titled “term:setCursorVisible(visible)”Show or hide the cursor.
term:setCursorBlink(blink)
Section titled “term:setCursorBlink(blink)”Enable or disable cursor blinking.
Colours
Section titled “Colours”term:setColors(fg, bg)
Section titled “term:setColors(fg, bg)”Set the default foreground and background colours (RGB565).
term:getColors() → fg, bg
Section titled “term:getColors() → fg, bg”Return the current default foreground and background colours.
Scrolling
Section titled “Scrolling”term:scroll(lines)
Section titled “term:scroll(lines)”Scroll the viewport up by lines rows (positive = up, negative = down).
term:getScrollbackCount() → n
Section titled “term:getScrollbackCount() → n”Return the number of lines currently in the scrollback buffer.
term:getScrollbackLine(n) → str
Section titled “term:getScrollbackLine(n) → str”Return scrollback line n (1-based) as a plain string. Raises an error if n is out of range.
term:getScrollbackOffset() → offset
Section titled “term:getScrollbackOffset() → offset”Return the current scrollback view offset (0 = showing live output).
term:setScrollbackOffset(offset)
Section titled “term:setScrollbackOffset(offset)”Jump the viewport to a specific scrollback position.
Rendering
Section titled “Rendering”Call one of these once per frame after writing content.
term:render()
Section titled “term:render()”Redraw every cell to the framebuffer. Use when the whole screen may be stale (e.g. first frame, font change).
term:renderDirty()
Section titled “term:renderDirty()”Redraw only rows marked dirty since the last render. Faster than render() for incremental updates.
term:markAllDirty()
Section titled “term:markAllDirty()”Mark every row as dirty so the next renderDirty() redraws everything.
term:isFullDirty() → bool
Section titled “term:isFullDirty() → bool”Returns true if all rows are marked dirty.
term:getDirtyRange() → first, last
Section titled “term:getDirtyRange() → first, last”Return the first and last dirty row indices (inclusive). Useful for partial redraws.
term:setFont(name)
Section titled “term:setFont(name)”Switch the terminal font. Valid values:
| Name | Description |
|---|---|
"scientifica" | Default bitmap font |
"scientifica_bold" | Bold variant |
term:getFont() → name
Section titled “term:getFont() → name”Return the current font name string.
Line numbers
Section titled “Line numbers”Draw a gutter on the left side with line numbers.
term:setLineNumbers(enabled)
Section titled “term:setLineNumbers(enabled)”Enable or disable the line number gutter (default: off).
term:setLineNumberStart(n)
Section titled “term:setLineNumberStart(n)”Set the first line number displayed (default: 1).
term:setLineNumberCols(cols)
Section titled “term:setLineNumberCols(cols)”Set the gutter width in columns (default: 5).
term:setLineNumberColors(fg, bg)
Section titled “term:setLineNumberColors(fg, bg)”Set gutter foreground and background colours (RGB565).
term:getContentCols() → n
Section titled “term:getContentCols() → n”Return the number of columns available for content (terminal cols − gutter width). Use this when calculating text layout so content does not overlap the gutter.
term:setLineNumbers(true)term:setLineNumberCols(4)term:setLineNumberColors(0x7BEF, 0x2945) -- grey on darklocal usable = term:getContentCols() -- e.g. 49 when gutter is 4Scrollbar
Section titled “Scrollbar”Draw a vertical scrollbar on the right side.
term:setScrollbar(enabled)
Section titled “term:setScrollbar(enabled)”Enable or disable the scrollbar (default: off).
term:setScrollbarColors(bg, thumb)
Section titled “term:setScrollbarColors(bg, thumb)”Set the scrollbar track background and thumb colours (RGB565).
term:setScrollbarWidth(width)
Section titled “term:setScrollbarWidth(width)”Set the scrollbar width in pixels (default: 4).
term:setScrollInfo(totalLines, scrollPosition)
Section titled “term:setScrollInfo(totalLines, scrollPosition)”Tell the scrollbar how many total logical lines exist and where the current viewport starts. Call this each frame when the document length or scroll position changes.
term:setScrollbar(true)term:setScrollbarWidth(6)term:setScrollInfo(#lines, scroll_offset)Grid dimensions
Section titled “Grid dimensions”term:getCols() → n
Section titled “term:getCols() → n”Return the total number of columns in the terminal grid.
term:getRows() → n
Section titled “term:getRows() → n”Return the total number of rows in the terminal grid.
Render bounds
Section titled “Render bounds”term:setRenderBounds(y_start, y_end)
Section titled “term:setRenderBounds(y_start, y_end)”Restrict rendering to rows between y_start and y_end (inclusive). Useful for embedding a terminal in a portion of the screen alongside other UI elements.
y_start(number): First row to render (0-based pixel row)y_end(number): Last row to render
term:setRenderBounds(16, 300) -- leave room for a headerCell access
Section titled “Cell access”Direct cell manipulation for syntax highlighting and custom rendering.
term:setCell(x, y, ch)
Section titled “term:setCell(x, y, ch)”Set the character at column x, row y (0-based). Out-of-bounds coordinates are silently ignored.
x(number): Columny(number): Rowch(string): Single character to place in the cell
term:getCell(x, y) → ch
Section titled “term:getCell(x, y) → ch”Return the character at column x, row y as a single-character string. Returns " " for out-of-bounds coordinates or empty cells.
term:setCellColors(x, y, fg, bg)
Section titled “term:setCellColors(x, y, fg, bg)”Set the foreground and background colours (RGB565) of a single cell. Marks the row dirty.
x(number): Columny(number): Rowfg(number): Foreground colour (RGB565)bg(number): Background colour (RGB565)
term:setRowColors(y, fgTable, bgTable [, startX [, count]])
Section titled “term:setRowColors(y, fgTable, bgTable [, startX [, count]])”Batch-set foreground and background colours for a range of cells in row y. Both fgTable and bgTable are arrays of RGB565 values. Marks the row dirty.
y(number): RowfgTable(table): Array of foreground coloursbgTable(table): Array of background coloursstartX(number, optional): Starting column (default 0)count(number, optional): Number of cells to set (default: all columns)
-- Highlight columns 0-9 of row 3local fg = {}; local bg = {}for i = 1, 10 do fg[i] = 0xFFE0; bg[i] = 0x0000 end -- yellow on blackterm:setRowColors(3, fg, bg, 0, 10)Word wrap
Section titled “Word wrap”term:setWordWrap(enabled)
Section titled “term:setWordWrap(enabled)”Enable or disable word wrapping (default: off).
term:setWordWrapColumn(col)
Section titled “term:setWordWrapColumn(col)”Set the column at which wrapping occurs.
term:setWrapIndicator(enabled)
Section titled “term:setWrapIndicator(enabled)”Show a visual indicator (e.g. ↩) at wrapped line ends.
term:getWordWrap() → bool
Section titled “term:getWordWrap() → bool”Return the current word-wrap state.
term:getVisualRowCount() → n
Section titled “term:getVisualRowCount() → n”Return the number of visual (wrapped) rows the current content occupies.
Input helpers
Section titled “Input helpers”These methods block the calling Lua coroutine while keeping the system menu, HTTP callbacks, screenshots, and the watchdog all responsive: they run the full OS service pass (menu, callbacks, dev commands, exit request).
term:waitForAnyKey()
Section titled “term:waitForAnyKey()”Block until any button is pressed, then return nil.
term:waitForKey(keyName) → mask
Section titled “term:waitForKey(keyName) → mask”Block until the named key is pressed. Returns the button mask integer.
Valid key names: "enter", "left", "right", "up", "down", "esc", "f1"–"f5", "tab", "backspace".
term:readKey() → mask | nil
Section titled “term:readKey() → mask | nil”Non-blocking. Returns the button mask if any key is currently pressed, or nil.
term:readChar() → str | nil
Section titled “term:readChar() → str | nil”Non-blocking. Returns a single-character string if a printable key was typed, or nil.
term:waitForChar() → str
Section titled “term:waitForChar() → str”Block until a printable character is typed. Returns the character as a string.
Complete example
Section titled “Complete example”local D = picocalc.display
local term = picocalc.terminal.new()term:setLineNumbers(true)term:setScrollbar(true)term:setScrollbarWidth(6)
local lines = {}
local function redraw() term:renderDirty() D.flush()end
-- Write some contentfor i = 1, 50 do local line = string.format("Line %d: the quick brown fox\n", i) table.insert(lines, line) term:write(line)end
term:setScrollInfo(#lines, 0)redraw()
-- Scroll with arrow keyswhile true do local key = term:waitForKey("up") or term:readKey() if key then if key & picocalc.input.BTN_UP ~= 0 then term:scroll(-1) elseif key & picocalc.input.BTN_DOWN ~= 0 then term:scroll(1) elseif key & picocalc.input.BTN_ESC ~= 0 then return end redraw() endend