ratatui/
lib.rs

1#![no_std]
2// show the feature flags in the generated documentation
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/ratatui/ratatui/main/assets/logo.png",
6    html_favicon_url = "https://raw.githubusercontent.com/ratatui/ratatui/main/assets/favicon.ico"
7)]
8#![warn(missing_docs)]
9//! ![Release header](https://github.com/ratatui/ratatui/blob/b23480adfa9430697071c906c7ba4d4f9bd37a73/assets/release-header.png?raw=true)
10//!
11//! <div align="center">
12//!
13//! [![Crate Badge]][Crate] [![Docs Badge]][API Docs] [![CI Badge]][CI Workflow] [![Deps.rs
14//! Badge]][Deps.rs]<br> [![Codecov Badge]][Codecov] [![License Badge]](./LICENSE) [![Sponsors
15//! Badge]][GitHub Sponsors]<br> [![Discord Badge]][Discord Server] [![Matrix Badge]][Matrix]
16//! [![Forum Badge]][Forum]<br>
17//!
18//! [Ratatui Website] · [API Docs] · [Examples] · [Changelog] · [Breaking Changes]<br>
19//! [Contributing] · [Report a bug] · [Request a Feature] · [Create a Pull Request]
20//!
21//! </div>
22//!
23//! [Ratatui][Ratatui Website] is a crate for cooking up terminal user interfaces in Rust. It is a
24//! lightweight library that provides a set of [widgets](`widgets`) and utilities to build complex
25//! Rust TUIs. Ratatui was forked from the [tui-rs] crate in 2023 in order to continue its
26//! development.
27//!
28//! ## Quickstart
29//!
30//! Add `ratatui` and `crossterm` as dependencies to your cargo.toml:
31//!
32//! ```shell
33//! cargo add ratatui crossterm
34//! ```
35//!
36//! Then you can create a simple "Hello World" application:
37//!
38//! ```rust,no_run
39//! use crossterm::event;
40//!
41//! fn main() -> std::io::Result<()> {
42//!     ratatui::run(|mut terminal| {
43//!         loop {
44//!             terminal.draw(|frame| frame.render_widget("Hello World!", frame.area()))?;
45//!             if event::read()?.is_key_press() {
46//!                 break Ok(());
47//!             }
48//!         }
49//!     })
50//! }
51//! ```
52//!
53//! The full code for this example which contains a little more detail is in the [Examples]
54//! directory. For more guidance on different ways to structure your application see the
55//! [Application Patterns] and [Hello Ratatui tutorial] sections in the [Ratatui Website] and the
56//! various [Examples]. There are also several starter [Templates] available to help you get
57//! started quickly with common patterns.
58//!
59//! # Other documentation
60//!
61//! - [Ratatui Website] - explains the library's concepts and provides step-by-step tutorials
62//! - [Tutorials] - step-by-step guides including [Hello Ratatui tutorial] and [Counter App]
63//! - [Recipes] - practical how-to guides for common tasks and patterns
64//! - [FAQ] - frequently asked questions and answers
65//! - [Templates] - pre-built project templates using [Cargo Generate]
66//! - [Showcase] - a gallery of applications and widgets built with Ratatui
67//! - [Ratatui Forum][Forum] - a place to ask questions and discuss the library
68//! - [API Docs] - the full API documentation for the library on docs.rs.
69//! - [Examples] - a collection of examples that demonstrate how to use the library.
70//! - [Contributing] - Please read this if you are interested in contributing to the project.
71//! - [Changelog] - generated by [git-cliff] utilizing [Conventional Commits].
72//! - [Breaking Changes] - a list of breaking changes in the library.
73//!
74//! You can also watch the [FOSDEM 2024 talk] about Ratatui which gives a brief introduction to
75//! terminal user interfaces and showcases the features of Ratatui, along with a hello world demo.
76//!
77//! ## Getting Help
78//!
79//! If you need help or have questions, check out our [FAQ] for common questions and solutions.
80//! You can also join our community on [Discord][Discord Server], [Matrix], or post on our
81//! [Forum] for assistance and discussions.
82//!
83//! # Crate Organization
84//!
85//! Starting with Ratatui 0.30.0, the project was reorganized into a modular workspace to improve
86//! compilation times, API stability, and dependency management. Most applications should continue
87//! using this main `ratatui` crate, which re-exports everything for convenience:
88//!
89//! - **[`ratatui`](crate)**: Main crate with complete functionality (recommended for apps)
90//! - **[`ratatui-core`]**: Core traits and types for widget libraries
91//! - **[`ratatui-widgets`]**: Built-in widget implementations
92//! - **Backend crates**: [`ratatui-crossterm`], [`ratatui-termion`], [`ratatui-termwiz`]
93//! - **[`ratatui-macros`]**: Macros for simplifying the boilerplate
94//!
95//! **For application developers**: No changes needed - continue using `ratatui` as before.
96//!
97//! **For widget library authors**: Consider depending on [`ratatui-core`] instead of the full
98//! `ratatui` crate for better API stability and reduced dependencies.
99//!
100//! See [ARCHITECTURE.md] for detailed information about the crate organization and design
101//! decisions.
102//!
103//! # Writing Applications
104//!
105//! Ratatui is based on the principle of immediate rendering with intermediate buffers. This means
106//! that for each frame, your app must render all [`widgets`] that are supposed to be part of the
107//! UI. This is in contrast to the retained mode style of rendering where widgets are updated and
108//! then automatically redrawn on the next frame. See the [Rendering] section of the [Ratatui
109//! Website] for more info.
110//!
111//! Ratatui uses [Crossterm] by default as it works on most platforms. See the [Installation]
112//! section of the [Ratatui Website] for more details on how to use other backends ([Termion] /
113//! [Termwiz]).
114//!
115//! Every application built with `ratatui` needs to implement the following steps:
116//!
117//! - Initialize the terminal (see the [`init` module] for convenient initialization functions)
118//! - A main loop that:
119//!   - Draws the UI
120//!   - Handles input events
121//! - Restore the terminal state
122//!
123//! ## Initialize and restore the terminal
124//!
125//! The simplest way to initialize and run a terminal application is to use the [`run()`] function,
126//! which handles terminal initialization, restoration, and panic hooks automatically:
127//!
128//! ```rust,no_run
129//! fn main() -> std::io::Result<()> {
130//!     ratatui::run(|mut terminal| {
131//!         loop {
132//!             terminal.draw(render)?;
133//!             if should_quit()? {
134//!                 break Ok(());
135//!             }
136//!         }
137//!     })
138//! }
139//!
140//! fn render(frame: &mut ratatui::Frame) {
141//!     // ...
142//! }
143//!
144//! fn should_quit() -> std::io::Result<bool> {
145//!     // ...
146//! #   Ok(false)
147//! }
148//! ```
149//!
150//! For more control over initialization and restoration, you can use [`init()`] and [`restore()`]:
151//!
152//! ```rust,no_run
153//! fn main() -> std::io::Result<()> {
154//!     let mut terminal = ratatui::init();
155//!     let result = run_app(&mut terminal);
156//!     ratatui::restore();
157//!     result
158//! }
159//!
160//! fn run_app(terminal: &mut ratatui::DefaultTerminal) -> std::io::Result<()> {
161//!     loop {
162//!         terminal.draw(render)?;
163//!         if should_quit()? {
164//!             break Ok(());
165//!         }
166//!     }
167//! }
168//! # fn render(_frame: &mut ratatui::Frame) {}
169//! # fn should_quit() -> std::io::Result<bool> { Ok(false) }
170//! ```
171//!
172//! Note that when using [`init()`] and [`restore()`], it's important to use a separate function
173//! for the main loop to ensure that [`restore()`] is always called, even if the `?` operator
174//! causes early return from an error.
175//!
176//! For more detailed information about initialization options and when to use each function, see
177//! the [`init` module] documentation.
178//!
179//! ### Manual Terminal and Backend Construction
180//!
181//! Before the convenience functions were introduced in version 0.28.1 ([`init()`]/[`restore()`])
182//! and 0.30.0 ([`run()`]), applications constructed [`Terminal`] and [`Backend`] instances
183//! manually. This approach is still supported for applications that need fine-grained control over
184//! initialization. See the [`Terminal`] and [`backend`] module documentation for details.
185//!
186//! See the [`backend` module] and the [Backends] section of the [Ratatui Website] for more info on
187//! the alternate screen and raw mode. Learn more about different backend options in the [Backend
188//! Comparison] guide.
189//!
190//! ## Drawing the UI
191//!
192//! Drawing the UI is done by calling the [`Terminal::draw`] method on the terminal instance. This
193//! method takes a closure that is called with a [`Frame`] instance. The [`Frame`] provides the size
194//! of the area to draw to and allows the app to render any [`Widget`] using the provided
195//! [`render_widget`] method. After this closure returns, a diff is performed and only the changes
196//! are drawn to the terminal. See the [Widgets] section of the [Ratatui Website] and the [Widget
197//! Recipes] for more info on creating effective UIs.
198//!
199//! The closure passed to the [`Terminal::draw`] method should handle the rendering of a full frame.
200//! For guidance on setting up the terminal before drawing, see the [`init` module] documentation.
201//!
202//! ```rust,no_run
203//! use ratatui::Frame;
204//! use ratatui::widgets::Paragraph;
205//!
206//! fn run(terminal: &mut ratatui::DefaultTerminal) -> std::io::Result<()> {
207//!     loop {
208//!         terminal.draw(|frame| render(frame))?;
209//!         if handle_events()? {
210//!             break Ok(());
211//!         }
212//!     }
213//! }
214//!
215//! fn render(frame: &mut Frame) {
216//!     let text = Paragraph::new("Hello World!");
217//!     frame.render_widget(text, frame.area());
218//! }
219//! # fn handle_events() -> std::io::Result<bool> { Ok(false) }
220//! ```
221//!
222//! ## Handling events
223//!
224//! Ratatui does not include any input handling. Instead event handling can be implemented by
225//! calling backend library methods directly. See the [Handling Events] section of the [Ratatui
226//! Website] for conceptual information. For example, if you are using [Crossterm], you can use the
227//! [`crossterm::event`] module to handle events.
228//!
229//! ```rust,no_run
230//! use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind};
231//!
232//! fn handle_events() -> std::io::Result<bool> {
233//!     match event::read()? {
234//!         Event::Key(key) if key.kind == KeyEventKind::Press => match key.code {
235//!             KeyCode::Char('q') => return Ok(true),
236//!             // handle other key events
237//!             _ => {}
238//!         },
239//!         // handle other events
240//!         _ => {}
241//!     }
242//!     Ok(false)
243//! }
244//! ```
245//!
246//! ## Layout
247//!
248//! The library comes with a basic yet useful layout management object called [`Layout`] which
249//! allows you to split the available space into multiple areas and then render widgets in each
250//! area. This lets you describe a responsive terminal UI by nesting layouts. See the [Layout]
251//! section of the [Ratatui Website] for more info, and check out the [Layout Recipes] for
252//! practical examples.
253//!
254//! ```rust,no_run
255//! use ratatui::Frame;
256//! use ratatui::layout::{Constraint, Layout};
257//! use ratatui::widgets::Block;
258//!
259//! fn draw(frame: &mut Frame) {
260//!     use Constraint::{Fill, Length, Min};
261//!
262//!     let vertical = Layout::vertical([Length(1), Min(0), Length(1)]);
263//!     let [title_area, main_area, status_area] = vertical.areas(frame.area());
264//!     let horizontal = Layout::horizontal([Fill(1); 2]);
265//!     let [left_area, right_area] = horizontal.areas(main_area);
266//!
267//!     frame.render_widget(Block::bordered().title("Title Bar"), title_area);
268//!     frame.render_widget(Block::bordered().title("Status Bar"), status_area);
269//!     frame.render_widget(Block::bordered().title("Left"), left_area);
270//!     frame.render_widget(Block::bordered().title("Right"), right_area);
271//! }
272//! ```
273//!
274//! Running this example produces the following output:
275//!
276//! ```text
277//! Title Bar───────────────────────────────────
278//! ┌Left────────────────┐┌Right───────────────┐
279//! │                    ││                    │
280//! └────────────────────┘└────────────────────┘
281//! Status Bar──────────────────────────────────
282//! ```
283//!
284//! ## Text and styling
285//!
286//! The [`Text`], [`Line`] and [`Span`] types are the building blocks of the library and are used in
287//! many places. [`Text`] is a list of [`Line`]s and a [`Line`] is a list of [`Span`]s. A [`Span`]
288//! is a string with a specific style.
289//!
290//! The [`style` module] provides types that represent the various styling options. The most
291//! important one is [`Style`] which represents the foreground and background colors and the text
292//! attributes of a [`Span`]. The [`style` module] also provides a [`Stylize`] trait that allows
293//! short-hand syntax to apply a style to widgets and text. See the [Styling Text] section of the
294//! [Ratatui Website] for more info, and explore the [Styling Recipes] for creative examples.
295//!
296//! ```rust,no_run
297//! use ratatui::Frame;
298//! use ratatui::layout::{Constraint, Layout};
299//! use ratatui::style::{Color, Modifier, Style, Stylize};
300//! use ratatui::text::{Line, Span};
301//! use ratatui::widgets::{Block, Paragraph};
302//!
303//! fn draw(frame: &mut Frame) {
304//!     let areas = Layout::vertical([Constraint::Length(1); 4]).split(frame.area());
305//!
306//!     let line = Line::from(vec![
307//!         Span::raw("Hello "),
308//!         Span::styled(
309//!             "World",
310//!             Style::new()
311//!                 .fg(Color::Green)
312//!                 .bg(Color::White)
313//!                 .add_modifier(Modifier::BOLD),
314//!         ),
315//!         "!".red().on_light_yellow().italic(),
316//!     ]);
317//!     frame.render_widget(line, areas[0]);
318//!
319//!     // using the short-hand syntax and implicit conversions
320//!     let paragraph = Paragraph::new("Hello World!".red().on_white().bold());
321//!     frame.render_widget(paragraph, areas[1]);
322//!
323//!     // style the whole widget instead of just the text
324//!     let paragraph = Paragraph::new("Hello World!").style(Style::new().red().on_white());
325//!     frame.render_widget(paragraph, areas[2]);
326//!
327//!     // use the simpler short-hand syntax
328//!     let paragraph = Paragraph::new("Hello World!").blue().on_yellow();
329//!     frame.render_widget(paragraph, areas[3]);
330//! }
331//! ```
332#![cfg_attr(feature = "document-features", doc = "\n## Features")]
333#![cfg_attr(feature = "document-features", doc = document_features::document_features!())]
334//!
335//! [Ratatui Website]: https://ratatui.rs/
336//! [Installation]: https://ratatui.rs/installation/
337//! [Tutorials]: https://ratatui.rs/tutorials/
338//! [Hello Ratatui tutorial]: https://ratatui.rs/tutorials/hello-ratatui/
339//! [Counter App]: https://ratatui.rs/tutorials/counter-app/
340//! [Recipes]: https://ratatui.rs/recipes/
341//! [FAQ]: https://ratatui.rs/faq/
342//! [Templates]: https://ratatui.rs/templates/
343//! [Cargo Generate]: https://cargo-generate.github.io/cargo-generate/
344//! [Showcase]: https://ratatui.rs/showcase/
345//! [Rendering]: https://ratatui.rs/concepts/rendering/
346//! [Application Patterns]: https://ratatui.rs/concepts/application-patterns/
347//! [Hello World tutorial]: https://ratatui.rs/tutorials/hello-world/
348//! [Backends]: https://ratatui.rs/concepts/backends/
349//! [Backend Comparison]: https://ratatui.rs/concepts/backends/comparison/
350//! [Widgets]: https://ratatui.rs/recipes/widgets/
351//! [Widget Recipes]: https://ratatui.rs/recipes/widgets/
352//! [Handling Events]: https://ratatui.rs/concepts/event-handling/
353//! [Layout]: https://ratatui.rs/recipes/layout/
354//! [Layout Recipes]: https://ratatui.rs/recipes/layout/
355//! [Styling Text]: https://ratatui.rs/recipes/render/style-text/
356//! [Styling Recipes]: https://ratatui.rs/recipes/render/
357//! [templates]: https://github.com/ratatui/templates/
358//! [Examples]: https://github.com/ratatui/ratatui/tree/main/ratatui/examples/README.md
359//! [Report a bug]: https://github.com/ratatui/ratatui/issues/new?labels=bug&projects=&template=bug_report.md
360//! [Request a Feature]: https://github.com/ratatui/ratatui/issues/new?labels=enhancement&projects=&template=feature_request.md
361//! [Create a Pull Request]: https://github.com/ratatui/ratatui/compare
362//! [git-cliff]: https://git-cliff.org
363//! [Conventional Commits]: https://www.conventionalcommits.org
364//! [API Docs]: https://docs.rs/ratatui
365//! [Changelog]: https://github.com/ratatui/ratatui/blob/main/CHANGELOG.md
366//! [Contributing]: https://github.com/ratatui/ratatui/blob/main/CONTRIBUTING.md
367//! [Breaking Changes]: https://github.com/ratatui/ratatui/blob/main/BREAKING-CHANGES.md
368//! [FOSDEM 2024 talk]: https://www.youtube.com/watch?v=NU0q6NOLJ20
369//! [`render_widget`]: Frame::render_widget
370//! [`Widget`]: widgets::Widget
371//! [`Layout`]: layout::Layout
372//! [`Text`]: text::Text
373//! [`Line`]: text::Line
374//! [`Span`]: text::Span
375//! [`Style`]: style::Style
376//! [`style` module]: style
377//! [`Stylize`]: style::Stylize
378//! [`Backend`]: backend::Backend
379//! [`Terminal`]: Terminal
380//! [`backend` module]: backend
381//! [`init` module]: mod@init
382//! [`crossterm::event`]: https://docs.rs/crossterm/latest/crossterm/event/index.html
383//! [Crate]: https://crates.io/crates/ratatui
384//! [Crossterm]: https://crates.io/crates/crossterm
385//! [Termion]: https://crates.io/crates/termion
386//! [Termwiz]: https://crates.io/crates/termwiz
387//! [tui-rs]: https://crates.io/crates/tui
388//! [`ratatui-core`]: https://crates.io/crates/ratatui-core
389//! [`ratatui-widgets`]: https://crates.io/crates/ratatui-widgets
390//! [`ratatui-crossterm`]: https://crates.io/crates/ratatui-crossterm
391//! [`ratatui-termion`]: https://crates.io/crates/ratatui-termion
392//! [`ratatui-termwiz`]: https://crates.io/crates/ratatui-termwiz
393//! [`ratatui-macros`]: https://crates.io/crates/ratatui-macros
394//! [ARCHITECTURE.md]: https://github.com/ratatui/ratatui/blob/main/ARCHITECTURE.md
395//! [GitHub Sponsors]: https://github.com/sponsors/ratatui
396//! [Crate Badge]: https://img.shields.io/crates/v/ratatui?logo=rust&style=flat-square&logoColor=E05D44&color=E05D44
397//! [License Badge]: https://img.shields.io/crates/l/ratatui?style=flat-square&color=1370D3
398//! [CI Badge]: https://img.shields.io/github/actions/workflow/status/ratatui/ratatui/ci.yml?style=flat-square&logo=github
399//! [CI Workflow]: https://github.com/ratatui/ratatui/actions/workflows/ci.yml
400//! [Codecov Badge]: https://img.shields.io/codecov/c/github/ratatui/ratatui?logo=codecov&style=flat-square&token=BAQ8SOKEST&color=C43AC3&logoColor=C43AC3
401//! [Codecov]: https://app.codecov.io/gh/ratatui/ratatui
402//! [Deps.rs Badge]: https://deps.rs/repo/github/ratatui/ratatui/status.svg?style=flat-square
403//! [Deps.rs]: https://deps.rs/repo/github/ratatui/ratatui
404//! [Discord Badge]: https://img.shields.io/discord/1070692720437383208?label=discord&logo=discord&style=flat-square&color=1370D3&logoColor=1370D3
405//! [Discord Server]: https://discord.gg/pMCEU9hNEj
406//! [Docs Badge]: https://img.shields.io/docsrs/ratatui?logo=rust&style=flat-square&logoColor=E05D44
407//! [Matrix Badge]: https://img.shields.io/matrix/ratatui-general%3Amatrix.org?style=flat-square&logo=matrix&label=Matrix&color=C43AC3
408//! [Matrix]: https://matrix.to/#/#ratatui:matrix.org
409//! [Forum Badge]: https://img.shields.io/discourse/likes?server=https%3A%2F%2Fforum.ratatui.rs&style=flat-square&logo=discourse&label=forum&color=C43AC3
410//! [Forum]: https://forum.ratatui.rs
411//! [Sponsors Badge]: https://img.shields.io/github/sponsors/ratatui?logo=github&style=flat-square&color=1370D3
412//! [`ratatui-core`]: https://crates.io/crates/ratatui-core
413//! [`ratatui-widgets`]: https://crates.io/crates/ratatui-widgets
414//! [`ratatui-crossterm`]: https://crates.io/crates/ratatui-crossterm
415//! [`ratatui-termion`]: https://crates.io/crates/ratatui-termion
416//! [`ratatui-termwiz`]: https://crates.io/crates/ratatui-termwiz
417//! [`ratatui-macros`]: https://crates.io/crates/ratatui-macros
418//! [ARCHITECTURE.md]: https://github.com/ratatui/ratatui/blob/main/ARCHITECTURE.md
419
420#![warn(clippy::std_instead_of_core)]
421#![warn(clippy::std_instead_of_alloc)]
422#![warn(clippy::alloc_instead_of_core)]
423
424extern crate alloc;
425#[cfg(feature = "std")]
426extern crate std;
427
428/// re-export the `palette` crate so that users don't have to add it as a dependency
429#[cfg(feature = "palette")]
430pub use palette;
431pub use ratatui_core::terminal::{CompletedFrame, Frame, Terminal, TerminalOptions, Viewport};
432pub use ratatui_core::{buffer, layout};
433/// re-export the `crossterm` crate so that users don't have to add it as a dependency
434#[cfg(feature = "crossterm")]
435pub use ratatui_crossterm::crossterm;
436#[cfg(feature = "macros")]
437pub use ratatui_macros as macros;
438/// re-export the `termion` crate so that users don't have to add it as a dependency
439#[cfg(all(not(windows), feature = "termion"))]
440pub use ratatui_termion::termion;
441/// re-export the `termwiz` crate so that users don't have to add it as a dependency
442#[cfg(feature = "termwiz")]
443pub use ratatui_termwiz::termwiz;
444
445#[cfg(feature = "crossterm")]
446#[doc(inline)]
447pub use crate::init::{
448    DefaultTerminal, init, init_with_options, restore, run, try_init, try_init_with_options,
449    try_restore,
450};
451
452/// Re-exports for the backend implementations.
453pub mod backend {
454    pub use ratatui_core::backend::{Backend, ClearType, TestBackend, WindowSize};
455    #[cfg(feature = "crossterm")]
456    pub use ratatui_crossterm::{CrosstermBackend, FromCrossterm, IntoCrossterm};
457    #[cfg(all(not(windows), feature = "termion"))]
458    pub use ratatui_termion::{FromTermion, IntoTermion, TermionBackend};
459    #[cfg(feature = "termwiz")]
460    pub use ratatui_termwiz::{FromTermwiz, IntoTermwiz, TermwizBackend};
461}
462
463pub mod prelude;
464pub use ratatui_core::{style, symbols, text};
465pub mod widgets;
466pub use ratatui_widgets::border;
467#[cfg(feature = "crossterm")]
468pub mod init;