Skip to main content

uncurses_ratatui/
init.rs

1//! Setup and teardown helpers for the default backend.
2//!
3//! ## What this module provides
4//!
5//! The backend constructors are deliberately explicit: constructing an
6//! [`UncursesBackend`] does not enter raw mode, hide the cursor, or switch
7//! screens. This module layers the conventional application setup on top and
8//! returns a ready-to-draw [`Terminal`].
9//!
10//! ## Fullscreen default
11//!
12//! [`try_init`] and [`init`] create a backend over process stdio, initialize
13//! the wrapped [`Program`](uncurses::program::Program) with default
14//! [`ProgramOptions`], enter the alternate screen, hide the cursor, and build a
15//! [`Terminal`] with [`Viewport::Fullscreen`].
16//!
17//! ## Custom options and viewports
18//!
19//! [`try_init_with_options`] and [`init_with_options`] accept the exact
20//! [`TerminalOptions`] and [`ProgramOptions`] to apply. Fullscreen and fixed
21//! viewports enter the alternate screen. [`Viewport::Inline`] intentionally
22//! stays on the main screen, resizes the screen buffer to the requested inline
23//! height, and lets the backend translate absolute frame rows into that inline
24//! buffer.
25//!
26//! ## Restoration
27//!
28//! [`try_restore`] calls [`UncursesBackend::restore`], which delegates to the
29//! wrapped screen's pause/teardown path: staged terminal modes are reset,
30//! cursor visibility and screen state are restored, pending bytes are flushed,
31//! and raw mode is left. [`restore`] is the logging convenience wrapper for
32//! applications that cannot use `?` during shutdown.
33//!
34//! ## Manual setup
35//!
36//! Use [`UncursesBackend::stdio`], [`UncursesBackend::open`],
37//! [`UncursesBackend::new`], and [`UncursesBackend::init_with`] directly when
38//! process stdio is not the desired terminal or setup must be interleaved with
39//! other terminal operations.
40
41use std::io;
42
43use ratatui::{Terminal, TerminalOptions, Viewport};
44use uncurses::program::ProgramOptions;
45use uncurses::terminal::{Stdin, Stdout};
46
47use crate::UncursesBackend;
48
49/// Default terminal type returned by the setup helpers.
50///
51/// This is a [`Terminal`] whose backend is [`UncursesBackend`] over the
52/// process standard input and output handles. Use this alias for APIs that
53/// accept the value returned by [`init`], [`try_init`],
54/// [`init_with_options`], or [`try_init_with_options`].
55///
56/// The alias itself performs no setup and cannot fail.
57pub type DefaultTerminal = Terminal<UncursesBackend<Stdin, Stdout>>;
58
59/// Initialize a fullscreen terminal over process stdio and panic on failure.
60///
61/// This is the infallible convenience wrapper around [`try_init`]. It is
62/// useful for examples and applications that prefer startup failure to abort
63/// immediately with a clear message.
64///
65/// ## Returns
66///
67/// A ready-to-draw [`DefaultTerminal`] using [`Viewport::Fullscreen`] and
68/// default [`ProgramOptions`].
69///
70/// ## Panics
71///
72/// Panics with `failed to initialize terminal` if [`try_init`] returns an
73/// error.
74///
75/// ## Usage note
76///
77/// Pair a successful call with [`restore`] or [`try_restore`] before exiting.
78pub fn init() -> DefaultTerminal {
79    try_init().expect("failed to initialize terminal")
80}
81
82/// Initialize a fullscreen terminal over process stdio.
83///
84/// This uses [`try_init_with_options`] with [`Viewport::Fullscreen`] and
85/// [`ProgramOptions::default`]. Setup constructs an [`UncursesBackend`] over
86/// stdio, initializes its screen, enters the alternate screen, hides the
87/// cursor, records the fullscreen viewport, and builds the returned
88/// [`Terminal`].
89///
90/// ## Returns
91///
92/// A ready-to-draw [`DefaultTerminal`].
93///
94/// ## Errors
95///
96/// Returns any error from opening or configuring stdio, entering raw mode,
97/// applying screen setup, entering the alternate screen, hiding the cursor, or
98/// constructing the [`Terminal`].
99///
100/// ## Panics
101///
102/// Does not intentionally panic. A poisoned internal event-source lock inside
103/// lower-level input code would still panic if encountered during later use.
104///
105/// ## Usage note
106///
107/// This function installs no panic hook. Teardown state lives inside the
108/// returned terminal, so install your own hook if the application needs
109/// best-effort restoration after panic. Pair normal exits with [`try_restore`]
110/// or [`restore`].
111pub fn try_init() -> io::Result<DefaultTerminal> {
112    try_init_with_options(
113        TerminalOptions {
114            viewport: Viewport::Fullscreen,
115        },
116        ProgramOptions::default(),
117    )
118}
119
120/// Initialize a terminal with explicit options and panic on failure.
121///
122/// This is the infallible convenience wrapper around
123/// [`try_init_with_options`].
124///
125/// ## Parameters
126///
127/// * `options` - widget-library terminal options, including the viewport.
128/// * `screen_options` - uncurses screen defaults to apply during screen init.
129///
130/// ## Returns
131///
132/// A ready-to-draw [`DefaultTerminal`] configured with the supplied options.
133///
134/// ## Panics
135///
136/// Panics with `failed to initialize terminal` if [`try_init_with_options`]
137/// returns an error.
138///
139/// ## Usage note
140///
141/// Use the fallible form in libraries or in applications that need custom error
142/// reporting. Pair a successful call with [`restore`] or [`try_restore`].
143pub fn init_with_options(
144    options: TerminalOptions,
145    screen_options: ProgramOptions,
146) -> DefaultTerminal {
147    try_init_with_options(options, screen_options).expect("failed to initialize terminal")
148}
149
150/// Initialize a terminal with explicit terminal and screen options.
151///
152/// Setup creates an [`UncursesBackend`] over process stdio, calls
153/// [`UncursesBackend::init_with`] with `screen_options`, conditionally enters
154/// the alternate screen, hides the cursor, records `options.viewport` in the
155/// backend, and finally calls [`Terminal::with_options`].
156///
157/// ## Parameters
158///
159/// * `options` - terminal options from the widget library. The viewport is
160///   cloned before constructing the [`Terminal`] so the backend can mirror the
161///   same viewport behavior.
162/// * `screen_options` - screen defaults controlling bracketed paste and mouse
163///   tracking.
164///
165/// ## Returns
166///
167/// A ready-to-draw [`DefaultTerminal`].
168///
169/// ## Errors
170///
171/// Returns any error from opening stdio, screen initialization, alternate
172/// screen entry, cursor hiding, or [`Terminal::with_options`].
173///
174/// ## Panics
175///
176/// Does not intentionally panic.
177///
178/// ## Usage note
179///
180/// [`Viewport::Inline`] stays on the main screen; all other viewports enter the
181/// alternate screen before the terminal is returned. Always restore with
182/// [`try_restore`] or [`restore`] after a successful setup.
183pub fn try_init_with_options(
184    options: TerminalOptions,
185    screen_options: ProgramOptions,
186) -> io::Result<DefaultTerminal> {
187    let viewport = options.viewport.clone();
188    let mut backend = UncursesBackend::stdio()?;
189    backend.init_with(screen_options)?;
190    if !matches!(viewport, Viewport::Inline(_)) {
191        backend.program_mut().enter_alt_screen()?;
192    }
193    backend.program_mut().hide_cursor()?;
194    backend.set_viewport(viewport);
195    Terminal::with_options(backend, options)
196}
197
198/// Restore a terminal built by the setup helpers, logging any error.
199///
200/// This convenience wrapper calls [`try_restore`] and writes a diagnostic to
201/// standard error if restoration fails. It is intended for shutdown paths where
202/// there is no useful way to return an error.
203///
204/// ## Parameters
205///
206/// * `terminal` - a terminal returned by this module's setup helpers.
207///
208/// ## Panics
209///
210/// Does not intentionally panic.
211///
212/// ## Usage note
213///
214/// Use [`try_restore`] when the caller can propagate or inspect restoration
215/// errors.
216pub fn restore(terminal: &mut DefaultTerminal) {
217    if let Err(e) = try_restore(terminal) {
218        eprintln!("failed to restore terminal: {e}");
219    }
220}
221
222/// Restore a terminal built by the setup helpers.
223///
224/// This calls [`UncursesBackend::restore`] on the terminal's backend. The
225/// backend delegates to the wrapped screen's teardown path, which resets staged
226/// modes, restores cursor and screen state, flushes pending output, and leaves
227/// raw mode.
228///
229/// ## Parameters
230///
231/// * `terminal` - a mutable [`DefaultTerminal`] returned by [`init`],
232///   [`try_init`], [`init_with_options`], or [`try_init_with_options`].
233///
234/// ## Returns
235///
236/// `Ok(())` once teardown has completed.
237///
238/// ## Errors
239///
240/// Returns any error from screen teardown, flushing, or restoring the terminal
241/// mode.
242///
243/// ## Panics
244///
245/// Does not intentionally panic.
246///
247/// ## Usage note
248///
249/// Treat this as the single teardown entry point for terminals initialized by
250/// this module; do not independently undo individual modes first.
251pub fn try_restore(terminal: &mut DefaultTerminal) -> io::Result<()> {
252    terminal.backend_mut().restore()
253}