ratatui/terminal/
init.rs

1use std::io::{self, stdout, Stdout};
2
3use crossterm::{
4    execute,
5    terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
6};
7
8use crate::{backend::CrosstermBackend, terminal::TerminalOptions, Terminal};
9
10/// A type alias for the default terminal type.
11///
12/// This is a [`Terminal`] using the [`CrosstermBackend`] which writes to [`Stdout`]. This is a
13/// reasonable default for most applications. To use a different backend or output stream, instead
14/// use [`Terminal`] and a [backend][`crate::backend`] of your choice directly.
15pub type DefaultTerminal = Terminal<CrosstermBackend<Stdout>>;
16
17/// Initialize a terminal with reasonable defaults for most applications.
18///
19/// This will create a new [`DefaultTerminal`] and initialize it with the following defaults:
20///
21/// - Backend: [`CrosstermBackend`] writing to [`Stdout`]
22/// - Raw mode is enabled
23/// - Alternate screen buffer enabled
24/// - A panic hook is installed that restores the terminal before panicking. Ensure that this method
25///   is called after any other panic hooks that may be installed to ensure that the terminal is
26///   restored before those hooks are called.
27///
28/// For more control over the terminal initialization, use [`Terminal::new`] or
29/// [`Terminal::with_options`].
30///
31/// Ensure that this method is called *after* your app installs any other panic hooks to ensure the
32/// terminal is restored before the other hooks are called.
33///
34/// Generally, use this function instead of [`try_init`] to ensure that the terminal is restored
35/// correctly if any of the initialization steps fail. If you need to handle the error yourself, use
36/// [`try_init`] instead.
37///
38/// # Panics
39///
40/// This function will panic if any of the following steps fail:
41///
42/// - Enabling raw mode
43/// - Entering the alternate screen buffer
44/// - Creating the terminal fails due to being unable to calculate the terminal size
45///
46/// # Examples
47///
48/// ```rust,no_run
49/// let terminal = ratatui::init();
50/// ```
51pub fn init() -> DefaultTerminal {
52    try_init().expect("failed to initialize terminal")
53}
54
55/// Try to initialize a terminal using reasonable defaults for most applications.
56///
57/// This function will attempt to create a [`DefaultTerminal`] and initialize it with the following
58/// defaults:
59///
60/// - Raw mode is enabled
61/// - Alternate screen buffer enabled
62/// - A panic hook is installed that restores the terminal before panicking.
63/// - A [`Terminal`] is created using [`CrosstermBackend`] writing to [`Stdout`]
64///
65/// If any of these steps fail, the error is returned.
66///
67/// Ensure that this method is called *after* your app installs any other panic hooks to ensure the
68/// terminal is restored before the other hooks are called.
69///
70/// Generally, you should use [`init`] instead of this function, as the panic hook installed by this
71/// function will ensure that any failures during initialization will restore the terminal before
72/// panicking. This function is provided for cases where you need to handle the error yourself.
73///
74/// # Examples
75///
76/// ```no_run
77/// let terminal = ratatui::try_init()?;
78/// # Ok::<(), std::io::Error>(())
79/// ```
80pub fn try_init() -> io::Result<DefaultTerminal> {
81    set_panic_hook();
82    enable_raw_mode()?;
83    execute!(stdout(), EnterAlternateScreen)?;
84    let backend = CrosstermBackend::new(stdout());
85    Terminal::new(backend)
86}
87
88/// Initialize a terminal with the given options and reasonable defaults.
89///
90/// This function allows the caller to specify a custom [`Viewport`] via the [`TerminalOptions`]. It
91/// will create a new [`DefaultTerminal`] and initialize it with the given options and the following
92/// defaults:
93///
94/// [`Viewport`]: crate::Viewport
95///
96/// - Raw mode is enabled
97/// - A panic hook is installed that restores the terminal before panicking.
98///
99/// Unlike [`init`], this function does not enter the alternate screen buffer as this may not be
100/// desired in all cases. If you need the alternate screen buffer, you should enable it manually
101/// after calling this function.
102///
103/// For more control over the terminal initialization, use [`Terminal::with_options`].
104///
105/// Ensure that this method is called *after* your app installs any other panic hooks to ensure the
106/// terminal is restored before the other hooks are called.
107///
108/// Generally, use this function instead of [`try_init_with_options`] to ensure that the terminal is
109/// restored correctly if any of the initialization steps fail. If you need to handle the error
110/// yourself, use [`try_init_with_options`] instead.
111///
112/// # Panics
113///
114/// This function will panic if any of the following steps fail:
115///
116/// - Enabling raw mode
117/// - Creating the terminal fails due to being unable to calculate the terminal size
118///
119/// # Examples
120///
121/// ```rust,no_run
122/// use ratatui::{TerminalOptions, Viewport};
123///
124/// let options = TerminalOptions {
125///     viewport: Viewport::Inline(5),
126/// };
127/// let terminal = ratatui::init_with_options(options);
128/// ```
129pub fn init_with_options(options: TerminalOptions) -> DefaultTerminal {
130    try_init_with_options(options).expect("failed to initialize terminal")
131}
132
133/// Try to initialize a terminal with the given options and reasonable defaults.
134///
135/// This function allows the caller to specify a custom [`Viewport`] via the [`TerminalOptions`]. It
136/// will attempt to create a [`DefaultTerminal`] and initialize it with the given options and the
137/// following defaults:
138///
139/// [`Viewport`]: crate::Viewport
140///
141/// - Raw mode is enabled
142/// - A panic hook is installed that restores the terminal before panicking.
143///
144/// Unlike [`try_init`], this function does not enter the alternate screen buffer as this may not be
145/// desired in all cases. If you need the alternate screen buffer, you should enable it manually
146/// after calling this function.
147///
148/// If any of these steps fail, the error is returned.
149///
150/// Ensure that this method is called *after* your app installs any other panic hooks to ensure the
151/// terminal is restored before the other hooks are called.
152///
153/// Generally, you should use [`init_with_options`] instead of this function, as the panic hook
154/// installed by this function will ensure that any failures during initialization will restore the
155/// terminal before panicking. This function is provided for cases where you need to handle the
156/// error yourself.
157///
158/// # Examples
159///
160/// ```no_run
161/// use ratatui::{TerminalOptions, Viewport};
162///
163/// let options = TerminalOptions {
164///     viewport: Viewport::Inline(5),
165/// };
166/// let terminal = ratatui::try_init_with_options(options)?;
167/// # Ok::<(), std::io::Error>(())
168/// ```
169pub fn try_init_with_options(options: TerminalOptions) -> io::Result<DefaultTerminal> {
170    set_panic_hook();
171    enable_raw_mode()?;
172    let backend = CrosstermBackend::new(stdout());
173    Terminal::with_options(backend, options)
174}
175
176/// Restores the terminal to its original state.
177///
178/// This function should be called before the program exits to ensure that the terminal is
179/// restored to its original state.
180///
181/// This function will attempt to restore the terminal to its original state by performing the
182/// following steps:
183///
184/// 1. Raw mode is disabled.
185/// 2. The alternate screen buffer is left.
186///
187/// If either of these steps fail, the error is printed to stderr and ignored.
188///
189/// Use this function over [`try_restore`] when you don't need to handle the error yourself, as
190/// ignoring the error is generally the correct behavior when cleaning up before exiting. If you
191/// need to handle the error yourself, use [`try_restore`] instead.
192///
193/// # Examples
194///
195/// ```rust,no_run
196/// ratatui::restore();
197/// ```
198pub fn restore() {
199    if let Err(err) = try_restore() {
200        // There's not much we can do if restoring the terminal fails, so we just print the error
201        eprintln!("Failed to restore terminal: {err}");
202    }
203}
204
205/// Restore the terminal to its original state.
206///
207/// This function will attempt to restore the terminal to its original state by performing the
208/// following steps:
209///
210/// 1. Raw mode is disabled.
211/// 2. The alternate screen buffer is left.
212///
213/// If either of these steps fail, the error is returned.
214///
215/// Use [`restore`] instead of this function when you don't need to handle the error yourself, as
216/// ignoring the error is generally the correct behavior when cleaning up before exiting. If you
217/// need to handle the error yourself, use this function instead.
218///
219/// # Examples
220///
221/// ```no_run
222/// ratatui::try_restore()?;
223/// # Ok::<(), std::io::Error>(())
224/// ```
225pub fn try_restore() -> io::Result<()> {
226    // disabling raw mode first is important as it has more side effects than leaving the alternate
227    // screen buffer
228    disable_raw_mode()?;
229    execute!(stdout(), LeaveAlternateScreen)?;
230    Ok(())
231}
232
233/// Sets a panic hook that restores the terminal before panicking.
234///
235/// Replaces the panic hook with a one that will restore the terminal state before calling the
236/// original panic hook. This ensures that the terminal is left in a good state when a panic occurs.
237fn set_panic_hook() {
238    let hook = std::panic::take_hook();
239    std::panic::set_hook(Box::new(move |info| {
240        restore();
241        hook(info);
242    }));
243}