Skip to main content

Crate retroglyph_crossterm

Crate retroglyph_crossterm 

Source
Expand description

Output, Input, and Cursor implementations that render to a real terminal via crossterm, bundled together as Backend.

This crate owns the OS/TTY-specific parts: raw mode, the alternate screen, the kitty keyboard protocol, and crossterm::event polling. Cell-diffing and ANSI/SGR output are delegated to retroglyph_terminal::TerminalRenderer.

draw, flush, and clear propagate std::io::Error through this backend’s Output::Error type. resize, set_cursor_visible, and set_cursor_position are infallible (Output::resize and the Cursor methods have no Result return), so I/O failures in those methods (e.g. a closed terminal or disconnected pipe) are discarded silently rather than surfaced.

§Event polling and CPU cost

poll_event wraps a single crossterm::event::poll() syscall per call. A zero timeout (as used by Terminal::drain_events to drain everything buffered without blocking) performs one non-blocking crossterm::event::poll(Duration::ZERO) syscall (select/epoll under the hood), not a busy spin inside poll_event itself: once the OS reports no data waiting, it returns None immediately rather than looping. The actual CPU cost lives one level up, in the caller’s game loop: an uncapped loop that calls drain_events() every iteration with no frame limiter (no sleep, no vsync wait) will issue that non-blocking syscall as fast as the CPU allows, trading power/CPU usage for input latency.

§Focus and lifecycle events

With CrosstermOptions::focus_change enabled (the default), a terminal losing and regaining input focus is reported as Event::FocusLost/Event::FocusGained. This is the only lifecycle signal this backend currently has: unlike a windowed backend, there’s no separate “suspended”/“paused” notion here, and this crate maps every focus change the same way regardless of the underlying reason (window manager focus switch, terminal minimized, or, notably on Wayland compositors, a terminal surface being hidden or unmapped without an accompanying resize).

Terminal-side state (raw mode, the alternate screen, cursor position, last-written colors/attributes) is untouched by a focus change and is preserved across it: this backend does not react to Event::FocusLost/Event::FocusGained itself, so nothing is torn down or reinitialized. Rendering is not deferred automatically either: Output::draw and Output::flush keep writing escape sequences to stdout even while unfocused, since crossterm has no OS-level way to know whether that output is actually being presented while hidden. An app that wants to pause redraws while unfocused (e.g. to avoid wasted work on a backgrounded Wayland surface) should track Event::FocusLost/Event::FocusGained itself and skip its own draw calls in between.

If retroglyph-core later adds a dedicated Event::Suspended (or similar) distinct from plain focus loss, this crate would need coordinated changes with retroglyph-window (which shares the Event enum) before mapping anything to it; no such variant exists today, so there is nothing for this backend to emit.

§Tracing

With the optional tracing feature enabled, Output::draw, Output::flush, and Input::poll_event are each wrapped in a tracing span (debug level for draw/flush, trace for poll_event since it’s called every game-loop iteration by Terminal::drain_events), so a subscriber (e.g. tracing-subscriber’s fmt layer, or a flamegraph via tracing-flame) can show where render and input-polling time actually goes. The feature adds no code and no dependency when disabled.

§Features

This crate has no default features; every feature below is optional and off unless enabled.

§dev

⚪ Optional.

Forwards retroglyph-core’s dev feature, which forces development diagnostics on in a build that would otherwise compile them out (see retroglyph_core::dev).

§egc

⚪ Optional.

Forwards to retroglyph-terminal’s egc feature (which forwards to retroglyph-core’s), enabling grapheme-cluster-aware cell diffing.

This crate has no code of its own gated on the flag; it exposes it so callers don’t need to know which crate in the terminal family actually implements it.

§tracing

⚪ Optional.

Instruments draw, flush, and poll_event with tracing spans for profiling render/input time.

See where time is spent with any tracing subscriber (e.g. tracing-subscriber’s fmt layer, or a flamegraph via tracing-flame).

§Content writer

Crossterm is generic over its content writer: Crossterm<W>, defaulting to BufWriter<Stdout> to match this type’s historical, stdout-only behavior. Use Crossterm::with_writer or CrosstermOptions::build_with_writer to render into a file, a pipe, or an in-memory buffer instead, e.g. to capture and assert on the emitted ANSI/SGR bytes in a test without a real TTY. Only the rendered cell content goes through W; raw mode, the alternate screen, and the other terminal-protocol negotiation always target the real process stdout regardless of W: see CrosstermOptions::build_with_writer’s docs for the exact split.

Structs§

Crossterm
A terminal rendering backend powered by crossterm.
CrosstermOptions
Options controlling which optional terminal protocol features Crossterm::with_options enables.
SuspendGuard
RAII guard returned by Crossterm::suspend; see that method’s docs for the full contract.