Skip to main content

Crossterm

Struct Crossterm 

Source
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

Source

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| {})?;
Source

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 terminal
Source

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.

Source

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.

Source

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>

Source

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());
Source

pub const fn writer(&self) -> &W

Returns a reference to the content writer.

Source

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.

Source

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.

Source

pub const fn writer_mut(&mut self) -> &mut W

Returns a mutable reference to the content writer.

Source§

impl<W: Write> Crossterm<W>

Source

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>

Source

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).

Source

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>

Source§

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)

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)

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> Drop for Crossterm<W>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<W: Write> Input for Crossterm<W>

Source§

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)

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>

Source§

type Error = Error

Error type returned by fallible operations.
Source§

fn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where I: Iterator<Item = DrawCell<'a>>,

Draw changed cells across all layers. Read more
Source§

fn flush(&mut self) -> Result<(), Self::Error>

Flush buffered output to the display. Read more
Source§

fn size(&self) -> Size

Return current display dimensions.
Source§

fn resize(&mut self, size: Size)

Notify the backend of a resize to size, updating what size reports. Read more
Source§

fn clear(&mut self) -> Result<(), Self::Error>

Clear the entire display. Read more
§

fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where I: Iterator<Item = DrawCell<'a>>,

Draw changed cells to the output surface, layer 0 only. Read more
§

fn needs_full_frame(&self) -> bool

Returns 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

Whether this backend composites layers itself (per pixel or quad), receiving the raw layered stream from draw_layers. Read more

Auto Trait Implementations§

§

impl<W> Freeze for Crossterm<W>
where W: Freeze,

§

impl<W> RefUnwindSafe for Crossterm<W>
where W: RefUnwindSafe,

§

impl<W> Send for Crossterm<W>
where W: Send,

§

impl<W> Sync for Crossterm<W>
where W: Sync,

§

impl<W> Unpin for Crossterm<W>
where W: Unpin,

§

impl<W> UnsafeUnpin for Crossterm<W>
where W: UnsafeUnpin,

§

impl<W> UnwindSafe for Crossterm<W>
where W: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<T> Backend for T
where T: Output + Input + Cursor,