pub struct Terminal<B: Backend> { /* private fields */ }Expand description
A double-buffered terminal generic over a Backend.
Owns the current and previous frame grids and the backend’s lifecycle (resize, present,
events). Drawing itself goes entirely through Surface: see draw for the
common case (draw a frame, then present it) and surface for manual control
over presenting.
§Out-of-bounds drawing
Surface clips any write that falls outside its own area rather than panicking; see
Surface’s own “out-of-bounds drawing” documentation.
§Examples
use retroglyph_core::backend::Headless;
use retroglyph_core::{Color, Terminal};
let mut term = Terminal::new(Headless::new(20, 5));
term.draw(|surface| {
surface.put((2, 1), '@', retroglyph_core::Style::new().fg(Color::GREEN));
})
.unwrap();Implementations§
Source§impl<B: Backend> Terminal<B>
impl<B: Backend> Terminal<B>
Sourcepub fn new(backend: B) -> Self
pub fn new(backend: B) -> Self
Create a terminal with the given backend. Grid dimensions are queried from the backend.
Sourcepub fn draw(
&mut self,
f: impl FnOnce(&mut Surface<'_>),
) -> Result<(), <B as Output>::Error>
pub fn draw( &mut self, f: impl FnOnce(&mut Surface<'_>), ) -> Result<(), <B as Output>::Error>
Draws one frame: f gets a Surface scoped to the whole terminal on layer 0, then the
frame is presented (see present) once f returns.
This is the common entry point for drawing: a caller that draws every frame regardless of
whether anything changed calls this once per frame. A caller that only wants to redraw
when its own state changed should gate the call to draw itself (e.g. if state.changed() { term.draw(|s| render(s, &state))?; }) rather than rely on draw/
present to no-op. Unlike some earlier revisions of this API, presenting
is unconditional here.
§Errors
Propagates errors from present.
Sourcepub const fn area(&self) -> Rect
pub const fn area(&self) -> Rect
Returns the full drawing surface as a Rect at the origin.
Equivalent to Rect::new(0, 0, width, height). Handy for passing the
whole terminal to layout helpers or region-based drawing.
Sourcepub fn resize(&mut self, width: u16, height: u16)
pub fn resize(&mut self, width: u16, height: u16)
Resize both grids to width × height cells.
Content within the overlapping region is preserved in the current grid.
The previous grid is cleared so the next present redraws
the entire new surface rather than diffing stale data.
Sourcepub const fn grid_mut(&mut self) -> &mut Grid
pub const fn grid_mut(&mut self) -> &mut Grid
Returns a mutable reference to the current grid, with no clipping or layer scoping.
Escape hatch for whole-grid operations that don’t fit Surface’s clipped,
single-layer model (e.g. Grid::blit). Most drawing should go through
draw/surface instead.
Sourcepub const fn backend_mut(&mut self) -> &mut B
pub const fn backend_mut(&mut self) -> &mut B
Returns a mutable reference to the backend.
Sourcepub const fn present_count(&self) -> u64
pub const fn present_count(&self) -> u64
Number of times present has been called so far.
Wraps on overflow; intended for detecting whether present was called at all between two
points in time (compare a saved count against the current one), not as a precise total.
Embedding drivers (e.g. retroglyph-window’s windowed drivers) use this to decide whether
application code already presented during a frame, so they can skip a redundant
driver-side present.
Sourcepub fn present(&mut self) -> Result<(), <B as Output>::Error>
pub fn present(&mut self) -> Result<(), <B as Output>::Error>
Present the current frame: computes the diff against the previous frame, sends changed
cells to the backend, flushes, then swaps buffers. Always presents unconditionally, even
if nothing was drawn since the last call; most callers want draw instead
of calling this directly.
When the backend requires a full frame (see
crate::Output::needs_full_frame), all cells from every allocated layer are
sent rather than just the diff, so pixel-based backends can clear and
redraw to avoid orphaned pixels from sub-cell offsets.
After a present, the new current buffer is cleared so the next frame starts empty.
Callers should not draw into a frame and skip presenting it: the next draw
call starts from an empty grid regardless.
§Immediate mode
This is an immediate-mode API (the same trade ratatui makes): the current buffer is wiped after every present, so each frame must redraw its entire scene from scratch. Cells are not retained between frames. The diff only bounds what is sent to the backend (terminal or pixel I/O); it does not bound the CPU cost of your redraw.
§Errors
Propagates errors from the backend’s draw_layers or
flush operations. Either failure returns before the
current/previous buffers are swapped, so the cells from the failed frame stay marked
dirty and are resent the next time present succeeds; the caller doesn’t need to
redraw anything to recover, just call draw/present again.
Sourcepub fn poll(&mut self, timeout: Duration) -> Option<Event>
pub fn poll(&mut self, timeout: Duration) -> Option<Event>
Polls for an input event, waiting up to timeout.
If an event was previously buffered by has_input, it is
returned immediately. Otherwise, the backend is polled for a new event.
Event::Resize events are automatically applied: both grids are resized
before the event is returned to the caller, so the game loop can immediately
redraw at the new size.
Sourcepub fn read_blocking(&mut self) -> Event
pub fn read_blocking(&mut self) -> Event
Reads an input event, blocking indefinitely until one is available.
Only call this on backends that genuinely block (e.g. crossterm, window). Backends
that never block (e.g. Headless, which returns
immediately regardless of timeout) will panic here once their event queue is
empty; use poll or drain_events instead if
that is a possibility.
§Panics
Panics if the backend’s poll_event returns
None even with an unbounded timeout.
Sourcepub fn drain_events(&mut self) -> impl Iterator<Item = Event> + use<'_, B>
pub fn drain_events(&mut self) -> impl Iterator<Item = Event> + use<'_, B>
Drains all available events without blocking.
Returns an iterator that yields every pending event — the internal queued event
followed by all events buffered in the backend. The iterator polls the backend
with zero timeout repeatedly until None is returned.
This is needed for frame-based game loops (e.g. software backend + WASM, where
frames are gated by requestAnimationFrame). Multiple keypresses can arrive
between frames; draining all of them ensures accumulated input doesn’t replay in
slow motion.
Crossterm and headless backends can also use this, but the single-event poll
pattern works for them because their loops aren’t frame-capped.
Sourcepub fn has_input(&mut self) -> bool
pub fn has_input(&mut self) -> bool
Checks if a pending input event is available without blocking.
If an event is already buffered, returns true. Otherwise, polls the backend
with zero timeout. If the backend returns an event, it is stored in the internal
buffer and true is returned; otherwise, returns false.