pub struct Crossterm<W: Write = BufWriter<Stdout>> { /* private fields */ }Expand description
A terminal rendering backend powered by crossterm.
Generic over the content writer W: the sink that receives rendered cell output
([Output::draw]/[Output::flush], plus the runtime cursor/clear escapes). Defaults to
BufWriter<Stdout>, matching this type’s historical behavior; use
Crossterm::with_writer/CrosstermOptions::build_with_writer to render to a file, a
pipe, or an in-memory buffer instead (e.g. for tests that want to inspect the emitted ANSI
bytes without a real TTY). See CrosstermOptions::build_with_writer for exactly which
operations go through W versus the real terminal.
§Concurrency: only one live instance per process
Raw mode, the alternate screen, and the other terminal-protocol state this backend negotiates
are process-wide OS resources (there’s exactly one controlling terminal, one raw-mode flag,
one alternate-screen buffer), not something a Crossterm instance owns exclusively the way a
File owns a file descriptor. Because of that, at most one Crossterm (of any W) may be
live at a time in a process: constructing a second one while a first is still alive (new,
with_options, with_writer, and every CrosstermOptions::build/
CrosstermOptions::build_with_writer call) returns an std::io::Error with
std::io::ErrorKind::ResourceBusy instead of proceeding: this is a documented error, not
undefined behavior, and nothing is torn down or corrupted by the attempt. Sequential
construct-drop-construct is fully supported: once the live instance is dropped, a new one can
be constructed immediately.
Implementations§
Source§impl Crossterm
impl Crossterm
Sourcepub fn new() -> Result<Self, Error>
pub fn new() -> Result<Self, Error>
Creates a new Crossterm backend rendering to standard output.
Enables raw mode, enters the alternate screen, hides the cursor, and
enables mouse capture, focus-change reporting, bracketed paste, and
the kitty keyboard protocol (all by default; see CrosstermOptions
to disable any of them). Registers a process-wide panic hook (once,
across all instances) that restores the terminal before the default
panic handler runs, so a panic mid-render doesn’t leave the user’s
shell in raw mode or the alternate screen.
This is a thin wrapper over Crossterm::with_options with
CrosstermOptions::default().
§Errors
Same as CrosstermOptions::build.
§Examples
use retroglyph_core::terminal::Terminal;
use retroglyph_crossterm::Crossterm;
// Requires a real controlling terminal (raw mode, the alternate screen, and cursor
// hiding all target the actual process stdout), so this example is `no_run`.
let mut term = Terminal::new(Crossterm::new()?);
term.draw(|_surface| {})?;Sourcepub fn builder() -> CrosstermOptions
pub fn builder() -> CrosstermOptions
Starts building a Crossterm backend with explicit control over which optional
terminal protocol features are enabled.
Equivalent to CrosstermOptions::new(); call CrosstermOptions::build (or
CrosstermOptions::build_with_writer) once the desired features are chosen. This is
the preferred entry point over CrosstermOptions::new() for readability at the call
site:
use retroglyph_crossterm::Crossterm;
let options = Crossterm::builder()
.mouse_capture(false)
.kitty_protocol(false)
.alt_screen(true)
.raw_mode(true);
// let backend = options.build()?; // requires a real terminalSourcepub fn with_options(options: CrosstermOptions) -> Result<Self, Error>
pub fn with_options(options: CrosstermOptions) -> Result<Self, Error>
Creates a new Crossterm backend rendering to standard output, with
explicit control over which optional protocol features are enabled.
Hides the cursor unconditionally. Raw mode, entering the alternate screen, mouse
capture, focus-change reporting, bracketed paste, and the kitty keyboard protocol are
all enabled by default but can be disabled individually via options; see
CrosstermOptions. Registers a process-wide panic hook (once, across all instances)
that restores the terminal before the default panic handler runs, so a panic
mid-render doesn’t leave the user’s shell in raw mode or the alternate screen.
This is a thin wrapper over CrosstermOptions::build; prefer
Crossterm::builder().<options>().build() at new call sites.
§Errors
Same as CrosstermOptions::build.
Sourcepub fn run<A>(app: A) -> Result<(), Error>where
A: App<Self>,
pub fn run<A>(app: A) -> Result<(), Error>where
A: App<Self>,
Creates a crossterm terminal and drives app with the blocking loop until
it returns Flow::Exit.
This is a thin wrapper over the generic
run_blocking; the terminal is restored on the
way out via Drop, so raw mode and the alternate screen are left intact
until the loop actually returns. Event-driven by default (see
RunOptions::default): an app that returns
Flow::Idle blocks on input rather than spinning. Use
Crossterm::run_with to pass different RunOptions,
for example RunOptions::animated for a
continuously-rendering app.
§Errors
Returns an std::io::Error if the terminal fails to initialize, or if a frame present
fails while app is running.
Sourcepub fn run_with<A>(app: A, options: RunOptions) -> Result<(), Error>where
A: App<Self>,
pub fn run_with<A>(app: A, options: RunOptions) -> Result<(), Error>where
A: App<Self>,
Creates a crossterm terminal and drives app with the blocking loop, per options, until
it returns Flow::Exit.
This is a thin wrapper over the generic
run_blocking_with; see Crossterm::run for the
zero-config equivalent, and RunOptions for the available
pacing and idle-blocking controls. Reaching this method is the intended way to opt into
RunOptions::animated or a custom
RunOptions::idle_wake without hand-building a
Terminal and calling run_blocking_with directly.
§Errors
Returns an std::io::Error if the terminal fails to initialize, or if a frame present
fails while app is running.
Source§impl<W: Write> Crossterm<W>
impl<W: Write> Crossterm<W>
Sourcepub fn with_writer(writer: W) -> Result<Self, Error>
pub fn with_writer(writer: W) -> Result<Self, Error>
Creates a new Crossterm backend rendering to writer instead of standard output.
Thin wrapper over CrosstermOptions::build_with_writer with
CrosstermOptions::default(); see that method for the exact contract of which
operations go through writer versus the real terminal.
§Errors
Same as CrosstermOptions::build.
§Examples
Rendering into an in-memory buffer, to capture and assert on the emitted ANSI/SGR bytes
without a real TTY. Terminal-protocol setup (raw mode, the alternate screen, hiding the
cursor) still targets the real process stdout regardless of writer (see this method’s
docs above), so this example is no_run: it requires an actual controlling terminal to
construct successfully, even though writer itself is just a Vec<u8>.
use retroglyph_crossterm::Crossterm;
let mut buffer: Vec<u8> = Vec::new();
let term = Crossterm::with_writer(&mut buffer)?;
drop(term);
assert!(buffer.is_empty());Sourcepub const fn plain_mode(&self) -> bool
pub const fn plain_mode(&self) -> bool
Returns whether the underlying renderer is in plain (non-ANSI) mode.
CrosstermOptions::build sets this automatically based on whether the real process
stdout is an interactive terminal (see that method’s docs); CrosstermOptions::build_with_writer
always leaves it false, since an arbitrary writer’s “is this a terminal” status can’t be
determined generically. See
TerminalRenderer::set_plain_mode
for what plain mode changes about rendering.
Sourcepub const fn color_support(&self) -> ColorSupport
pub const fn color_support(&self) -> ColorSupport
Returns the configured ColorSupport level.
Set explicitly via CrosstermOptions::color_support, or auto-detected from
$NO_COLOR/$TERM if not overridden; see that method’s docs for the detection rules.
Sourcepub const fn writer_mut(&mut self) -> &mut W
pub const fn writer_mut(&mut self) -> &mut W
Returns a mutable reference to the content writer.
Source§impl<W: Write> Crossterm<W>
impl<W: Write> Crossterm<W>
Sourcepub fn suspend(&mut self) -> Result<SuspendGuard<'_, W>>
pub fn suspend(&mut self) -> Result<SuspendGuard<'_, W>>
Temporarily hands the real terminal back to the OS/shell, for shelling out to $EDITOR,
a pager, or a debugger.
Exits raw mode, leaves the alternate screen, and shows the cursor, only undoing whichever
of those this instance actually has active, using the same “only undo what was actually
done” bookkeeping this instance’s Drop and the process-wide panic hook already share,
leaving the terminal in the state a normal shell command expects. Mouse capture,
focus-change reporting, bracketed paste, and the kitty keyboard protocol are also
disabled, matching what a normal process exit/panic already does.
Returns a SuspendGuard borrowing self: while it’s alive, no other Crossterm method
can be called (the borrow checker enforces this), and dropping the guard (or calling
SuspendGuard::resume explicitly) restores every option this instance was originally
built with and forces a full redraw on the next [Output::draw], since whatever ran while
suspended may have written arbitrary content to the real screen that this backend’s diff
state doesn’t know about.
Does not handle Ctrl+Z/SIGTSTP: this is an explicit API for the common case (a key
binding that shells out), not a signal handler. An app that also wants to
suspend on SIGTSTP needs to install its own signal handler and call this method (and
SuspendGuard::resume) from it.
§Errors
Returns an std::io::Error if flushing the pending frame fails, or if any of the
terminal-restoring commands fail (e.g. a closed terminal or disconnected pipe).
Source§impl<W: Write> Crossterm<W>
impl<W: Write> Crossterm<W>
Sourcepub fn set_title(&mut self, title: &str) -> Result<()>
pub fn set_title(&mut self, title: &str) -> Result<()>
Sets the terminal window/tab title.
Queues crossterm::terminal::SetTitle and flushes immediately (unlike
[Cursor::set_cursor_visible]/[Cursor::set_cursor_position], this is not expected to be
called every frame, so there is no deferred-flush benefit to chase). Not every terminal
emulator honors this OSC sequence; on ones that don’t, this is silently a no-op from the
caller’s perspective.
§Errors
Returns an std::io::Error if writing or flushing the escape sequence fails (e.g. a
closed terminal or disconnected pipe).
Sourcepub fn ring_bell(&mut self) -> Result<()>
pub fn ring_bell(&mut self) -> Result<()>
Rings the terminal bell (writes the BEL control character, \x07).
Crossterm has no dedicated Command type for this (unlike Self::set_title’s
SetTitle), so this writes the raw byte directly. Whether the terminal actually makes a
sound, flashes, or does nothing at all is entirely up to the terminal emulator/user
configuration.
§Errors
Returns an std::io::Error if writing or flushing the byte fails (e.g. a closed terminal
or disconnected pipe).
Trait Implementations§
Source§impl<W: Write> Cursor for Crossterm<W>
impl<W: Write> Cursor for Crossterm<W>
Source§fn set_cursor_visible(&mut self, visible: bool)
fn set_cursor_visible(&mut self, visible: bool)
Queues the show/hide escape without flushing; the next [Output::flush] call drains it
along with everything else. A caller that hides the cursor and moves it in the same frame
(a common pattern right before a draw) would otherwise pay an extra flush per call on top
of the normal draw/flush pair, with no observable benefit since nothing reads the terminal
state in between.
Source§fn set_cursor_position(&mut self, position: Pos)
fn set_cursor_position(&mut self, position: Pos)
Queues the cursor-move escape without flushing; see set_cursor_visible’s
docs for why this is deferred to the next [Output::flush] instead of flushing here.
Source§fn set_cursor_style(&mut self, style: CursorStyle)
fn set_cursor_style(&mut self, style: CursorStyle)
Queues the DECSCUSR cursor-shape escape without flushing; see
set_cursor_visible’s docs for why this is deferred to the
next [Output::flush] instead of flushing here.
Source§impl<W: Write> Input for Crossterm<W>
impl<W: Write> Input for Crossterm<W>
Source§fn poll_event(&mut self, timeout: Duration) -> Option<Event>
fn poll_event(&mut self, timeout: Duration) -> Option<Event>
Polls for the next input event, blocking up to timeout. See the crate-level “Event
polling and CPU cost” doc section for what a zero timeout costs and where the actual CPU
cost of an uncapped game loop comes from.
Backends and examples in this workspace that need a frame cap (e.g. software + WASM,
gated on requestAnimationFrame) already throttle themselves upstream of this call; a
crossterm-driven loop wanting the same tradeoff should add its own
std::thread::sleep/tick budget around drain_events() rather than expecting this method
to throttle on its behalf.
Source§fn push_event(&mut self, event: Event)
fn push_event(&mut self, event: Event)
Queues event ahead of the real terminal’s own stream; the next
poll_event returns it.
See the pushed_events field comment for why this backend implements this at all, when it
has a perfectly good event source of its own.
Source§impl<W: Write> Output for Crossterm<W>
impl<W: Write> Output for Crossterm<W>
Source§fn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>where
I: Iterator<Item = DrawCell<'a>>,
fn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>where
I: Iterator<Item = DrawCell<'a>>,
Source§fn flush(&mut self) -> Result<(), Self::Error>
fn flush(&mut self) -> Result<(), Self::Error>
§fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>where
I: Iterator<Item = DrawCell<'a>>,
fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>where
I: Iterator<Item = DrawCell<'a>>,
§fn needs_full_frame(&self) -> bool
fn needs_full_frame(&self) -> bool
true if the backend needs the entire frame (all cells on
all layers) on every call to draw_layers, rather
than just the changed cells. Read more§fn composites_layers(&self) -> bool
fn composites_layers(&self) -> bool
draw_layers. Read more