Screen

The terminal screen is a grid of cells backed by scrollback, with a primary and an alternate screen, scrolling margins, and resize-time text reflow.

The screen is the visible grid that the terminal renders. Programs write characters and control sequences into it, and the terminal maintains everything those programs assume: cell contents, cell attributes, the cursor, the scrolling region, and the scrollback that sits above the visible area.

The Grid

A screen is a fixed grid of rows x cols cells. Each cell holds a single grapheme (one or more code points that render as one user-visible character) along with attributes such as foreground and background color, bold, italic, underline, blink, reverse, and protection state. See colors for how cell colors are specified.

Wide characters such as most CJK glyphs occupy two adjacent cells. The left cell holds the grapheme; the right cell is a spacer that the cursor and most operations treat as a single unit with its partner.

The cursor is always located in exactly one cell of the active screen. The cursor is covered in detail under cursor.

Primary and Alternate Screens

Every terminal session has two screens:

  • The primary screen is the default. Lines that scroll off the top are pushed into the scrollback buffer and remain retrievable by scrolling up.
  • The alternate screen is a separate full-screen buffer used by full-screen TUIs such as editors, pagers, and TUI dashboards. It has no scrollback. Switching back to the primary screen restores whatever was on it before, untouched.

Programs switch screens with DEC private modes 47, 1047, or 1049. The three variants differ in whether the alternate screen is cleared on entry, whether it is cleared on exit, and whether the cursor is saved across the switch. Mode 1049 is the modern default and is what most TUIs use: it saves the primary cursor, clears the alternate screen, and restores the primary cursor on exit.

Note

The primary and alternate screens have independent cursor state, saved-cursor state, charset state, and scrolling region. Switching screens does not leak any of that across.

Scrollback and the Viewport

The grid you see on screen is the viewport. The lines that have scrolled off the top of the primary screen live in the scrollback buffer. Scrolling the viewport up just moves the visible window backward through the scrollback; it does not change any cell data.

The amount of scrollback Wintty keeps is bounded by the scrollback-limit config option, which is specified in bytes. When the limit is reached the oldest scrollback rows are dropped.

Tip

The alternate screen never produces scrollback. If you want to keep output from a TUI around, copy it out before the program exits or have it write to a file.

Scrolling Region (Margins)

By default the entire viewport scrolls when content is added past the bottom row. The scrolling region narrows that.

  • DECSTBM sets the top and bottom margins. Once set, line feeds at the bottom margin scroll only the region bounded by the margins, leaving rows above and below untouched.
  • DECSLRM sets the left and right margins. When left-and-right margin mode is enabled, horizontal scrolling operations and certain insert and delete operations also respect these column boundaries.

The scrolling region is per-screen, so the primary and alternate screens have separate margins. Resetting the terminal or switching screens resets the active region.

Note

Left and right margins must be explicitly enabled by the DEC private mode that gates DECSLRM. Many programs that only need vertical margins use DECSTBM alone and never touch the horizontal margins.

Origin Mode

Cursor Position and other absolute positioning sequences address rows and columns from the screen origin by default, with (1, 1) being the top-left cell.

DEC private mode 6 ("origin mode") changes that. When origin mode is on, absolute positioning is interpreted relative to the current scrolling region: (1, 1) becomes the top-left of the region defined by the top, bottom, left, and right margins, and the cursor cannot be positioned outside the region.

Warning

Programs that set margins and then issue absolute cursor moves need to be aware of origin mode. Whether CUP 1;1 lands at the screen corner or at the top-left of the margin region depends on whether origin mode is set, not on the sequence itself.

Resize Behavior

When the window or pane changes size, the terminal resizes both screens to the new dimensions. The interesting case is a width change on the primary screen.

  • Rows that were soft-wrapped at the old width are unwrapped and rewrapped at the new width, so a paragraph that previously occupied three rows at a narrow width may collapse to two rows when widened and vice versa. This is text reflow.
  • Hard line breaks (rows ended by a line feed) are never merged across a resize. Only continuation rows that were wrapped by the terminal itself reflow.
  • The alternate screen does not reflow. It is treated as opaque program-managed content, and the program is expected to redraw on resize.
  • Wide characters that would no longer fit at the new width are handled by the page logic so that no half of a wide cell is ever left orphaned.

The cursor and any tracked selection are preserved across reflow when possible. The implementation lives in src/terminal/PageList.zig and src/terminal/Terminal.zig if you want the full detail.

  • DECSTBM sets top and bottom margins.
  • DECSLRM sets left and right margins.
  • CUP positions the cursor (origin mode aware).
  • SU and SD scroll the region.
  • ED and EL erase within the screen.