ratatui 0.30.0

A library that's all about cooking up terminal user interfaces
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
//! Terminal initialization and restoration functions.
//!
//! This module provides a set of convenience functions for initializing and restoring terminal
//! state when creating Ratatui applications. These functions handle the common setup and teardown
//! tasks required for terminal user interfaces.
//!
//! All functions in this module use the [`CrosstermBackend`] by default, which provides excellent
//! cross-platform compatibility and is the recommended backend for most applications. The
//! [`DefaultTerminal`] type alias encapsulates this choice, providing a ready-to-use terminal
//! configuration that works well across different operating systems. For more information about
//! backend choices and alternatives, see the [`backend`](`crate::backend`) module.
//!
//! Once you have initialized a terminal using the functions in this module, you can use it to
//! [draw the UI](`crate#drawing-the-ui`) and [handle events](`crate#handling-events`). For more
//! information about building widgets for your application, see the [`widgets`](`crate::widgets`)
//! module.
//!
//! **Note**: All functions and types in this module are re-exported at the crate root for
//! convenience, so you can call `ratatui::run()`, `ratatui::init()`, etc. instead of
//! `ratatui::init::run()`, `ratatui::init::init()`, etc.
//!
//! # Available Types and Functions
//!
//! ## Types
//!
//! - [`DefaultTerminal`] - A type alias for `Terminal<CrosstermBackend<Stdout>>`, providing a
//!   reasonable default terminal configuration for most applications. All initialization functions
//!   return this type.
//!
//! ## Functions
//!
//! The module provides several related functions that handle different initialization scenarios:
//!
//! - [`run`] - Initializes a terminal, runs a closure, and automatically restores the terminal
//!   state. This is the simplest way to run a Ratatui application and handles all setup and cleanup
//!   automatically.
//! - [`init`] - Creates a terminal with reasonable defaults including alternate screen and raw
//!   mode. Panics on failure.
//! - [`try_init`] - Same as [`init`] but returns a `Result` instead of panicking.
//! - [`init_with_options`] - Creates a terminal with custom [`TerminalOptions`], enabling raw mode
//!   but not alternate screen. Panics on failure.
//! - [`try_init_with_options`] - Same as [`init_with_options`] but returns a `Result` instead of
//!   panicking.
//! - [`restore`] - Restores the terminal to its original state. Prints errors to stderr but does
//!   not panic.
//! - [`try_restore`] - Same as [`restore`] but returns a `Result` instead of printing errors.
//!
//! # Usage Guide
//!
//! For the simplest setup with automatic cleanup, use [`run`]:
//!
//! ```rust,no_run
//! fn main() -> std::io::Result<()> {
//!     ratatui::run(|terminal| {
//!         loop {
//!             terminal.draw(|frame| frame.render_widget("Hello, world!", frame.area()))?;
//!             if crossterm::event::read()?.is_key_press() {
//!                 break Ok(());
//!             }
//!         }
//!     })
//! }
//! ```
//!
//! For standard full-screen applications with manual control over initialization and cleanup:
//!
//! ```rust,no_run
//! // Using init() - panics on failure
//! let mut terminal = ratatui::init();
//! // ... app logic ...
//! ratatui::restore();
//!
//! // Using try_init() - returns Result for custom error handling
//! let mut terminal = ratatui::try_init()?;
//! // ... app logic ...
//! ratatui::try_restore()?;
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! For applications that need custom terminal behavior (inline rendering, custom viewport sizes,
//! or applications that don't want alternate screen buffer):
//!
//! ```rust,no_run
//! use ratatui::{TerminalOptions, Viewport};
//!
//! let options = TerminalOptions {
//!     viewport: Viewport::Inline(10),
//! };
//!
//! // Using init_with_options() - panics on failure
//! let mut terminal = ratatui::init_with_options(options);
//! // ... app logic ...
//! ratatui::restore();
//!
//! // Using try_init_with_options() - returns Result for custom error handling
//! let options = TerminalOptions {
//!     viewport: Viewport::Inline(10),
//! };
//! let mut terminal = ratatui::try_init_with_options(options)?;
//! // ... app logic ...
//! ratatui::try_restore()?;
//! # Ok::<(), std::io::Error>(())
//! ```
//!
//! For cleanup, use [`restore`] in most cases where you want to attempt restoration but don't need
//! to handle errors (they are printed to stderr). Use [`try_restore`] when you need to handle
//! restoration errors, perhaps to retry or provide user feedback.
//!
//! Once you have a terminal set up, continue with the main loop to [draw the
//! UI](`crate#drawing-the-ui`) and [handle events](`crate#handling-events`). See the [main crate
//! documentation](`crate`) for comprehensive examples of complete applications.
//!
//! # Key Differences
//!
//! | Function | Alternate Screen | Raw Mode | Error Handling | Use Case |
//! |----------|------------------|----------|----------------|----------|
//! | [`run`] | ✓ | ✓ | Auto-cleanup | Simple apps |
//! | [`init`] | ✓ | ✓ | Panic | Standard full-screen apps |
//! | [`try_init`] | ✓ | ✓ | Result | Standard apps with error handling |
//! | [`init_with_options`] | ✗ | ✓ | Panic | Custom viewport apps |
//! | [`try_init_with_options`] | ✗ | ✓ | Result | Custom viewport with error handling |
//!
//! # Panic Hook
//!
//! All initialization functions install a panic hook that automatically restores the terminal
//! state before panicking. This ensures that even if your application panics, the terminal will
//! be left in a usable state.
//!
//! **Important**: Call the initialization functions *after* installing any other panic hooks to
//! ensure the terminal is restored before other hooks run.

use std::io::{self, Stdout, stdout};

use ratatui_core::terminal::{Terminal, TerminalOptions};
use ratatui_crossterm::CrosstermBackend;
use ratatui_crossterm::crossterm::execute;
use ratatui_crossterm::crossterm::terminal::{
    EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode,
};

/// A type alias for the default terminal type.
///
/// This is a [`Terminal`] using the [`CrosstermBackend`] which writes to [`Stdout`]. This is a
/// reasonable default for most applications. To use a different backend or output stream, instead
/// use [`Terminal`] and a [backend][`crate::backend`] of your choice directly.
pub type DefaultTerminal = Terminal<CrosstermBackend<Stdout>>;

/// Run a closure with a terminal initialized with reasonable defaults for most applications.
///
/// This function creates a new [`DefaultTerminal`] with [`init`] and then runs the given closure
/// with a mutable reference to the terminal. After the closure completes, the terminal is restored
/// to its original state with [`restore`].
///
/// This function is a convenience wrapper around [`init`] and [`restore`], and is useful for simple
/// applications that need a terminal with reasonable defaults for the entire lifetime of the
/// application.
///
/// See the [module-level documentation](mod@crate::init) for a comparison of all initialization
/// functions and guidance on when to use each one.
///
/// # Examples
///
/// A simple example where the app logic is contained in the closure:
///
/// ```rust,no_run
/// use crossterm::event;
///
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
///     ratatui::run(|terminal| {
///         loop {
///             terminal.draw(|frame| frame.render_widget("Hello, world!", frame.area()))?;
///             if event::read()?.is_key_press() {
///                 break Ok(());
///             }
///         }
///     })
/// }
/// ```
///
/// A more complex example where the app logic is contained in a separate function:
///
/// ```rust,no_run
/// use crossterm::event;
///
/// type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
///
/// fn main() -> Result<()> {
///     ratatui::run(app)
/// }
///
/// fn app(terminal: &mut ratatui::DefaultTerminal) -> Result<()> {
///     const GREETING: &str = "Hello, world!";
///     loop {
///         terminal.draw(|frame| frame.render_widget(format!("{GREETING}"), frame.area()))?;
///         if matches!(event::read()?, event::Event::Key(_)) {
///             break Ok(());
///         }
///     }
/// }
/// ```
///
/// Once the app logic becomes more complex, it may be beneficial to move the app logic into a
/// separate struct. This allows the app logic to be split into multiple methods with each having
/// access to the state of the app. This can make the app logic easier to understand and maintain.
///
/// ```rust,no_run
/// use crossterm::event;
///
/// type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
///
/// fn main() -> Result<()> {
///     let mut app = App::new();
///     ratatui::run(|terminal| app.run(terminal))
/// }
///
/// struct App {
///     should_quit: bool,
///     name: String,
/// }
///
/// impl App {
///     fn new() -> Self {
///         Self {
///             should_quit: false,
///             name: "world".to_string(),
///         }
///     }
///
///     fn run(&mut self, terminal: &mut ratatui::DefaultTerminal) -> Result<()> {
///         while !self.should_quit {
///             terminal.draw(|frame| frame.render_widget("Hello, world!", frame.area()))?;
///             self.handle_events()?;
///         }
///         Ok(())
///     }
///
///     fn render(&mut self, frame: &mut ratatui::Frame) -> Result<()> {
///         let greeting = format!("Hello, {}!", self.name);
///         frame.render_widget(greeting, frame.area());
///         Ok(())
///     }
///
///     fn handle_events(&mut self) -> Result<()> {
///         if event::read()?.is_key_press() {
///             self.should_quit = true;
///         }
///         Ok(())
///     }
/// }
/// ```
pub fn run<F, R>(f: F) -> R
where
    F: FnOnce(&mut DefaultTerminal) -> R,
{
    let mut terminal = init();
    let result = f(&mut terminal);
    restore();
    result
}

/// Initialize a terminal with reasonable defaults for most applications.
///
/// This will create a new [`DefaultTerminal`] and initialize it with the following defaults:
///
/// - Backend: [`CrosstermBackend`] writing to [`Stdout`]
/// - Raw mode is enabled
/// - Alternate screen buffer enabled
/// - A panic hook is installed that restores the terminal before panicking. Ensure that this method
///   is called after any other panic hooks that may be installed to ensure that the terminal is
///   restored before those hooks are called.
///
/// For more control over the terminal initialization, use [`Terminal::new`] or
/// [`Terminal::with_options`].
///
/// Ensure that this method is called *after* your app installs any other panic hooks to ensure the
/// terminal is restored before the other hooks are called.
///
/// Generally, use this function instead of [`try_init`] to ensure that the terminal is restored
/// correctly if any of the initialization steps fail. If you need to handle the error yourself, use
/// [`try_init`] instead.
///
/// See the [module-level documentation](mod@crate::init) for a comparison of all initialization
/// functions and guidance on when to use each one.
///
/// # Panics
///
/// This function will panic if any of the following steps fail:
///
/// - Enabling raw mode
/// - Entering the alternate screen buffer
/// - Creating the terminal fails due to being unable to calculate the terminal size
///
/// # Examples
///
/// ```rust,no_run
/// let terminal = ratatui::init();
/// ```
pub fn init() -> DefaultTerminal {
    try_init().expect("failed to initialize terminal")
}

/// Try to initialize a terminal using reasonable defaults for most applications.
///
/// This function will attempt to create a [`DefaultTerminal`] and initialize it with the following
/// defaults:
///
/// - Raw mode is enabled
/// - Alternate screen buffer enabled
/// - A panic hook is installed that restores the terminal before panicking.
/// - A [`Terminal`] is created using [`CrosstermBackend`] writing to [`Stdout`]
///
/// If any of these steps fail, the error is returned.
///
/// Ensure that this method is called *after* your app installs any other panic hooks to ensure the
/// terminal is restored before the other hooks are called.
///
/// Generally, you should use [`init`] instead of this function, as the panic hook installed by this
/// function will ensure that any failures during initialization will restore the terminal before
/// panicking. This function is provided for cases where you need to handle the error yourself.
///
/// See the [module-level documentation](mod@crate::init) for a comparison of all initialization
/// functions and guidance on when to use each one.
///
/// # Examples
///
/// ```no_run
/// let terminal = ratatui::try_init()?;
/// # Ok::<(), std::io::Error>(())
/// ```
pub fn try_init() -> io::Result<DefaultTerminal> {
    set_panic_hook();
    enable_raw_mode()?;
    execute!(stdout(), EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout());
    Terminal::new(backend)
}

/// Initialize a terminal with the given options and reasonable defaults.
///
/// This function allows the caller to specify a custom [`Viewport`] via the [`TerminalOptions`]. It
/// will create a new [`DefaultTerminal`] and initialize it with the given options and the following
/// defaults:
///
/// [`Viewport`]: crate::Viewport
///
/// - Raw mode is enabled
/// - A panic hook is installed that restores the terminal before panicking.
///
/// Unlike [`init`], this function does not enter the alternate screen buffer as this may not be
/// desired in all cases. If you need the alternate screen buffer, you should enable it manually
/// after calling this function.
///
/// For more control over the terminal initialization, use [`Terminal::with_options`].
///
/// Ensure that this method is called *after* your app installs any other panic hooks to ensure the
/// terminal is restored before the other hooks are called.
///
/// Generally, use this function instead of [`try_init_with_options`] to ensure that the terminal is
/// restored correctly if any of the initialization steps fail. If you need to handle the error
/// yourself, use [`try_init_with_options`] instead.
///
/// See the [module-level documentation](mod@crate::init) for a comparison of all initialization
/// functions and guidance on when to use each one.
///
/// # Panics
///
/// This function will panic if any of the following steps fail:
///
/// - Enabling raw mode
/// - Creating the terminal fails due to being unable to calculate the terminal size
///
/// # Examples
///
/// ```rust,no_run
/// use ratatui::{TerminalOptions, Viewport};
///
/// let options = TerminalOptions {
///     viewport: Viewport::Inline(5),
/// };
/// let terminal = ratatui::init_with_options(options);
/// ```
pub fn init_with_options(options: TerminalOptions) -> DefaultTerminal {
    try_init_with_options(options).expect("failed to initialize terminal")
}

/// Try to initialize a terminal with the given options and reasonable defaults.
///
/// This function allows the caller to specify a custom [`Viewport`] via the [`TerminalOptions`]. It
/// will attempt to create a [`DefaultTerminal`] and initialize it with the given options and the
/// following defaults:
///
/// [`Viewport`]: crate::Viewport
///
/// - Raw mode is enabled
/// - A panic hook is installed that restores the terminal before panicking.
///
/// Unlike [`try_init`], this function does not enter the alternate screen buffer as this may not be
/// desired in all cases. If you need the alternate screen buffer, you should enable it manually
/// after calling this function.
///
/// If any of these steps fail, the error is returned.
///
/// Ensure that this method is called *after* your app installs any other panic hooks to ensure the
/// terminal is restored before the other hooks are called.
///
/// Generally, you should use [`init_with_options`] instead of this function, as the panic hook
/// installed by this function will ensure that any failures during initialization will restore the
/// terminal before panicking. This function is provided for cases where you need to handle the
/// error yourself.
///
/// See the [module-level documentation](mod@crate::init) for a comparison of all initialization
/// functions and guidance on when to use each one.
///
/// # Examples
///
/// ```no_run
/// use ratatui::{TerminalOptions, Viewport};
///
/// let options = TerminalOptions {
///     viewport: Viewport::Inline(5),
/// };
/// let terminal = ratatui::try_init_with_options(options)?;
/// # Ok::<(), std::io::Error>(())
/// ```
pub fn try_init_with_options(options: TerminalOptions) -> io::Result<DefaultTerminal> {
    set_panic_hook();
    enable_raw_mode()?;
    let backend = CrosstermBackend::new(stdout());
    Terminal::with_options(backend, options)
}

/// Restores the terminal to its original state.
///
/// This function should be called before the program exits to ensure that the terminal is
/// restored to its original state.
///
/// This function will attempt to restore the terminal to its original state by performing the
/// following steps:
///
/// 1. Raw mode is disabled.
/// 2. The alternate screen buffer is left.
///
/// If either of these steps fail, the error is printed to stderr and ignored.
///
/// Use this function over [`try_restore`] when you don't need to handle the error yourself, as
/// ignoring the error is generally the correct behavior when cleaning up before exiting. If you
/// need to handle the error yourself, use [`try_restore`] instead.
///
/// See the [module-level documentation](mod@crate::init) for a comparison of all initialization
/// functions and guidance on when to use each one.
///
/// # Examples
///
/// ```rust,no_run
/// ratatui::restore();
/// ```
pub fn restore() {
    if let Err(err) = try_restore() {
        // There's not much we can do if restoring the terminal fails, so we just print the error
        std::eprintln!("Failed to restore terminal: {err}");
    }
}

/// Restore the terminal to its original state.
///
/// This function will attempt to restore the terminal to its original state by performing the
/// following steps:
///
/// 1. Raw mode is disabled.
/// 2. The alternate screen buffer is left.
///
/// If either of these steps fail, the error is returned.
///
/// Use [`restore`] instead of this function when you don't need to handle the error yourself, as
/// ignoring the error is generally the correct behavior when cleaning up before exiting. If you
/// need to handle the error yourself, use this function instead.
///
/// See the [module-level documentation](mod@crate::init) for a comparison of all initialization
/// functions and guidance on when to use each one.
///
/// # Examples
///
/// ```no_run
/// ratatui::try_restore()?;
/// # Ok::<(), std::io::Error>(())
/// ```
pub fn try_restore() -> io::Result<()> {
    // disabling raw mode first is important as it has more side effects than leaving the alternate
    // screen buffer
    disable_raw_mode()?;
    execute!(stdout(), LeaveAlternateScreen)?;
    Ok(())
}

/// Sets a panic hook that restores the terminal before panicking.
///
/// Replaces the panic hook with a one that will restore the terminal state before calling the
/// original panic hook. This ensures that the terminal is left in a good state when a panic occurs.
fn set_panic_hook() {
    let hook = std::panic::take_hook();
    std::panic::set_hook(alloc::boxed::Box::new(move |info| {
        restore();
        hook(info);
    }));
}