style

js/tty/style.ts

fino:tty/style — terminal text appearance as data.

A Style is a fully-resolved cell appearance: colors and attributes, with every absent field meaning "terminal default". Styles are plain data, never escape sequences — SGR bytes exist only at the wire edge, produced by styleToSgr() as a minimal transition between two styles.

Styles are interned: internStyle() returns a canonical object per distinct appearance, so equality on interned styles is a pointer compare. The layout and paint pipeline in fino:tty/tui relies on this when compacting adjacent cells into styled runs.

SGR encoding and decoding implement the color and text-attribute subset of ECMA-48 used by modern terminals. Other control functions remain outside this style data model.

import { internStyle, styleToSgr, EMPTY_STYLE } from 'fino:tty/style';

const accent = internStyle({ fg: 'cyan', bold: true });
const open = styleToSgr(EMPTY_STYLE, accent); // '\x1b[1;36m'
const close = styleToSgr(accent, EMPTY_STYLE); // '\x1b[0m'

Types

type NamedColor = | 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'brightBlack' | 'brightRed' | 'brightGreen' | 'brightYellow' | 'brightBlue' | 'brightMagenta' | 'brightCyan' | 'brightWhite' | 'default'

The sixteen standard palette colors plus default, the terminal's own foreground or background.

type Color = | NamedColor | { readonly ansi256: number } | { readonly rgb: readonly [number, number, number] }

A terminal color: a named palette entry, a 256-color index, or a truecolor triple.

Interfaces

interface Style {

A fully-resolved cell appearance. Absent fields mean "terminal default"; an explicit false means the attribute is off (which matters when merging).

Readonly Properties

readonly fg?: Color
readonly bg?: Color
readonly bold?: boolean
readonly dim?: boolean
readonly italic?: boolean
readonly underline?: boolean
readonly inverse?: boolean
readonly strike?: boolean

Constants

const EMPTY_STYLE: Style

The default appearance: every field absent.

Functions

function internStyle(style: Style): Style

Return the canonical object for a style, so that two styles describing the same appearance are ===. Attributes set to false normalize to absent.

The intern table is bounded; a program generating unbounded distinct styles (say, per-pixel truecolor) resets it rather than growing without limit, which only costs the pointer-equality fast path, never correctness.

function styleEquals(a: Style, b: Style): boolean

Whether two styles describe the same appearance.

function colorEquals(a: Color | undefined, b: Color | undefined): boolean

Whether two colors are the same.

function mergeStyle(under: Style, over: Style): Style

Layer over on top of under: absent fields inherit, explicit false turns an attribute off, and a set color replaces. Returns an interned style.

function styleToSgr(from: Style, to: Style): string

The minimal SGR sequence that changes a cell painted in from to paint in to. Returns '' when the styles are equal. Transitioning to the default appearance emits a bare reset.

function supportsTruecolor(colorterm: string | undefined): boolean

Whether a COLORTERM value declares 24-bit RGB support.

Keeping detection pure lets callers pass an injected environment value and reuse the same policy without coupling rendering code to process state.

import { supportsTruecolor } from 'fino:tty/style';

supportsTruecolor('truecolor'); // true
supportsTruecolor(undefined); // false

function nearestAnsi256(r: number, g: number, b: number): number

Return the nearest xterm 256-color palette index for an RGB color.

Both the 6×6×6 color cube and grayscale ramp are considered. Centralizing this fallback avoids each color-producing component implementing its own approximation.

import { nearestAnsi256 } from 'fino:tty/style';

nearestAnsi256(255, 0, 0); // 196
nearestAnsi256(128, 128, 128); // 244

function applySgr(style: Style, params: readonly number[]): Style

Apply one SGR parameter list (the numbers of a CSI ... m sequence) to a style, returning the interned result. Unknown parameters are ignored.