diff --git a/ratatui-core/src/terminal/terminal.rs b/ratatui-core/src/terminal/terminal.rs index 39c93994..8b91aa43 100644 --- a/ratatui-core/src/terminal/terminal.rs +++ b/ratatui-core/src/terminal/terminal.rs @@ -26,8 +26,32 @@ use crate::terminal::{CompletedFrame, Frame, TerminalOptions, Viewport}; /// application with the new size. This will automatically resize the internal buffers to match the /// new size for inline and fullscreen viewports. Fixed viewports are not resized automatically. /// +/// # Initialization +/// +/// For most applications, consider using the convenience functions `ratatui::run()`, +/// `ratatui::init()`, and `ratatui::restore()` (available since version 0.28.1) along with the +/// `DefaultTerminal` type alias instead of constructing `Terminal` instances manually. These +/// functions handle the common setup and teardown tasks automatically. Manual construction +/// using `Terminal::new()` or `Terminal::with_options()` is still supported for applications +/// that need fine-grained control over initialization. +/// /// # Examples /// +/// ## Using convenience functions (recommended for most applications) +/// +/// ```rust,ignore +/// // Modern approach using convenience functions +/// ratatui::run(|terminal| { +/// terminal.draw(|frame| { +/// let area = frame.area(); +/// frame.render_widget(Paragraph::new("Hello World!"), area); +/// })?; +/// Ok(()) +/// })?; +/// ``` +/// +/// ## Manual construction (for fine-grained control) +/// /// ```rust,ignore /// use std::io::stdout; /// diff --git a/ratatui/src/init.rs b/ratatui/src/init.rs index 3312175f..e5ea2dc1 100644 --- a/ratatui/src/init.rs +++ b/ratatui/src/init.rs @@ -1,3 +1,134 @@ +//! 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>`, 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}; @@ -24,6 +155,9 @@ pub type DefaultTerminal = Terminal>; /// 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: @@ -145,6 +279,9 @@ where /// 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: @@ -181,6 +318,9 @@ pub fn init() -> DefaultTerminal { /// 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 @@ -219,6 +359,9 @@ pub fn try_init() -> io::Result { /// 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: @@ -265,6 +408,9 @@ pub fn init_with_options(options: TerminalOptions) -> DefaultTerminal { /// 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 @@ -300,6 +446,9 @@ pub fn try_init_with_options(options: TerminalOptions) -> io::Result std::io::Result<()> { +//! ratatui::run(|mut terminal| { +//! loop { +//! terminal.draw(|frame| frame.render_widget("Hello World!", frame.area()))?; +//! if event::read()?.is_key_press() { +//! break Ok(()); +//! } //! } -//! } -//! ratatui::restore(); -//! } -//! -//! fn draw(frame: &mut Frame) { -//! let text = Text::raw("Hello World!"); -//! frame.render_widget(text, frame.area()); +//! }) //! } //! ``` //! //! The full code for this example which contains a little more detail is in the [Examples] //! directory. For more guidance on different ways to structure your application see the -//! [Application Patterns] and [Hello World tutorial] sections in the [Ratatui Website] and the -//! various [Examples]. There are also several starter templates available in the [templates] -//! repository. +//! [Application Patterns] and [Hello Ratatui tutorial] sections in the [Ratatui Website] and the +//! various [Examples]. There are also several starter [Templates] available to help you get +//! started quickly with common patterns. //! //! # Other documentation //! //! - [Ratatui Website] - explains the library's concepts and provides step-by-step tutorials +//! - [Tutorials] - step-by-step guides including [Hello Ratatui tutorial] and [Counter App] +//! - [Recipes] - practical how-to guides for common tasks and patterns +//! - [FAQ] - frequently asked questions and answers +//! - [Templates] - pre-built project templates using [Cargo Generate] +//! - [Showcase] - a gallery of applications and widgets built with Ratatui //! - [Ratatui Forum][Forum] - a place to ask questions and discuss the library //! - [API Docs] - the full API documentation for the library on docs.rs. //! - [Examples] - a collection of examples that demonstrate how to use the library. @@ -77,6 +75,12 @@ //! You can also watch the [FOSDEM 2024 talk] about Ratatui which gives a brief introduction to //! terminal user interfaces and showcases the features of Ratatui, along with a hello world demo. //! +//! ## Getting Help +//! +//! If you need help or have questions, check out our [FAQ] for common questions and solutions. +//! You can also join our community on [Discord][Discord Server], [Matrix], or post on our +//! [Forum] for assistance and discussions. +//! //! # Crate Organization //! //! Starting with Ratatui 0.30.0, the project was reorganized into a modular workspace to improve @@ -97,7 +101,7 @@ //! See [ARCHITECTURE.md] for detailed information about the crate organization and design //! decisions. //! -//! # Introduction +//! # Writing Applications //! //! Ratatui is based on the principle of immediate rendering with intermediate buffers. This means //! that for each frame, your app must render all [`widgets`] that are supposed to be part of the @@ -111,7 +115,7 @@ //! //! Every application built with `ratatui` needs to implement the following steps: //! -//! - Initialize the terminal +//! - Initialize the terminal (see the [`init` module] for convenient initialization functions) //! - A main loop that: //! - Draws the UI //! - Handles input events @@ -119,30 +123,70 @@ //! //! ## Initialize and restore the terminal //! -//! The [`Terminal`] type is the main entry point for any Ratatui application. It is generic over a -//! a choice of [`Backend`] implementations that each provide functionality to draw frames, clear -//! the screen, hide the cursor, etc. There are backend implementations for [Crossterm], [Termion] -//! and [Termwiz]. +//! The simplest way to initialize and run a terminal application is to use the [`run()`] function, +//! which handles terminal initialization, restoration, and panic hooks automatically: //! -//! The simplest way to initialize the terminal is to use the [`init`] function which returns a -//! [`DefaultTerminal`] instance with the default options, enters the Alternate Screen and Raw mode -//! and sets up a panic hook that restores the terminal in case of panic. This instance can then be -//! used to draw frames and interact with the terminal state. (The [`DefaultTerminal`] instance is a -//! type alias for a terminal with the [`crossterm`] backend.) The [`restore`] function restores the -//! terminal to its original state. +//! ```rust,no_run +//! fn main() -> std::io::Result<()> { +//! ratatui::run(|mut terminal| { +//! loop { +//! terminal.draw(render)?; +//! if should_quit()? { +//! break Ok(()); +//! } +//! } +//! }) +//! } +//! +//! fn render(frame: &mut ratatui::Frame) { +//! // ... +//! } +//! +//! fn should_quit() -> std::io::Result { +//! // ... +//! # Ok(false) +//! } +//! ``` +//! +//! For more control over initialization and restoration, you can use [`init()`] and [`restore()`]: //! //! ```rust,no_run //! fn main() -> std::io::Result<()> { //! let mut terminal = ratatui::init(); -//! let result = run(&mut terminal); +//! let result = run_app(&mut terminal); //! ratatui::restore(); //! result //! } -//! # fn run(terminal: &mut ratatui::DefaultTerminal) -> std::io::Result<()> { Ok(()) } +//! +//! fn run_app(terminal: &mut ratatui::DefaultTerminal) -> std::io::Result<()> { +//! loop { +//! terminal.draw(render)?; +//! if should_quit()? { +//! break Ok(()); +//! } +//! } +//! } +//! # fn render(_frame: &mut ratatui::Frame) {} +//! # fn should_quit() -> std::io::Result { Ok(false) } //! ``` //! +//! Note that when using [`init()`] and [`restore()`], it's important to use a separate function +//! for the main loop to ensure that [`restore()`] is always called, even if the `?` operator +//! causes early return from an error. +//! +//! For more detailed information about initialization options and when to use each function, see +//! the [`init` module] documentation. +//! +//! ### Manual Terminal and Backend Construction +//! +//! Before the convenience functions were introduced in version 0.28.1 ([`init()`]/[`restore()`]) +//! and 0.30.0 ([`run()`]), applications constructed [`Terminal`] and [`Backend`] instances +//! manually. This approach is still supported for applications that need fine-grained control over +//! initialization. See the [`Terminal`] and [`backend`] module documentation for details. +//! //! See the [`backend` module] and the [Backends] section of the [Ratatui Website] for more info on -//! the alternate screen and raw mode. +//! the alternate screen and raw mode. Learn more about different backend options in the [Backend +//! Comparison] guide. //! //! ## Drawing the UI //! @@ -150,9 +194,11 @@ //! method takes a closure that is called with a [`Frame`] instance. The [`Frame`] provides the size //! of the area to draw to and allows the app to render any [`Widget`] using the provided //! [`render_widget`] method. After this closure returns, a diff is performed and only the changes -//! are drawn to the terminal. See the [Widgets] section of the [Ratatui Website] for more info. +//! are drawn to the terminal. See the [Widgets] section of the [Ratatui Website] and the [Widget +//! Recipes] for more info on creating effective UIs. //! //! The closure passed to the [`Terminal::draw`] method should handle the rendering of a full frame. +//! For guidance on setting up the terminal before drawing, see the [`init` module] documentation. //! //! ```rust,no_run //! use ratatui::Frame; @@ -160,14 +206,14 @@ //! //! fn run(terminal: &mut ratatui::DefaultTerminal) -> std::io::Result<()> { //! loop { -//! terminal.draw(|frame| draw(frame))?; +//! terminal.draw(|frame| render(frame))?; //! if handle_events()? { //! break Ok(()); //! } //! } //! } //! -//! fn draw(frame: &mut Frame) { +//! fn render(frame: &mut Frame) { //! let text = Paragraph::new("Hello World!"); //! frame.render_widget(text, frame.area()); //! } @@ -178,7 +224,7 @@ //! //! Ratatui does not include any input handling. Instead event handling can be implemented by //! calling backend library methods directly. See the [Handling Events] section of the [Ratatui -//! Website] for more info. For example, if you are using [Crossterm], you can use the +//! Website] for conceptual information. For example, if you are using [Crossterm], you can use the //! [`crossterm::event`] module to handle events. //! //! ```rust,no_run @@ -198,12 +244,13 @@ //! } //! ``` //! -//! # Layout +//! ## Layout //! //! The library comes with a basic yet useful layout management object called [`Layout`] which //! allows you to split the available space into multiple areas and then render widgets in each //! area. This lets you describe a responsive terminal UI by nesting layouts. See the [Layout] -//! section of the [Ratatui Website] for more info. +//! section of the [Ratatui Website] for more info, and check out the [Layout Recipes] for +//! practical examples. //! //! ```rust,no_run //! use ratatui::Frame; @@ -235,7 +282,7 @@ //! Status Bar────────────────────────────────── //! ``` //! -//! # Text and styling +//! ## Text and styling //! //! The [`Text`], [`Line`] and [`Span`] types are the building blocks of the library and are used in //! many places. [`Text`] is a list of [`Line`]s and a [`Line`] is a list of [`Span`]s. A [`Span`] @@ -245,7 +292,7 @@ //! important one is [`Style`] which represents the foreground and background colors and the text //! attributes of a [`Span`]. The [`style` module] also provides a [`Stylize`] trait that allows //! short-hand syntax to apply a style to widgets and text. See the [Styling Text] section of the -//! [Ratatui Website] for more info. +//! [Ratatui Website] for more info, and explore the [Styling Recipes] for creative examples. //! //! ```rust,no_run //! use ratatui::Frame; @@ -288,14 +335,26 @@ //! //! [Ratatui Website]: https://ratatui.rs/ //! [Installation]: https://ratatui.rs/installation/ +//! [Tutorials]: https://ratatui.rs/tutorials/ +//! [Hello Ratatui tutorial]: https://ratatui.rs/tutorials/hello-ratatui/ +//! [Counter App]: https://ratatui.rs/tutorials/counter-app/ +//! [Recipes]: https://ratatui.rs/recipes/ +//! [FAQ]: https://ratatui.rs/faq/ +//! [Templates]: https://ratatui.rs/templates/ +//! [Cargo Generate]: https://cargo-generate.github.io/cargo-generate/ +//! [Showcase]: https://ratatui.rs/showcase/ //! [Rendering]: https://ratatui.rs/concepts/rendering/ //! [Application Patterns]: https://ratatui.rs/concepts/application-patterns/ //! [Hello World tutorial]: https://ratatui.rs/tutorials/hello-world/ //! [Backends]: https://ratatui.rs/concepts/backends/ -//! [Widgets]: https://ratatui.rs/how-to/widgets/ +//! [Backend Comparison]: https://ratatui.rs/concepts/backends/comparison/ +//! [Widgets]: https://ratatui.rs/recipes/widgets/ +//! [Widget Recipes]: https://ratatui.rs/recipes/widgets/ //! [Handling Events]: https://ratatui.rs/concepts/event-handling/ -//! [Layout]: https://ratatui.rs/how-to/layout/ -//! [Styling Text]: https://ratatui.rs/how-to/render/style-text/ +//! [Layout]: https://ratatui.rs/recipes/layout/ +//! [Layout Recipes]: https://ratatui.rs/recipes/layout/ +//! [Styling Text]: https://ratatui.rs/recipes/render/style-text/ +//! [Styling Recipes]: https://ratatui.rs/recipes/render/ //! [templates]: https://github.com/ratatui/templates/ //! [Examples]: https://github.com/ratatui/ratatui/tree/main/ratatui/examples/README.md //! [Report a bug]: https://github.com/ratatui/ratatui/issues/new?labels=bug&projects=&template=bug_report.md @@ -318,7 +377,9 @@ //! [`style` module]: style //! [`Stylize`]: style::Stylize //! [`Backend`]: backend::Backend +//! [`Terminal`]: Terminal //! [`backend` module]: backend +//! [`init` module]: mod@init //! [`crossterm::event`]: https://docs.rs/crossterm/latest/crossterm/event/index.html //! [Crate]: https://crates.io/crates/ratatui //! [Crossterm]: https://crates.io/crates/crossterm @@ -383,6 +444,7 @@ pub use ratatui_termion::termion; pub use ratatui_termwiz::termwiz; #[cfg(feature = "crossterm")] +#[doc(inline)] pub use crate::init::{ DefaultTerminal, init, init_with_options, restore, run, try_init, try_init_with_options, try_restore, @@ -404,4 +466,4 @@ pub use ratatui_core::{style, symbols, text}; pub mod widgets; pub use ratatui_widgets::border; #[cfg(feature = "crossterm")] -mod init; +pub mod init;