Buffers
One cell is a single slot. A whole terminal screen is a grid of them, rows by columns. A buffer is that grid held in memory: a rectangle of cells you can fill, read, and reshape without anything reaching the terminal yet.
A grid of cells
A Buffer is width × height cells, addressed by (x, y) with the origin in
the top-left corner. x grows to the right, y grows downward. A brand-new
buffer is full of blank cells, ready to paint
over.
| row / col | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| row 1 (y=0) | H | i | ||||
| row 2 (y=1) | ||||||
| row 3 (y=2) |
A six-by-three cell buffer with Hi painted at the top-left; every other slot
is a blank cell.
This is exactly how a terminal emulator thinks of its own screen: not a bag of pixels, but a grid of character cells it repaints as text arrives. A buffer is your private copy of that same idea.
Off-screen by design
A buffer is just memory. Writing into it changes nothing on the terminal. You
compose a full frame in the grid, then hand it to something that actually draws:
Screen renders a desired grid to bytes, and
Program owns that screen for interactive apps.
That separation makes the useful tricks possible: diffing one frame against the
last, snapshotting a frame in a test, or serializing it to bytes for a
transcript.
Wide cells span columns
A wide grapheme occupies several columns in its row. The first column holds the primary cell, and each additional column holds a continuation. The buffer writes the primary and its continuations together. The Width page explains how uncurses measures graphemes and why their widths matter.
Working with a buffer
Create one, paint cells into it by position, and ask about its shape:
use uncurses::buffer::{Buffer, SurfaceMut};
use uncurses::cell::Cell;
use uncurses::layout::Position;
fn main() {
let mut frame = Buffer::new(20, 5); // 20 columns, 5 rows of blank cells
frame.set_cell(Position::new(0, 0), &Cell::new("H", 1));
frame.set_cell(Position::new(1, 0), &Cell::new("i", 1));
assert_eq!(frame.width(), 20);
assert_eq!(frame.height(), 5);
}Buffer is the plain grid, but it is not the only one. It implements the shared
surface traits, so the same fill, clear, and
copy operations work on every grid type. TextBuffer builds on it to paint
whole strings while respecting width.