Skip to content

Architecture

Iain Smith edited this page Sep 14, 2026 · 6 revisions

Architecture

veetee is a Cargo workspace. The emulator core has no GUI dependencies, so it is tested headless, fuzzed and driven by scripts.

Crate Role
vt-parser Allocation-free DEC STD 070 / ECMA-48 parser (Williams state machine): 7-bit and 8-bit controls, UTF-8, VT52; CSI, DCS, OSC, APC, PM, SOS
vt-core The terminal: page memory, cells and line sizes, modes, margins, character sets, soft fonts, UDKs, status line, macros, reports, DEC keyboard encoding, selection text
vt-keyboard The TOML keymap (keymap.rs, built-in default.toml): GDK key symbols → LK401 keys and local functions; PC key positions → LK411 stations
vt-fonts Original bitmap fonts in a text format, their parser, font sets per terminal family and the stroke-preserving resampler
vt-render OpenGL renderer: page layout on the model's raster, instanced cell quads, glyph and soft-font atlases, smooth-scroll clipping, and the post-processing pass for glow, afterglow and curvature (postfx.rs)
vt-transport Transport trait; local PTY (ConPTY on Windows), serial (termios or Win32), Telnet, SSH (OpenSSH client)
veetee GTK4/libadwaita application: a window holds one or two sessions (workspace.rs), each drawn by a terminal view; Set-Up overlay and saved settings (setup_store.rs), sound synthesis (sound.rs, cpal), keymap editor, appearance preferences
vt-headless Script runner, recording replay and parser tracer used by the conformance suites
xtask cargo xtask vttest, esctest, openvms and dist
packaging/windows Bundles the Windows zip with the GTK runtime from MSYS2

Data flow

flowchart LR
  Host[(Host)] -- bytes --> T[Transport]
  T --> IO[I/O thread]
  IO -- advance --> Core[vt-core Terminal]
  Core -- replies --> T
  Core -- events: bell, size --> IO
  IO -- redraw notice --> UI[GTK view]
  UI -- lock, build frame --> R[vt-render]
  UI -- keys, paste --> Core
Loading

Each session has an I/O thread that reads from the transport and feeds the terminal, which sits behind a mutex. Replies (device reports) are written straight back to the host. The GTK thread receives a redraw notice, locks the terminal briefly to build the instance buffer, and draws it with OpenGL. Keys go through vt-keyboard into Terminal::key, which encodes them for the current modes, or into a host-programmed definition when the VT520 key programming (keyprog.rs) has one for that key position.

Printable text is written a run at a time when that is exactly what writing it a character at a time would do (ASCII or DEC Special Graphics in GL, no insert mode, national mode or single shift, and no character reaching the margin); scrolled lines reuse memory. The terminal model handles about 100 MB/s of plain text; cargo run --release -p vt-core --example terminal_throughput measures it.

The view keeps assistive technologies informed through view/area.rs, a GtkGLArea subclass implementing GtkAccessibleText: its text is the screen's lines, its caret the cursor, and at most ten times a second it reports what changed as removed and inserted text.

With --record, the I/O thread also writes each read, reply and checkpoint to a .vtrec recording (recording.rs), which vt-headless replay plays back.

Terminal model

  • The parser calls Perform methods; a pause hook lets the terminal change parser settings (such as 8-bit controls or VT52 mode) in the middle of a buffer.
  • Cells store the displayed character, renditions and the code received, which the DEC rectangle checksum needs.
  • Page memory holds up to six pages; the cursor's page is the active grid, and the user window selects which lines are on screen.
  • Character sets translate codes through G0–G3/GL/GR, national replacement sets, DEC Supplemental, DEC Technical, ISO Latin-1 and soft fonts (Private Use Area characters).
  • Colour (color.rs) holds the VT525 colour map and assignments and resolves a cell's renditions to colours; the colour mode in effect when a character is written is kept with it.
  • VT500 Set-Up (terminal/vt520.rs) keeps host-selectable settings and the VT500 private modes for reporting.
  • Set-Up (setup.rs, terminal/setup.rs) holds every Set-Up feature, reads and applies them, and draws the VT420 Set-Up screens as terminal output for a scratch terminal; saved features in Config::setup are the power-up settings.
  • Smooth scroll: in DECSCLM mode Terminal::advance_paced stops after each line that scrolls; the session's I/O thread records the scroll for the renderer to animate and waits the line's time before processing more host output.
  • Key programming (keyprog.rs) stores DECPFK/DECPAK definitions by LK411 key station in the VT520's 768 bytes of key memory.
  • Configuration (Config) holds the model and Set-Up values; Extensions holds opt-in xterm behaviour.

Fonts and rendering

A FontSet holds every face a terminal family shows: for the VT420 family, hand-drawn 10×16 and 6×16 fonts for 24-line screens, the 10×10 font and a derived 6×10 face for 36 lines, and hand-drawn 10×8 and 6×8 ASCII for 48 lines. Display Controls symbols are generated for every cell size from a 3×5 dot alphabet (controls.rs). Faces without a hand-drawn glyph take one resampled from a larger face: each axis merges neighbouring dot columns or rows, choosing per glyph the grouping that keeps separate strokes separate, while line drawing uses a fixed grouping so it still joins across cells. The renderer uploads all faces into one atlas, picks the face for the current column mode and screen height, and sizes the page from the family's raster (Family::line_aspect).

Licensing

Code is MIT OR Apache-2.0; cargo deny allows only permissive dependencies. Fonts are SIL OFL. Test tools under other licences (vttest, esctest2) are downloaded at test time, never vendored. The Windows zip bundles unmodified MSYS2 builds of GTK, libadwaita and their dependencies (mostly LGPL) as separate DLLs, with their licences in its licenses folder. The VT500 character set tables are generated from xterm's transcriptions under its MIT-style licence; see THIRD-PARTY.md.

Clone this wiki locally