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 [`Screen`](uncurses::screen::Screen) with default
14//! [`ScreenOptions`], 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 [`ScreenOptions`] 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::screen::ScreenOptions;
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 [`ScreenOptions`].
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/// [`ScreenOptions::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 ScreenOptions::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: ScreenOptions,
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, keyboard
163/// enhancements, mouse tracking, in-band resize preference, and pixel-size
164/// behavior.
165///
166/// ## Returns
167///
168/// A ready-to-draw [`DefaultTerminal`].
169///
170/// ## Errors
171///
172/// Returns any error from opening stdio, screen initialization, alternate
173/// screen entry, cursor hiding, or [`Terminal::with_options`].
174///
175/// ## Panics
176///
177/// Does not intentionally panic.
178///
179/// ## Usage note
180///
181/// [`Viewport::Inline`] stays on the main screen; all other viewports enter the
182/// alternate screen before the terminal is returned. Always restore with
183/// [`try_restore`] or [`restore`] after a successful setup.
184pub fn try_init_with_options(
185 options: TerminalOptions,
186 screen_options: ScreenOptions,
187) -> io::Result<DefaultTerminal> {
188 let viewport = options.viewport.clone();
189 let mut backend = UncursesBackend::stdio()?;
190 backend.init_with(screen_options)?;
191 if !matches!(viewport, Viewport::Inline(_)) {
192 backend.screen_mut().enter_alt_screen()?;
193 }
194 backend.screen_mut().hide_cursor()?;
195 backend.set_viewport(viewport);
196 Terminal::with_options(backend, options)
197}
198
199/// Restore a terminal built by the setup helpers, logging any error.
200///
201/// This convenience wrapper calls [`try_restore`] and writes a diagnostic to
202/// standard error if restoration fails. It is intended for shutdown paths where
203/// there is no useful way to return an error.
204///
205/// ## Parameters
206///
207/// * `terminal` - a terminal returned by this module's setup helpers.
208///
209/// ## Panics
210///
211/// Does not intentionally panic.
212///
213/// ## Usage note
214///
215/// Use [`try_restore`] when the caller can propagate or inspect restoration
216/// errors.
217pub fn restore(terminal: &mut DefaultTerminal) {
218 if let Err(e) = try_restore(terminal) {
219 eprintln!("failed to restore terminal: {e}");
220 }
221}
222
223/// Restore a terminal built by the setup helpers.
224///
225/// This calls [`UncursesBackend::restore`] on the terminal's backend. The
226/// backend delegates to the wrapped screen's teardown path, which resets staged
227/// modes, restores cursor and screen state, flushes pending output, and leaves
228/// raw mode.
229///
230/// ## Parameters
231///
232/// * `terminal` - a mutable [`DefaultTerminal`] returned by [`init`],
233/// [`try_init`], [`init_with_options`], or [`try_init_with_options`].
234///
235/// ## Returns
236///
237/// `Ok(())` once teardown has completed.
238///
239/// ## Errors
240///
241/// Returns any error from screen teardown, flushing, or restoring the terminal
242/// mode.
243///
244/// ## Panics
245///
246/// Does not intentionally panic.
247///
248/// ## Usage note
249///
250/// Treat this as the single teardown entry point for terminals initialized by
251/// this module; do not independently undo individual modes first.
252pub fn try_restore(terminal: &mut DefaultTerminal) -> io::Result<()> {
253 terminal.backend_mut().restore()
254}