chore: move widgets into ratatui-widgets crate (#1474)

All the widgets now live in their own ratatui-widgets crate, but are re-exported in the main ratatui crate.
This makes it easier to use portions of the ratatui library and is part of the effort to modularize

Part of: #1388

---------

Co-authored-by: Orhun Parmaksız <orhun@archlinux.org>
Co-authored-by: Orhun Parmaksız <orhunparmaksiz@gmail.com>
This commit is contained in:
Josh McKinney 2024-11-15 19:42:07 -08:00 committed by GitHub
parent 9f90f7495f
commit e7085e3a3e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 773 additions and 511 deletions

22
Cargo.lock generated
View file

@ -2089,7 +2089,6 @@ name = "ratatui"
version = "0.29.0"
dependencies = [
"argh",
"bitflags 2.6.0",
"color-eyre",
"criterion",
"crossterm",
@ -2106,6 +2105,7 @@ dependencies = [
"rand 0.8.5",
"rand_chacha 0.3.1",
"ratatui-core",
"ratatui-widgets",
"rstest",
"serde",
"serde_json",
@ -2117,7 +2117,6 @@ dependencies = [
"tracing",
"tracing-appender",
"tracing-subscriber",
"unicode-segmentation",
"unicode-width",
]
@ -2144,6 +2143,25 @@ dependencies = [
"unicode-width",
]
[[package]]
name = "ratatui-widgets"
version = "0.3.0"
dependencies = [
"bitflags 2.6.0",
"indoc",
"instability",
"itertools 0.13.0",
"pretty_assertions",
"ratatui",
"ratatui-core",
"rstest",
"serde",
"strum",
"time",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "rayon"
version = "1.10.0"

View file

@ -1,7 +1,7 @@
[workspace]
resolver = "2"
members = ["ratatui", "ratatui-core", "xtask"]
default-members = ["ratatui", "ratatui-core"]
members = ["ratatui", "ratatui-core", "ratatui-widgets", "xtask"]
default-members = ["ratatui", "ratatui-core", "ratatui-widgets"]
[workspace.package]
authors = ["Florian Dehau <work@fdehau.com>", "The Ratatui Developers"]
@ -29,7 +29,9 @@ indoc = "2.0.5"
instability = "0.3.1"
itertools = "0.13.0"
pretty_assertions = "1.4.1"
ratatui = { path = "ratatui" }
ratatui-core = { path = "ratatui-core" }
ratatui-widgets = { path = "ratatui-widgets" }
rstest = "0.23.0"
serde = { version = "1.0.214", features = ["derive"] }
strum = { version = "0.26.3", features = ["derive"] }

View file

@ -27,7 +27,8 @@ cargo add ratatui-core
## Contributing
We welcome contributions from the community! Please see our [CONTRIBUTING](../CONTRIBUTING.md) guide for more details on how to get involved.
We welcome contributions from the community! Please see our [CONTRIBUTING](../CONTRIBUTING.md) guide
for more details on how to get involved.
## License

104
ratatui-widgets/Cargo.toml Normal file
View file

@ -0,0 +1,104 @@
[package]
name = "ratatui-widgets"
description = "A collection of Ratatui widgets for building terminal user interfaces."
version = "0.3.0"
authors.workspace = true
documentation.workspace = true
repository.workspace = true
homepage.workspace = true
keywords.workspace = true
categories.workspace = true
license.workspace = true
exclude.workspace = true
edition.workspace = true
rust-version.workspace = true
[features]
## enables serialization and deserialization of style and color types using the [`serde`] crate.
## This is useful if you want to save themes to a file.
serde = ["dep:serde", "ratatui-core/serde"]
#! Widgets that add dependencies are gated behind feature flags to prevent unused transitive
#! dependencies. The available features are:
## enables all widgets.
all-widgets = ["calendar"]
## enables the [`calendar`](widgets::calendar) widget module and adds a dependency on [`time`].
calendar = ["dep:time"]
## Enable all unstable features.
unstable = ["unstable-rendered-line-info", "unstable-widget-ref"]
## enables the [`WidgetRef`] and [`StatefulWidgetRef`] traits which are experimental and may change
## in the future.
unstable-widget-ref = ["ratatui-core/unstable-widget-ref"]
## Enables the [`Paragraph::line_count`](widgets::Paragraph::line_count)
## [`Paragraph::line_width`](widgets::Paragraph::line_width) methods
## which are experimental and may change in the future.
## See [Issue 293](https://github.com/ratatui/ratatui/issues/293) for more details.
unstable-rendered-line-info = []
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
[dependencies]
bitflags.workspace = true
itertools.workspace = true
indoc.workspace = true
instability.workspace = true
ratatui-core = { workspace = true }
strum.workspace = true
time = { version = "0.3.11", optional = true, features = ["local-offset"] }
unicode-segmentation.workspace = true
unicode-width.workspace = true
serde = { workspace = true, optional = true }
[dev-dependencies]
rstest.workspace = true
pretty_assertions.workspace = true
ratatui.workspace = true
[lints.rust]
unsafe_code = "forbid"
[lints.clippy]
cargo = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
cast_possible_truncation = "allow"
cast_possible_wrap = "allow"
cast_precision_loss = "allow"
cast_sign_loss = "allow"
missing_errors_doc = "allow"
missing_panics_doc = "allow"
module_name_repetitions = "allow"
must_use_candidate = "allow"
# we often split up a module into multiple files with the main type in a file named after the
# module, so we want to allow this pattern
module_inception = "allow"
# nursery or restricted
as_underscore = "warn"
deref_by_slicing = "warn"
else_if_without_else = "warn"
empty_line_after_doc_comments = "warn"
equatable_if_let = "warn"
fn_to_numeric_cast_any = "warn"
format_push_string = "warn"
map_err_ignore = "warn"
missing_const_for_fn = "warn"
mixed_read_write_in_expression = "warn"
mod_module_files = "warn"
needless_pass_by_ref_mut = "warn"
needless_raw_strings = "warn"
or_fun_call = "warn"
redundant_type_annotations = "warn"
rest_pat_in_fully_bound_structs = "warn"
string_lit_chars_any = "warn"
string_slice = "warn"
string_to_string = "warn"
unnecessary_self_imports = "warn"
use_self = "warn"

76
ratatui-widgets/README.md Normal file
View file

@ -0,0 +1,76 @@
# Ratatui-widgets
<!-- DO NOT EDIT THIS FILE DIRECTLY, EDIT lib.rs AND THEN RUN cargo rdme to update this file -->
<!-- cargo-rdme start -->
Ratatui-widgets contains all the widgets that were previously part of the Ratatui crate. It is
meant to be used in conjunction with the [Ratatui] crate, which provides the core functionality
for building terminal user interfaces.
[Ratatui]: https://crates.io/crates/ratatui
Most applications shouldn't need to depend directly on Ratatui-widgets, as all the Ratatui crate
re-exports all the widgets from this crate. However, if you are building a widget library that
internally uses Ratatui widgets, or if you prefer finer grained dependencies, you may want to
depend on this crate rather than transitively through the Ratatui crate.
Previously, a crate named `Ratatui-widgets` was published with some formative ideas about an
eventual Ratatui framework. That crate is now move to [tui-framework-experiment], pending a new
name.
[tui-framework-experiment]: https://crates.io/crates/tui-framework-experiment
## Installation
Run the following command to add this crate to your project:
```sh
cargo add ratatui-widgets
```
## Available Widgets
- [`BarChart`]: displays multiple datasets as bars with optional grouping.
- [`Block`]: a basic widget that draws a block with optional borders, titles, and styles.
- [`calendar::Monthly`]: displays a single month.
- [`Canvas`]: draws arbitrary shapes using drawing characters.
- [`Chart`]: displays multiple datasets as lines or scatter graphs.
- [`Clear`]: clears the area it occupies. Useful to render over previously drawn widgets.
- [`Gauge`]: displays progress percentage using block characters.
- [`LineGauge`]: displays progress as a line.
- [`List`]: displays a list of items and allows selection.
- [`RatatuiLogo`]: displays the Ratatui logo.
- [`Paragraph`]: displays a paragraph of optionally styled and wrapped text.
- [`Scrollbar`]: displays a scrollbar.
- [`Sparkline`]: displays a single dataset as a sparkline.
- [`Table`]: displays multiple rows and columns in a grid and allows selection.
- [`Tabs`]: displays a tab bar and allows selection.
[`BarChart`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/barchart/struct.BarChart.html
[`Block`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/block/struct.Block.html
[`calendar::Monthly`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/calendar/struct.Monthly.html
[`Canvas`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/canvas/struct.Canvas.html
[`Chart`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/chart/struct.Chart.html
[`Clear`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/clear/struct.Clear.html
[`Gauge`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/gauge/struct.Gauge.html
[`LineGauge`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/gauge/struct.LineGauge.html
[`List`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/list/struct.List.html
[`RatatuiLogo`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/logo/struct.RatatuiLogo.html
[`Paragraph`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/paragraph/struct.Paragraph.html
[`Scrollbar`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/scrollbar/struct.Scrollbar.html
[`Sparkline`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/sparkline/struct.Sparkline.html
[`Table`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/table/struct.Table.html
[`Tabs`]: https://docs.rs/ratatui-widgets/latest/ratatui_widgets/tabs/struct.Tabs.html
All these widgets are re-exported directly under `ratatui::widgets` in the Ratatui crate.
## Contributing
Contributions are welcome! Please open an issue or submit a pull request on GitHub. For more
details on contributing, please see the [CONTRIBUTING](CONTRIBUTING.md) document.
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
<!-- cargo-rdme end -->

View file

@ -1,18 +1,20 @@
use crate::{
//! The [`BarChart`] widget and its related types (e.g. [`Bar`], [`BarGroup`]).
use ratatui_core::{
buffer::Buffer,
layout::{Direction, Rect},
style::{Style, Styled},
symbols::{self},
text::Line,
widgets::{block::BlockExt, Block, Widget, WidgetRef},
widgets::{Widget, WidgetRef},
};
pub use self::{bar::Bar, bar_group::BarGroup};
use crate::block::{Block, BlockExt};
mod bar;
mod bar_group;
pub use bar::Bar;
pub use bar_group::BarGroup;
/// A chart showing values as [bars](Bar).
///
/// Here is a possible `BarChart` output.
@ -189,7 +191,7 @@ impl<'a> BarChart<'a> {
/// It is also possible to set individually the style of each [`Bar`].
/// In this case the default style will be patched by the individual style
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn bar_style<S: Into<Style>>(mut self, style: S) -> Self {
self.bar_style = style.into();
@ -198,8 +200,8 @@ impl<'a> BarChart<'a> {
/// Set the width of the displayed bars.
///
/// For [`Horizontal`](crate::layout::Direction::Horizontal) bars this becomes the height of
/// the bar.
/// For [`Horizontal`](ratatui_core::layout::Direction::Horizontal) bars this becomes the height
/// of the bar.
///
/// If not set, this defaults to `1`.
/// The bar label also uses this value as its width.
@ -234,9 +236,9 @@ impl<'a> BarChart<'a> {
self
}
/// The [`bar::Set`](crate::symbols::bar::Set) to use for displaying the bars.
/// The [`bar::Set`](ratatui_core::symbols::bar::Set) to use for displaying the bars.
///
/// If not set, the default is [`bar::NINE_LEVELS`](crate::symbols::bar::NINE_LEVELS).
/// If not set, the default is [`bar::NINE_LEVELS`](ratatui_core::symbols::bar::NINE_LEVELS).
#[must_use = "method moves the value of self and returns the modified value"]
pub const fn bar_set(mut self, bar_set: symbols::bar::Set) -> Self {
self.bar_set = bar_set;
@ -255,7 +257,7 @@ impl<'a> BarChart<'a> {
///
/// [`Bar::value_style`] to set the value style individually.
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn value_style<S: Into<Style>>(mut self, style: S) -> Self {
self.value_style = style.into();
@ -274,7 +276,7 @@ impl<'a> BarChart<'a> {
///
/// [`Bar::label`] to set the label style individually.
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn label_style<S: Into<Style>>(mut self, style: S) -> Self {
self.label_style = style.into();
@ -295,7 +297,7 @@ impl<'a> BarChart<'a> {
///
/// The style will be applied to everything that isn't styled (borders, bars, labels, ...).
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -304,7 +306,7 @@ impl<'a> BarChart<'a> {
/// Set the direction of the bars.
///
/// [`Vertical`](crate::layout::Direction::Vertical) bars are the default.
/// [`Vertical`](ratatui_core::layout::Direction::Vertical) bars are the default.
///
/// # Examples
///
@ -634,15 +636,15 @@ impl<'a> Styled for BarChart<'a> {
#[cfg(test)]
mod tests {
use itertools::iproduct;
use super::*;
use crate::{
use ratatui_core::{
layout::Alignment,
style::{Color, Modifier, Stylize},
text::Span,
widgets::BorderType,
};
use super::*;
use crate::borders::BorderType;
#[test]
fn default() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));

View file

@ -1,7 +1,7 @@
use ratatui_core::{buffer::Buffer, layout::Rect, style::Style, text::Line, widgets::Widget};
use unicode_width::UnicodeWidthStr;
use crate::{buffer::Buffer, layout::Rect, style::Style, text::Line, widgets::Widget};
/// A bar to be shown by the [`BarChart`](crate::widgets::BarChart) widget.
/// A bar to be shown by the [`BarChart`](crate::barchart::BarChart) widget.
///
/// Here is an explanation of a `Bar`'s components.
/// ```plain
@ -59,11 +59,11 @@ impl<'a> Bar<'a> {
/// Set the label of the bar.
///
/// For [`Vertical`](crate::layout::Direction::Vertical) bars,
/// For [`Vertical`](ratatui_core::layout::Direction::Vertical) bars,
/// display the label **under** the bar.
/// For [`Horizontal`](crate::layout::Direction::Horizontal) bars,
/// For [`Horizontal`](ratatui_core::layout::Direction::Horizontal) bars,
/// display the label **in** the bar.
/// See [`BarChart::direction`](crate::widgets::BarChart::direction) to set the direction.
/// See [`BarChart::direction`](crate::barchart::BarChart::direction) to set the direction.
#[must_use = "method moves the value of self and returns the modified value"]
pub fn label(mut self, label: Line<'a>) -> Self {
self.label = Some(label);
@ -77,7 +77,7 @@ impl<'a> Bar<'a> {
///
/// This will apply to every non-styled element. It can be seen and used as a default value.
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -93,7 +93,7 @@ impl<'a> Bar<'a> {
///
/// [`Bar::value`] to set the value.
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn value_style<S: Into<Style>>(mut self, style: S) -> Self {
self.value_style = style.into();

View file

@ -1,11 +1,13 @@
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::{Alignment, Rect},
style::Style,
text::Line,
widgets::{barchart::Bar, Widget},
widgets::Widget,
};
use crate::barchart::Bar;
/// A group of bars to be shown by the Barchart.
///
/// # Examples

View file

@ -6,24 +6,25 @@
//! [title](Block::title) and [padding](Block::padding).
use itertools::Itertools;
use strum::{Display, EnumString};
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::{Alignment, Rect},
style::{Style, Styled},
symbols::border,
text::Line,
widgets::{Borders, Widget, WidgetRef},
widgets::{Widget, WidgetRef},
};
pub use self::{
padding::Padding,
title::{Position, Title},
};
use crate::borders::{BorderType, Borders};
mod padding;
pub mod title;
pub use padding::Padding;
pub use title::{Position, Title};
/// Base widget to be used to display a box border around all [upper level ones](crate::widgets).
/// Base widget to be used to display a box border around all other built-in widgets.
///
/// The borders can be configured with [`Block::borders`] and others. A block can have multiple
/// [`Title`] using [`Block::title`]. It can also be [styled](Block::style) and
@ -132,79 +133,6 @@ pub struct Block<'a> {
padding: Padding,
}
/// The type of border of a [`Block`].
///
/// See the [`borders`](Block::borders) method of `Block` to configure its borders.
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum BorderType {
/// A plain, simple border.
///
/// This is the default
///
/// # Example
///
/// ```plain
/// ┌───────┐
/// │ │
/// └───────┘
/// ```
#[default]
Plain,
/// A plain border with rounded corners.
///
/// # Example
///
/// ```plain
/// ╭───────╮
/// │ │
/// ╰───────╯
/// ```
Rounded,
/// A doubled border.
///
/// Note this uses one character that draws two lines.
///
/// # Example
///
/// ```plain
/// ╔═══════╗
/// ║ ║
/// ╚═══════╝
/// ```
Double,
/// A thick border.
///
/// # Example
///
/// ```plain
/// ┏━━━━━━━┓
/// ┃ ┃
/// ┗━━━━━━━┛
/// ```
Thick,
/// A border with a single line on the inside of a half block.
///
/// # Example
///
/// ```plain
/// ▗▄▄▄▄▄▄▄▖
/// ▐ ▌
/// ▐ ▌
/// ▝▀▀▀▀▀▀▀▘
QuadrantInside,
/// A border with a single line on the outside of a half block.
///
/// # Example
///
/// ```plain
/// ▛▀▀▀▀▀▀▀▜
/// ▌ ▐
/// ▌ ▐
/// ▙▄▄▄▄▄▄▄▟
QuadrantOutside,
}
impl<'a> Block<'a> {
/// Creates a new block with no [`Borders`] or [`Padding`].
pub const fn new() -> Self {
@ -244,8 +172,8 @@ impl<'a> Block<'a> {
/// space is calculated based on the full width of the block, rather than the leftover width.
///
/// You can provide any type that can be converted into [`Title`] including: strings, string
/// slices (`&str`), borrowed strings (`Cow<str>`), [spans](crate::text::Span), or vectors of
/// [spans](crate::text::Span) (`Vec<Span>`).
/// slices (`&str`), borrowed strings (`Cow<str>`), [spans](ratatui_core::text::Span), or
/// vectors of [spans](ratatui_core::text::Span) (`Vec<Span>`).
///
/// By default, the titles will avoid being rendered in the corners of the block but will align
/// against the left or right edge of the block if there is no border on that edge. The
@ -319,8 +247,8 @@ impl<'a> Block<'a> {
/// Adds a title to the top of the block.
///
/// You can provide any type that can be converted into [`Line`] including: strings, string
/// slices (`&str`), borrowed strings (`Cow<str>`), [spans](crate::text::Span), or vectors of
/// [spans](crate::text::Span) (`Vec<Span>`).
/// slices (`&str`), borrowed strings (`Cow<str>`), [spans](ratatui_core::text::Span), or
/// vectors of [spans](ratatui_core::text::Span) (`Vec<Span>`).
///
/// # Example
///
@ -348,8 +276,8 @@ impl<'a> Block<'a> {
/// Adds a title to the bottom of the block.
///
/// You can provide any type that can be converted into [`Line`] including: strings, string
/// slices (`&str`), borrowed strings (`Cow<str>`), [spans](crate::text::Span), or vectors of
/// [spans](crate::text::Span) (`Vec<Span>`).
/// slices (`&str`), borrowed strings (`Cow<str>`), [spans](ratatui_core::text::Span), or
/// vectors of [spans](ratatui_core::text::Span) (`Vec<Span>`).
///
/// # Example
///
@ -385,7 +313,7 @@ impl<'a> Block<'a> {
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn title_style<S: Into<Style>>(mut self, style: S) -> Self {
self.titles_style = style.into();
@ -461,7 +389,7 @@ impl<'a> Block<'a> {
/// Block::bordered().border_style(Style::new().blue());
/// ```
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn border_style<S: Into<Style>>(mut self, style: S) -> Self {
self.border_style = style.into();
@ -504,8 +432,8 @@ impl<'a> Block<'a> {
/// .style(Style::new().white().not_bold()); // will be white, and italic
/// ```
///
/// [`Paragraph`]: crate::widgets::Paragraph
/// [`Color`]: crate::style::Color
/// [`Paragraph`]: crate::paragraph::Paragraph
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -556,7 +484,7 @@ impl<'a> Block<'a> {
self
}
/// Sets the symbols used to display the border as a [`crate::symbols::border::Set`].
/// Sets the symbols used to display the border as a [`ratatui_core::symbols::border::Set`].
///
/// Setting this overwrites any [`border_type`](Block::border_type) that was set.
///
@ -673,25 +601,6 @@ impl<'a> Block<'a> {
}
}
impl BorderType {
/// Convert this `BorderType` into the corresponding [`Set`](border::Set) of border symbols.
pub const fn border_symbols(border_type: Self) -> border::Set {
match border_type {
Self::Plain => border::PLAIN,
Self::Rounded => border::ROUNDED,
Self::Double => border::DOUBLE,
Self::Thick => border::THICK,
Self::QuadrantInside => border::QUADRANT_INSIDE,
Self::QuadrantOutside => border::QUADRANT_OUTSIDE,
}
}
/// Convert this `BorderType` into the corresponding [`Set`](border::Set) of border symbols.
pub const fn to_border_set(self) -> border::Set {
Self::border_symbols(self)
}
}
impl Widget for Block<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
self.render_ref(area, buf);
@ -1000,11 +909,11 @@ impl<'a> Styled for Block<'a> {
#[cfg(test)]
mod tests {
use ratatui_core::style::{Color, Modifier, Stylize};
use rstest::rstest;
use strum::ParseError;
use super::*;
use crate::style::{Color, Modifier, Stylize};
#[test]
fn create_with_all_borders() {

View file

@ -19,8 +19,8 @@
/// Padding::symmetric(5, 6);
/// ```
///
/// [`Block`]: crate::widgets::Block
/// [`padding`]: crate::widgets::Block::padding
/// [`Block`]: crate::block::Block
/// [`padding`]: crate::block::Block::padding
/// [CSS padding]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Padding {

View file

@ -1,11 +1,10 @@
//! This module holds the [`Title`] element and its related configuration types.
//! A title is a piece of [`Block`](crate::widgets::Block) configuration.
//! A title is a piece of [`Block`](crate::block::Block) configuration.
use ratatui_core::{layout::Alignment, text::Line};
use strum::{Display, EnumString};
use crate::{layout::Alignment, text::Line};
/// A [`Block`](crate::widgets::Block) title.
/// A [`Block`](crate::block::Block) title.
///
/// It can be aligned (see [`Alignment`]) and positioned (see [`Position`]).
///
@ -17,8 +16,8 @@ use crate::{layout::Alignment, text::Line};
/// <https://github.com/ratatui/ratatui/issues/738>.
///
/// Use [`Line`] instead, when the position is not defined as part of the title. When a specific
/// position is needed, use [`Block::title_top`](crate::widgets::Block::title_top) or
/// [`Block::title_bottom`](crate::widgets::Block::title_bottom) instead.
/// position is needed, use [`Block::title_top`](crate::block::Block::title_top) or
/// [`Block::title_bottom`](crate::block::Block::title_bottom) instead.
///
/// # Example
///
@ -29,14 +28,14 @@ use crate::{layout::Alignment, text::Line};
/// Title::from("Title");
/// ```
///
/// Blue title on a white background (via [`Stylize`](crate::style::Stylize) trait).
/// Blue title on a white background (via [`Stylize`](ratatui_core::style::Stylize) trait).
/// ```
/// use ratatui::{style::Stylize, widgets::block::Title};
///
/// Title::from("Title".blue().on_white());
/// ```
///
/// Title with multiple styles (see [`Line`] and [`Stylize`](crate::style::Stylize)).
/// Title with multiple styles (see [`Line`] and [`Stylize`](ratatui_core::style::Stylize)).
/// ```
/// use ratatui::{style::Stylize, text::Line, widgets::block::Title};
///
@ -64,19 +63,19 @@ pub struct Title<'a> {
/// Title alignment
///
/// If [`None`], defaults to the alignment defined with
/// [`Block::title_alignment`](crate::widgets::Block::title_alignment) in the associated
/// [`Block`](crate::widgets::Block).
/// [`Block::title_alignment`](crate::block::Block::title_alignment) in the associated
/// [`Block`](crate::block::Block).
pub alignment: Option<Alignment>,
/// Title position
///
/// If [`None`], defaults to the position defined with
/// [`Block::title_position`](crate::widgets::Block::title_position) in the associated
/// [`Block`](crate::widgets::Block).
/// [`Block::title_position`](crate::block::Block::title_position) in the associated
/// [`Block`](crate::block::Block).
pub position: Option<Position>,
}
/// Defines the [title](crate::widgets::block::Title) position.
/// Defines the [title](crate::block::Title) position.
///
/// The title can be positioned on top or at the bottom of the block.
/// Defaults to [`Position::Top`].

View file

@ -1,6 +1,9 @@
//! Border related types ([`Borders`], [`BorderType`]) and a macro to create borders ([`border`]).
use std::fmt;
use bitflags::bitflags;
use ratatui_core::symbols::border;
use strum::{Display, EnumString};
bitflags! {
/// Bitflags that can be composed to set the visible borders essentially on the block widget.
@ -21,6 +24,98 @@ bitflags! {
}
}
/// The type of border of a [`Block`](crate::block::Block).
///
/// See the [`borders`](crate::block::Block::borders) method of `Block` to configure its borders.
#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)]
pub enum BorderType {
/// A plain, simple border.
///
/// This is the default
///
/// # Example
///
/// ```plain
/// ┌───────┐
/// │ │
/// └───────┘
/// ```
#[default]
Plain,
/// A plain border with rounded corners.
///
/// # Example
///
/// ```plain
/// ╭───────╮
/// │ │
/// ╰───────╯
/// ```
Rounded,
/// A doubled border.
///
/// Note this uses one character that draws two lines.
///
/// # Example
///
/// ```plain
/// ╔═══════╗
/// ║ ║
/// ╚═══════╝
/// ```
Double,
/// A thick border.
///
/// # Example
///
/// ```plain
/// ┏━━━━━━━┓
/// ┃ ┃
/// ┗━━━━━━━┛
/// ```
Thick,
/// A border with a single line on the inside of a half block.
///
/// # Example
///
/// ```plain
/// ▗▄▄▄▄▄▄▄▖
/// ▐ ▌
/// ▐ ▌
/// ▝▀▀▀▀▀▀▀▘
QuadrantInside,
/// A border with a single line on the outside of a half block.
///
/// # Example
///
/// ```plain
/// ▛▀▀▀▀▀▀▀▜
/// ▌ ▐
/// ▌ ▐
/// ▙▄▄▄▄▄▄▄▟
QuadrantOutside,
}
impl BorderType {
/// Convert this `BorderType` into the corresponding [`Set`](border::Set) of border symbols.
pub const fn border_symbols(border_type: Self) -> border::Set {
match border_type {
Self::Plain => border::PLAIN,
Self::Rounded => border::ROUNDED,
Self::Double => border::DOUBLE,
Self::Thick => border::THICK,
Self::QuadrantInside => border::QUADRANT_INSIDE,
Self::QuadrantOutside => border::QUADRANT_OUTSIDE,
}
}
/// Convert this `BorderType` into the corresponding [`Set`](border::Set) of border symbols.
pub const fn to_border_set(self) -> border::Set {
Self::border_symbols(self)
}
}
/// Implement the `Debug` trait for the `Borders` bitflags. This is a manual implementation to
/// display the flags in a more readable way. The default implementation would display the
/// flags as 'Border(0x0)' for `Borders::NONE` for example.
@ -55,7 +150,7 @@ impl fmt::Debug for Borders {
/// and RIGHT.
///
/// When used with NONE you should consider omitting this completely. For ALL you should consider
/// [`Block::bordered()`](crate::widgets::Block::bordered) instead.
/// [`Block::bordered()`](crate::block::Block::bordered) instead.
///
/// ## Examples
///
@ -87,7 +182,6 @@ impl fmt::Debug for Borders {
/// assert_eq!(border!(ALL), Borders::ALL);
/// assert_eq!(border!(), Borders::NONE);
/// ```
#[cfg(feature = "macros")]
#[macro_export]
macro_rules! border {
() => {
@ -124,11 +218,6 @@ mod tests {
"TOP | BOTTOM"
);
}
}
#[cfg(all(test, feature = "macros"))]
mod macro_tests {
use super::*;
#[test]
fn can_be_const() {

View file

@ -10,15 +10,16 @@
//! [`Monthly`] has several controls for what should be displayed
use std::collections::HashMap;
use time::{Date, Duration, OffsetDateTime};
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::{Alignment, Constraint, Layout, Rect},
style::Style,
text::{Line, Span},
widgets::{block::BlockExt, Block, Widget, WidgetRef},
widgets::{Widget, WidgetRef},
};
use time::{Date, Duration, OffsetDateTime};
use crate::block::{Block, BlockExt};
/// Display a month calendar for the month containing `display_date`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
@ -53,7 +54,7 @@ impl<'a, DS: DateStyler> Monthly<'a, DS> {
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn show_surrounding<S: Into<Style>>(mut self, style: S) -> Self {
self.show_surrounding = Some(style.into());
@ -65,7 +66,7 @@ impl<'a, DS: DateStyler> Monthly<'a, DS> {
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn show_weekdays_header<S: Into<Style>>(mut self, style: S) -> Self {
self.show_weekday = Some(style.into());
@ -77,7 +78,7 @@ impl<'a, DS: DateStyler> Monthly<'a, DS> {
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn show_month_header<S: Into<Style>>(mut self, style: S) -> Self {
self.show_month = Some(style.into());
@ -89,7 +90,7 @@ impl<'a, DS: DateStyler> Monthly<'a, DS> {
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn default_style<S: Into<Style>>(mut self, style: S) -> Self {
self.default_style = style.into();
@ -216,7 +217,7 @@ impl CalendarEventStore {
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
pub fn today<S: Into<Style>>(style: S) -> Self {
let mut res = Self::default();
res.add(
@ -233,7 +234,7 @@ impl CalendarEventStore {
/// `style` accepts any type that is convertible to [`Style`] (e.g. [`Style`], [`Color`], or
/// your own type that implements [`Into<Style>`]).
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
pub fn add<S: Into<Style>>(&mut self, date: Date, style: S) {
// to simplify style nonsense, last write wins
let _ = self.0.insert(date, style.into());
@ -265,10 +266,10 @@ impl Default for CalendarEventStore {
#[cfg(test)]
mod tests {
use ratatui_core::style::Color;
use time::Month;
use super::*;
use crate::style::Color;
#[test]
fn event_store() {

View file

@ -12,16 +12,18 @@
//! - [`Rectangle`]: A basic rectangle
//!
//! You can also implement your own custom [`Shape`]s.
mod circle;
mod line;
mod map;
mod points;
mod rectangle;
mod world;
use std::{fmt, iter::zip};
use itertools::Itertools;
use ratatui_core::{
buffer::Buffer,
layout::Rect,
style::{Color, Style},
symbols::{self, Marker},
text::Line as TextLine,
widgets::{Widget, WidgetRef},
};
pub use self::{
circle::Circle,
@ -30,14 +32,14 @@ pub use self::{
points::Points,
rectangle::Rectangle,
};
use crate::{
buffer::Buffer,
layout::Rect,
style::{Color, Style},
symbols::{self, Marker},
text::Line as TextLine,
widgets::{block::BlockExt, Block, Widget, WidgetRef},
};
use crate::block::{Block, BlockExt};
mod circle;
mod line;
mod map;
mod points;
mod rectangle;
mod world;
/// Something that can be drawn on a [`Canvas`].
///
@ -437,9 +439,7 @@ impl<'a, 'b> From<&'a mut Context<'b>> for Painter<'a, 'b> {
/// Holds the state of the [`Canvas`] when painting to it.
///
/// This is used by the [`Canvas`] widget to draw shapes on the grid. It can be useful to think of
/// this as similar to the [`Frame`] struct that is used to draw widgets on the terminal.
///
/// [`Frame`]: crate::Frame
/// this as similar to the `Frame` struct that is used to draw widgets on the terminal.
#[derive(Debug)]
pub struct Context<'a> {
x_bounds: [f64; 2],
@ -528,7 +528,7 @@ impl<'a> Context<'a> {
/// Note that the text is always printed on top of the canvas and is **not** affected by the
/// layers.
///
/// [`Text`]: crate::text::Text
/// [`Text`]: ratatui_core::text::Text
pub fn print<T>(&mut self, x: f64, y: f64, line: T)
where
T: Into<TextLine<'a>>,
@ -709,10 +709,10 @@ where
/// cell. This allows for more flexibility than the `BrailleGrid` which only supports a single
/// foreground color for each 2x4 dots cell.
///
/// [`Braille`]: crate::symbols::Marker::Braille
/// [`HalfBlock`]: crate::symbols::Marker::HalfBlock
/// [`Dot`]: crate::symbols::Marker::Dot
/// [`Block`]: crate::symbols::Marker::Block
/// [`Braille`]: ratatui_core::symbols::Marker::Braille
/// [`HalfBlock`]: ratatui_core::symbols::Marker::HalfBlock
/// [`Dot`]: ratatui_core::symbols::Marker::Dot
/// [`Block`]: ratatui_core::symbols::Marker::Block
///
/// # Examples
///
@ -828,9 +828,9 @@ where
#[cfg(test)]
mod tests {
use indoc::indoc;
use ratatui_core::buffer::Cell;
use super::*;
use crate::buffer::Cell;
// helper to test the canvas checks that drawing a vertical and horizontal line
// results in the expected output

View file

@ -1,7 +1,6 @@
use crate::{
style::Color,
widgets::canvas::{Painter, Shape},
};
use ratatui_core::style::Color;
use crate::canvas::{Painter, Shape};
/// A circle with a given center and radius and with a given color
#[derive(Debug, Default, Clone, PartialEq)]
@ -31,17 +30,12 @@ impl Shape for Circle {
#[cfg(test)]
mod tests {
use crate::{
buffer::Buffer,
layout::Rect,
style::Color,
symbols::Marker,
widgets::{
canvas::{Canvas, Circle},
Widget,
},
use ratatui_core::{
buffer::Buffer, layout::Rect, style::Color, symbols::Marker, widgets::Widget,
};
use crate::canvas::{Canvas, Circle};
#[test]
fn test_it_draws_a_circle() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 5));

View file

@ -1,7 +1,6 @@
use crate::{
style::Color,
widgets::canvas::{Painter, Shape},
};
use ratatui_core::style::Color;
use crate::canvas::{Painter, Shape};
/// A line from `(x1, y1)` to `(x2, y2)` with the given color
#[derive(Debug, Default, Clone, PartialEq)]
@ -112,16 +111,17 @@ fn draw_line_high(painter: &mut Painter, x1: usize, y1: usize, x2: usize, y2: us
#[cfg(test)]
mod tests {
use rstest::rstest;
use super::*;
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::Rect,
style::{Style, Stylize},
symbols::Marker,
widgets::{canvas::Canvas, Widget},
widgets::Widget,
};
use rstest::rstest;
use super::*;
use crate::canvas::Canvas;
#[rstest]
#[case::off_grid(&Line::new(-1.0, -1.0, 10.0, 10.0, Color::Red), [" "; 10])]
@ -207,7 +207,7 @@ mod tests {
fn tests<'expected_line, ExpectedLines>(#[case] line: &Line, #[case] expected: ExpectedLines)
where
ExpectedLines: IntoIterator,
ExpectedLines::Item: Into<crate::text::Line<'expected_line>>,
ExpectedLines::Item: Into<ratatui_core::text::Line<'expected_line>>,
{
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 10));
let canvas = Canvas::default()

View file

@ -1,11 +1,9 @@
use ratatui_core::style::Color;
use strum::{Display, EnumString};
use crate::{
style::Color,
widgets::canvas::{
use crate::canvas::{
world::{WORLD_HIGH_RESOLUTION, WORLD_LOW_RESOLUTION},
Painter, Shape,
},
};
/// Defines how many points are going to be used to draw a [`Map`].
@ -22,7 +20,7 @@ pub enum MapResolution {
///
/// Contains about 5000 points, you likely want to use [`Marker::Braille`] with this.
///
/// [`Marker::Braille`]: (crate::symbols::Marker::Braille)
/// [`Marker::Braille`]: (ratatui_core::symbols::Marker::Braille)
High,
}
@ -62,15 +60,11 @@ impl Shape for Map {
#[cfg(test)]
mod tests {
use ratatui_core::{buffer::Buffer, layout::Rect, symbols::Marker, widgets::Widget};
use strum::ParseError;
use super::*;
use crate::{
buffer::Buffer,
layout::Rect,
symbols::Marker,
widgets::{canvas::Canvas, Widget},
};
use crate::canvas::Canvas;
#[test]
fn map_resolution_to_string() {

View file

@ -1,7 +1,6 @@
use crate::{
style::Color,
widgets::canvas::{Painter, Shape},
};
use ratatui_core::style::Color;
use crate::canvas::{Painter, Shape};
/// A group of points with a given color
#[derive(Debug, Default, Clone, PartialEq)]

View file

@ -1,9 +1,8 @@
use crate::{
style::Color,
widgets::canvas::{Line, Painter, Shape},
};
use ratatui_core::style::Color;
/// A rectangle to draw on a [`Canvas`](crate::widgets::canvas::Canvas)
use crate::canvas::{Line, Painter, Shape};
/// A rectangle to draw on a [`Canvas`](crate::canvas::Canvas)
///
/// Sizes used here are **not** in terminal cell. This is much more similar to the
/// mathematic coordinate system.
@ -65,15 +64,17 @@ impl Shape for Rectangle {
#[cfg(test)]
mod tests {
use super::*;
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::{Margin, Rect},
style::{Style, Stylize},
symbols::Marker,
widgets::{canvas::Canvas, Widget},
widgets::Widget,
};
use super::*;
use crate::canvas::Canvas;
#[test]
fn draw_block_lines() {
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 10));

View file

@ -1,18 +1,19 @@
//! The [`Chart`] widget is used to plot one or more [`Dataset`] in a cartesian coordinate system.
use std::{cmp::max, ops::Not};
use strum::{Display, EnumString};
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::{Alignment, Constraint, Flex, Layout, Position, Rect},
style::{Color, Style, Styled},
symbols::{self},
text::Line,
widgets::{
block::BlockExt,
widgets::{Widget, WidgetRef},
};
use strum::{Display, EnumString};
use crate::{
block::{Block, BlockExt},
canvas::{Canvas, Line as CanvasLine, Points},
Block, Widget, WidgetRef,
},
};
/// An X or Y axis for the [`Chart`] widget
@ -126,8 +127,8 @@ impl<'a> Axis<'a> {
///
/// # Example
///
/// [`Axis`] also implements [`Stylize`](crate::style::Stylize) which mean you can style it
/// like so
/// [`Axis`] also implements [`Stylize`](ratatui_core::style::Stylize) which mean you can style
/// it like so
///
/// ```rust
/// use ratatui::{style::Stylize, widgets::Axis};
@ -410,8 +411,8 @@ impl<'a> Dataset<'a> {
///
/// # Example
///
/// [`Dataset`] also implements [`Stylize`](crate::style::Stylize) which mean you can style it
/// like so
/// [`Dataset`] also implements [`Stylize`](ratatui_core::style::Stylize) which mean you can
/// style it like so
///
/// ```rust
/// use ratatui::{style::Stylize, widgets::Dataset};
@ -1157,11 +1158,11 @@ impl<'a> Styled for Chart<'a> {
#[cfg(test)]
mod tests {
use ratatui_core::style::{Modifier, Stylize};
use rstest::rstest;
use strum::ParseError;
use super::*;
use crate::style::{Modifier, Stylize};
struct LegendTestCase {
chart_area: Rect,

View file

@ -1,4 +1,5 @@
use crate::{
//! The [`Clear`] widget allows you to clear a certain area to allow overdrawing (e.g. for popups).
use ratatui_core::{
buffer::Buffer,
layout::Rect,
widgets::{Widget, WidgetRef},
@ -7,7 +8,7 @@ use crate::{
/// A widget to clear/reset a certain area to allow overdrawing (e.g. for popups).
///
/// This widget **cannot be used to clear the terminal on the first render** as `ratatui` assumes
/// the render area is empty. Use [`crate::Terminal::clear`] instead.
/// the render area is empty. Use `Terminal::clear` instead.
///
/// # Examples
///
@ -50,8 +51,10 @@ impl WidgetRef for Clear {
#[cfg(test)]
mod tests {
use ratatui_core::{buffer::Buffer, layout::Rect, widgets::Widget};
use super::*;
use crate::{buffer::Buffer, layout::Rect, widgets::Widget};
#[test]
fn render() {
let mut buffer = Buffer::with_lines(["xxxxxxxxxxxxxxx"; 7]);

View file

@ -1,12 +1,15 @@
use crate::{
//! The [`Gauge`] widget is used to display a horizontal progress bar.
use ratatui_core::{
buffer::Buffer,
layout::Rect,
style::{Color, Style, Styled},
symbols::{self},
text::{Line, Span},
widgets::{block::BlockExt, Block, Widget, WidgetRef},
widgets::{Widget, WidgetRef},
};
use crate::block::{Block, BlockExt};
/// A widget to display a progress bar.
///
/// A `Gauge` renders a bar filled according to the value given to [`Gauge::percent`] or
@ -446,11 +449,13 @@ impl<'a> Styled for LineGauge<'a> {
#[cfg(test)]
mod tests {
use super::*;
use crate::{
use ratatui_core::{
style::{Color, Modifier, Style, Stylize},
symbols,
};
use super::*;
#[test]
#[should_panic = "Percentage should be between 0 and 100 inclusively"]
fn gauge_invalid_percentage() {

View file

@ -0,0 +1,89 @@
#![warn(missing_docs)]
//! Ratatui-widgets contains all the widgets that were previously part of the Ratatui crate. It is
//! meant to be used in conjunction with the [Ratatui] crate, which provides the core functionality
//! for building terminal user interfaces.
//!
//! [Ratatui]: https://crates.io/crates/ratatui
//!
//! Most applications shouldn't need to depend directly on Ratatui-widgets, as all the Ratatui crate
//! re-exports all the widgets from this crate. However, if you are building a widget library that
//! internally uses Ratatui widgets, or if you prefer finer grained dependencies, you may want to
//! depend on this crate rather than transitively through the Ratatui crate.
//!
//! Previously, a crate named `Ratatui-widgets` was published with some formative ideas about an
//! eventual Ratatui framework. That crate is now move to [tui-framework-experiment], pending a new
//! name.
//!
//! [tui-framework-experiment]: https://crates.io/crates/tui-framework-experiment
//!
//! # Installation
//!
//! Run the following command to add this crate to your project:
//!
//! ```sh
//! cargo add ratatui-widgets
//! ```
//!
//! # Available Widgets
//!
//! - [`BarChart`]: displays multiple datasets as bars with optional grouping.
//! - [`Block`]: a basic widget that draws a block with optional borders, titles, and styles.
//! - [`calendar::Monthly`]: displays a single month.
//! - [`Canvas`]: draws arbitrary shapes using drawing characters.
//! - [`Chart`]: displays multiple datasets as lines or scatter graphs.
//! - [`Clear`]: clears the area it occupies. Useful to render over previously drawn widgets.
//! - [`Gauge`]: displays progress percentage using block characters.
//! - [`LineGauge`]: displays progress as a line.
//! - [`List`]: displays a list of items and allows selection.
//! - [`RatatuiLogo`]: displays the Ratatui logo.
//! - [`Paragraph`]: displays a paragraph of optionally styled and wrapped text.
//! - [`Scrollbar`]: displays a scrollbar.
//! - [`Sparkline`]: displays a single dataset as a sparkline.
//! - [`Table`]: displays multiple rows and columns in a grid and allows selection.
//! - [`Tabs`]: displays a tab bar and allows selection.
//!
//! [`BarChart`]: crate::barchart::BarChart
//! [`Block`]: crate::block::Block
//! [`calendar::Monthly`]: crate::calendar::Monthly
//! [`Canvas`]: crate::canvas::Canvas
//! [`Chart`]: crate::chart::Chart
//! [`Clear`]: crate::clear::Clear
//! [`Gauge`]: crate::gauge::Gauge
//! [`LineGauge`]: crate::gauge::LineGauge
//! [`List`]: crate::list::List
//! [`RatatuiLogo`]: crate::logo::RatatuiLogo
//! [`Paragraph`]: crate::paragraph::Paragraph
//! [`Scrollbar`]: crate::scrollbar::Scrollbar
//! [`Sparkline`]: crate::sparkline::Sparkline
//! [`Table`]: crate::table::Table
//! [`Tabs`]: crate::tabs::Tabs
//!
//! All these widgets are re-exported directly under `ratatui::widgets` in the Ratatui crate.
//!
//! # Contributing
//!
//! Contributions are welcome! Please open an issue or submit a pull request on GitHub. For more
//! details on contributing, please see the [CONTRIBUTING](CONTRIBUTING.md) document.
//!
//! # License
//!
//! This project is licensed under the MIT License. See the [LICENSE](../LICENSE) file for details.
pub mod barchart;
pub mod block;
pub mod borders;
pub mod canvas;
pub mod chart;
pub mod clear;
pub mod gauge;
pub mod list;
pub mod logo;
pub mod paragraph;
pub mod scrollbar;
pub mod sparkline;
pub mod table;
pub mod tabs;
mod reflow;
#[cfg(feature = "calendar")]
pub mod calendar;

View file

@ -1,9 +1,14 @@
//! The [`List`] widget is used to display a list of items and allows selecting one or multiple
//! items.
use ratatui_core::style::{Style, Styled};
use strum::{Display, EnumString};
use crate::{
style::{Style, Styled},
widgets::{Block, HighlightSpacing, ListItem},
};
pub use self::{item::ListItem, state::ListState};
use crate::{block::Block, table::HighlightSpacing};
mod item;
mod rendering;
mod state;
/// A widget to display several items among which one can be selected (optional)
///
@ -13,13 +18,10 @@ use crate::{
/// the item's height is automatically determined. A `List` can also be put in reverse order (i.e.
/// *bottom to top*) whereas a [`Table`] cannot.
///
/// [`Table`]: crate::widgets::Table
/// [`Table`]: crate::table::Table
///
/// List items can be aligned using [`Text::alignment`], for more details see [`ListItem`].
///
/// [`List`] implements [`Widget`] and so it can be drawn using
/// [`Frame::render_widget`](crate::terminal::Frame::render_widget).
///
/// [`List`] is also a [`StatefulWidget`], which means you can use it with [`ListState`] to allow
/// the user to [scroll] through items and [select] one of them.
///
@ -95,12 +97,12 @@ use crate::{
/// (0..5).map(|i| format!("Item{i}")).collect::<List>();
/// ```
///
/// [`ListState`]: crate::widgets::list::ListState
/// [scroll]: crate::widgets::list::ListState::offset
/// [select]: crate::widgets::list::ListState::select
/// [`Text::alignment`]: crate::text::Text::alignment
/// [`StatefulWidget`]: crate::widgets::StatefulWidget
/// [`Widget`]: crate::widgets::Widget
/// [`ListState`]: crate::list::ListState
/// [scroll]: crate::list::ListState::offset
/// [select]: crate::list::ListState::select
/// [`Text::alignment`]: ratatui_core::text::Text::alignment
/// [`StatefulWidget`]: ratatui_core::widgets::StatefulWidget
/// [`Widget`]: ratatui_core::widgets::Widget
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
pub struct List<'a> {
/// An optional block to wrap the widget in
@ -178,7 +180,7 @@ impl<'a> List<'a> {
/// let filled_list = empty_list.items(["Item 1"]);
/// ```
///
/// [`Text`]: crate::text::Text
/// [`Text`]: ratatui_core::text::Text
pub fn new<T>(items: T) -> Self
where
T: IntoIterator,
@ -208,7 +210,7 @@ impl<'a> List<'a> {
/// let list = List::default().items(["Item 1", "Item 2"]);
/// ```
///
/// [`Text`]: crate::text::Text
/// [`Text`]: ratatui_core::text::Text
#[must_use = "method moves the value of self and returns the modified value"]
pub fn items<T>(mut self, items: T) -> Self
where
@ -265,7 +267,7 @@ impl<'a> List<'a> {
/// `List` also implements the [`Styled`] trait, which means you can use style shorthands from
/// the [`Stylize`] trait to set the style of the widget more concisely.
///
/// [`Stylize`]: crate::style::Stylize
/// [`Stylize`]: ratatui_core::style::Stylize
///
/// ```rust
/// use ratatui::{style::Stylize, widgets::List};
@ -274,7 +276,7 @@ impl<'a> List<'a> {
/// let list = List::new(items).red().italic();
/// ```
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -324,7 +326,7 @@ impl<'a> List<'a> {
/// let list = List::new(items).highlight_style(Style::new().red().italic());
/// ```
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn highlight_style<S: Into<Style>>(mut self, style: S) -> Self {
self.highlight_style = style.into();
@ -464,9 +466,9 @@ where
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use ratatui_core::style::{Color, Modifier, Stylize};
use super::*;
use crate::style::{Color, Modifier, Stylize};
#[test]
fn collect_list_from_iterator() {

View file

@ -1,4 +1,4 @@
use crate::{style::Style, text::Text};
use ratatui_core::{style::Style, text::Text};
/// A single item in a [`List`]
///
@ -63,10 +63,10 @@ use crate::{style::Style, text::Text};
/// ListItem::new(Text::from("foo").right_aligned());
/// ```
///
/// [`List`]: crate::widgets::List
/// [`Stylize`]: crate::style::Stylize
/// [`Line`]: crate::text::Line
/// [`Line::alignment`]: crate::text::Line::alignment
/// [`List`]: crate::list::List
/// [`Stylize`]: ratatui_core::style::Stylize
/// [`Line`]: ratatui_core::text::Line
/// [`Line::alignment`]: ratatui_core::text::Line::alignment
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ListItem<'a> {
pub(crate) content: Text<'a>,
@ -107,8 +107,8 @@ impl<'a> ListItem<'a> {
///
/// # See also
///
/// - [`List::new`](crate::widgets::List::new) to create a list of items that can be converted
/// to [`ListItem`]
/// - [`List::new`](super::List::new) to create a list of items that can be converted to
/// [`ListItem`]
pub fn new<T>(content: T) -> Self
where
T: Into<Text<'a>>,
@ -140,7 +140,7 @@ impl<'a> ListItem<'a> {
/// ```
///
/// `ListItem` also implements the [`Styled`] trait, which means you can use style shorthands
/// from the [`Stylize`](crate::style::Stylize) trait to set the style of the widget more
/// from the [`Stylize`](ratatui_core::style::Stylize) trait to set the style of the widget more
/// concisely.
///
/// ```rust
@ -149,9 +149,9 @@ impl<'a> ListItem<'a> {
/// let item = ListItem::new("Item 1").red().italic();
/// ```
///
/// [`Styled`]: crate::style::Styled
/// [`ListState`]: crate::widgets::list::ListState
/// [`Color`]: crate::style::Color
/// [`Styled`]: ratatui_core::style::Styled
/// [`ListState`]: crate::list::ListState
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -219,13 +219,13 @@ mod tests {
use std::borrow::Cow;
use pretty_assertions::assert_eq;
use super::*;
use crate::{
use ratatui_core::{
style::{Color, Modifier, Stylize},
text::{Line, Span},
};
use super::*;
#[test]
fn new_from_str() {
let item = ListItem::new("Test item");

View file

@ -1,12 +1,13 @@
use ratatui_core::{
buffer::Buffer,
layout::Rect,
widgets::{StatefulWidget, StatefulWidgetRef, Widget, WidgetRef},
};
use unicode_width::UnicodeWidthStr;
use crate::{
buffer::Buffer,
layout::Rect,
widgets::{
block::BlockExt, List, ListDirection, ListState, StatefulWidget, StatefulWidgetRef, Widget,
WidgetRef,
},
block::BlockExt,
list::{List, ListDirection, ListState},
};
impl Widget for List<'_> {
@ -273,17 +274,16 @@ impl List<'_> {
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use rstest::{fixture, rstest};
use super::*;
use crate::{
backend,
use ratatui_core::{
layout::{Alignment, Rect},
style::{Color, Modifier, Style, Stylize},
text::Line,
widgets::{Block, HighlightSpacing, ListItem, StatefulWidget, Widget},
Terminal,
widgets::{StatefulWidget, Widget},
};
use rstest::{fixture, rstest};
use super::*;
use crate::{block::Block, list::ListItem, table::HighlightSpacing};
#[fixture]
fn single_line_buf() -> Buffer {
@ -1148,8 +1148,7 @@ mod tests {
Lines: IntoIterator,
Lines::Item: Into<Line<'line>>,
{
let backend = backend::TestBackend::new(10, render_height);
let mut terminal = Terminal::new(backend).unwrap();
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, render_height));
let mut state = ListState::default();
*state.offset_mut() = offset;
@ -1158,10 +1157,8 @@ mod tests {
let list = List::new(["Item 0", "Item 1", "Item 2", "Item 3", "Item 4", "Item 5"])
.scroll_padding(padding)
.highlight_symbol(">> ");
terminal
.draw(|f| f.render_stateful_widget(list, f.area(), &mut state))
.unwrap();
terminal.backend().assert_buffer_lines(expected);
StatefulWidget::render(list, buffer.area, &mut buffer, &mut state);
assert_eq!(buffer, Buffer::with_lines(expected));
}
/// If there isn't enough room for the selected item and the requested padding the list can jump
@ -1169,8 +1166,7 @@ mod tests {
/// isn't currently happening
#[test]
fn padding_flicker() {
let backend = backend::TestBackend::new(10, 5);
let mut terminal = Terminal::new(backend).unwrap();
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 5));
let mut state = ListState::default();
*state.offset_mut() = 2;
@ -1181,15 +1177,11 @@ mod tests {
];
let list = List::new(items).scroll_padding(3).highlight_symbol(">> ");
terminal
.draw(|f| f.render_stateful_widget(&list, f.area(), &mut state))
.unwrap();
StatefulWidget::render(&list, buffer.area, &mut buffer, &mut state);
let offset_after_render = state.offset();
terminal
.draw(|f| f.render_stateful_widget(&list, f.area(), &mut state))
.unwrap();
StatefulWidget::render(&list, buffer.area, &mut buffer, &mut state);
// Offset after rendering twice should remain the same as after once
assert_eq!(offset_after_render, state.offset());
@ -1197,8 +1189,7 @@ mod tests {
#[test]
fn padding_inconsistent_item_sizes() {
let backend = backend::TestBackend::new(10, 3);
let mut terminal = Terminal::new(backend).unwrap();
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 3));
let mut state = ListState::default().with_offset(0).with_selected(Some(3));
let items = [
@ -1211,9 +1202,7 @@ mod tests {
];
let list = List::new(items).scroll_padding(1).highlight_symbol(">> ");
terminal
.draw(|f| f.render_stateful_widget(list, f.area(), &mut state))
.unwrap();
StatefulWidget::render(list, buffer.area, &mut buffer, &mut state);
#[rustfmt::skip]
let expected = [
@ -1221,15 +1210,14 @@ mod tests {
" Item 2 ",
">> Item 3 ",
];
terminal.backend().assert_buffer_lines(expected);
assert_eq!(buffer, Buffer::with_lines(expected));
}
// Tests to make sure when it's pushing back the first visible index value that it doesnt
// include an item that's too large
#[test]
fn padding_offset_pushback_break() {
let backend = backend::TestBackend::new(10, 4);
let mut terminal = Terminal::new(backend).unwrap();
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 4));
let mut state = ListState::default();
*state.offset_mut() = 1;
@ -1243,16 +1231,16 @@ mod tests {
];
let list = List::new(items).scroll_padding(2).highlight_symbol(">> ");
terminal
.draw(|f| f.render_stateful_widget(list, f.area(), &mut state))
.unwrap();
terminal.backend().assert_buffer_lines([
StatefulWidget::render(list, buffer.area, &mut buffer, &mut state);
#[rustfmt::skip]
assert_eq!(
buffer,
Buffer::with_lines([
" Item 1 ",
">> Item 2 ",
" Item 3 ",
" ",
]);
" "])
);
}
/// Regression test for a bug where highlight symbol being greater than width caused a panic due

View file

@ -3,7 +3,7 @@
/// This state can be used to scroll through items and select one. When the list is rendered as a
/// stateful widget, the selected item will be highlighted and the list will be shifted to ensure
/// that the selected item is visible. This will modify the [`ListState`] object passed to the
/// [`Frame::render_stateful_widget`](crate::terminal::Frame::render_stateful_widget) method.
/// `Frame::render_stateful_widget` method.
///
/// The state consists of two fields:
/// - [`offset`]: the index of the first item to be displayed
@ -41,7 +41,7 @@
/// # }
/// ```
///
/// [`List`]: crate::widgets::List
/// [`List`]: super::List
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ListState {
@ -276,7 +276,7 @@ impl ListState {
mod tests {
use pretty_assertions::assert_eq;
use crate::widgets::ListState;
use crate::list::ListState;
#[test]
fn selected() {

View file

@ -1,6 +1,6 @@
//! The [`RatatuiLogo`] widget renders the Ratatui logo.
use indoc::indoc;
use crate::{buffer::Buffer, layout::Rect, text::Text, widgets::Widget};
use ratatui_core::{buffer::Buffer, layout::Rect, text::Text, widgets::Widget};
/// A widget that renders the Ratatui logo
///

View file

@ -1,15 +1,17 @@
use unicode_width::UnicodeWidthStr;
use crate::{
//! The [`Paragraph`] widget and related types allows displaying a block of text with optional
//! wrapping, alignment, and block styling.
use ratatui_core::{
buffer::Buffer,
layout::{Alignment, Position, Rect},
style::{Style, Styled},
text::{Line, StyledGrapheme, Text},
widgets::{
block::BlockExt,
widgets::{Widget, WidgetRef},
};
use unicode_width::UnicodeWidthStr;
use crate::{
block::{Block, BlockExt},
reflow::{LineComposer, LineTruncator, WordWrapper, WrappedLine},
Block, Widget, WidgetRef,
},
};
const fn get_line_offset(line_width: u16, text_area_width: u16, alignment: Alignment) -> u16 {
@ -84,7 +86,7 @@ const fn get_line_offset(line_width: u16, text_area_width: u16, alignment: Align
/// .wrap(Wrap { trim: true });
/// ```
///
/// [`Span`]: crate::text::Span
/// [`Span`]: ratatui_core::text::Span
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Paragraph<'a> {
/// A block to wrap the widget in
@ -211,7 +213,7 @@ impl<'a> Paragraph<'a> {
/// let paragraph = Paragraph::new("Hello, world!").style(Style::new().red().on_white());
/// ```
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -500,30 +502,27 @@ impl<'a> Styled for Paragraph<'a> {
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
backend::TestBackend,
mod tests {
use ratatui_core::{
buffer::Buffer,
layout::{Alignment, Rect},
style::{Color, Modifier, Style, Stylize},
text::{Line, Span, Text},
widgets::{block::Position, Borders, Widget},
Terminal,
widgets::Widget,
};
use super::*;
use crate::{block::Position, borders::Borders};
/// Tests the [`Paragraph`] widget against the expected [`Buffer`] by rendering it onto an equal
/// area and comparing the rendered and expected content.
/// This can be used for easy testing of varying configured paragraphs with the same expected
/// buffer or any other test case really.
#[track_caller]
fn test_case(paragraph: &Paragraph, expected: &Buffer) {
let backend = TestBackend::new(expected.area.width, expected.area.height);
let mut terminal = Terminal::new(backend).unwrap();
terminal
.draw(|f| f.render_widget(paragraph.clone(), f.area()))
.unwrap();
terminal.backend().assert_buffer(expected);
let mut buffer = Buffer::empty(Rect::new(0, 0, expected.area.width, expected.area.height));
paragraph.render(buffer.area, &mut buffer);
assert_eq!(buffer, *expected);
}
#[test]

View file

@ -1,10 +1,10 @@
//! Internal module for reflowing text to fit into a certain width.
use std::{collections::VecDeque, mem};
use ratatui_core::{layout::Alignment, text::StyledGrapheme};
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
use crate::{layout::Alignment, text::StyledGrapheme};
/// A state machine to pack styled symbols into lines.
/// Cannot implement it as Iterator since it yields slices of the internal buffer (need streaming
/// iterators for that).
@ -12,6 +12,7 @@ pub trait LineComposer<'a> {
fn next_line<'lend>(&'lend mut self) -> Option<WrappedLine<'lend, 'a>>;
}
/// A line that has been wrapped to a certain width.
pub struct WrappedLine<'lend, 'text> {
/// One line reflowed to the correct width
pub line: &'lend [StyledGrapheme<'text>],
@ -51,6 +52,7 @@ where
O: Iterator<Item = (I, Alignment)>,
I: Iterator<Item = StyledGrapheme<'a>>,
{
/// Create a new `WordWrapper` with the given lines and maximum line width.
pub const fn new(lines: O, max_line_width: u16, trim: bool) -> Self {
Self {
input_lines: lines,
@ -250,6 +252,7 @@ where
O: Iterator<Item = (I, Alignment)>,
I: Iterator<Item = StyledGrapheme<'a>>,
{
/// Create a new `LineTruncator` with the given lines and maximum line width.
pub const fn new(lines: O, max_line_width: u16) -> Self {
Self {
input_lines: lines,
@ -259,6 +262,7 @@ where
}
}
/// Set the horizontal offset to skip render.
pub fn set_horizontal_offset(&mut self, horizontal_offset: u16) {
self.horizontal_offset = horizontal_offset;
}
@ -343,13 +347,14 @@ fn trim_offset(src: &str, mut offset: usize) -> &str {
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
mod tests {
use ratatui_core::{
style::Style,
text::{Line, Text},
};
use super::*;
#[derive(Clone, Copy)]
enum Composer {
WordWrapper { trim: bool },

View file

@ -1,3 +1,4 @@
//! The [`Scrollbar`] widget is used to display a scrollbar alongside other widgets.
#![warn(clippy::pedantic)]
#![allow(
clippy::cast_possible_truncation,
@ -8,16 +9,15 @@
use std::iter;
use strum::{Display, EnumString};
use unicode_width::UnicodeWidthStr;
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::Rect,
style::Style,
symbols::scrollbar::{Set, DOUBLE_HORIZONTAL, DOUBLE_VERTICAL},
widgets::StatefulWidget,
};
use strum::{Display, EnumString};
use unicode_width::UnicodeWidthStr;
/// A widget to display a scrollbar
///
@ -266,7 +266,7 @@ impl<'a> Scrollbar<'a> {
///
/// This is a fluent setter method which must be chained or used as it consumes self
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn thumb_style<S: Into<Style>>(mut self, thumb_style: S) -> Self {
self.thumb_style = thumb_style.into();
@ -293,7 +293,7 @@ impl<'a> Scrollbar<'a> {
///
/// This is a fluent setter method which must be chained or used as it consumes self
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn track_style<S: Into<Style>>(mut self, track_style: S) -> Self {
self.track_style = track_style.into();
@ -320,7 +320,7 @@ impl<'a> Scrollbar<'a> {
///
/// This is a fluent setter method which must be chained or used as it consumes self
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn begin_style<S: Into<Style>>(mut self, begin_style: S) -> Self {
self.begin_style = begin_style.into();
@ -347,7 +347,7 @@ impl<'a> Scrollbar<'a> {
///
/// This is a fluent setter method which must be chained or used as it consumes self
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn end_style<S: Into<Style>>(mut self, end_style: S) -> Self {
self.end_style = end_style.into();
@ -402,7 +402,7 @@ impl<'a> Scrollbar<'a> {
///
/// This is a fluent setter method which must be chained or used as it consumes self
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
let style = style.into();
@ -638,11 +638,11 @@ impl ScrollbarOrientation {
mod tests {
use std::str::FromStr;
use ratatui_core::{text::Text, widgets::Widget};
use rstest::{fixture, rstest};
use strum::ParseError;
use super::*;
use crate::{text::Text, widgets::Widget};
#[test]
fn scroll_direction_to_string() {

View file

@ -1,14 +1,16 @@
//! The [`Sparkline`] widget is used to display a sparkline over one or more lines.
use std::cmp::min;
use strum::{Display, EnumString};
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::Rect,
style::{Style, Styled},
symbols::{self},
widgets::{block::BlockExt, Block, Widget, WidgetRef},
widgets::{Widget, WidgetRef},
};
use strum::{Display, EnumString};
use crate::block::{Block, BlockExt};
/// Widget to render a sparkline over one or more lines.
///
@ -22,8 +24,8 @@ use crate::{
/// of `None` is interpreted an as the _absence_ of a value.
///
/// `Sparkline` can be styled either using [`Sparkline::style`] or preferably using the methods
/// provided by the [`Stylize`](crate::style::Stylize) trait. The style may be set for the entire
/// widget or for individual bars by setting individual [`SparklineBar::style`].
/// provided by the [`Stylize`](ratatui_core::style::Stylize) trait. The style may be set for the
/// entire widget or for individual bars by setting individual [`SparklineBar::style`].
///
/// The bars are rendered using a set of symbols. The default set is [`symbols::bar::NINE_LEVELS`].
/// You can change the set using [`Sparkline::bar_set`].
@ -109,7 +111,7 @@ impl<'a> Sparkline<'a> {
///
/// The foreground corresponds to the bars while the background is everything else.
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -125,7 +127,7 @@ impl<'a> Sparkline<'a> {
///
/// The foreground corresponds to the bars while the background is everything else.
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn absent_value_style<S: Into<Style>>(mut self, style: S) -> Self {
self.absent_value_style = style.into();
@ -269,7 +271,7 @@ impl SparklineBar {
/// style. If set, the style of the bar will be the style of the sparkline combined with
/// the style of the bar.
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Option<Style>>>(mut self, style: S) -> Self {
self.style = style.into();
@ -434,13 +436,13 @@ impl Sparkline<'_> {
#[cfg(test)]
mod tests {
use strum::ParseError;
use super::*;
use crate::{
use ratatui_core::{
buffer::Cell,
style::{Color, Modifier, Stylize},
};
use strum::ParseError;
use super::*;
#[test]
fn render_direction_to_string() {

View file

@ -1,19 +1,23 @@
use itertools::Itertools;
//! The [`Table`] widget is used to display multiple rows and columns in a grid and allows selecting
//! one or multiple cells.
#[allow(unused_imports)] // `Cell` is used in the doc comment but not the code
use crate::widgets::table::Cell;
use crate::{
use itertools::Itertools;
use ratatui_core::{
buffer::Buffer,
layout::{Constraint, Flex, Layout, Rect},
style::{Style, Styled},
text::Text,
widgets::{
block::BlockExt,
table::{HighlightSpacing, Row, TableState},
Block, StatefulWidget, StatefulWidgetRef, Widget, WidgetRef,
},
widgets::{StatefulWidget, StatefulWidgetRef, Widget, WidgetRef},
};
pub use self::{cell::Cell, highlight_spacing::HighlightSpacing, row::Row, state::TableState};
use crate::block::{Block, BlockExt};
mod cell;
mod highlight_spacing;
mod row;
mod state;
/// A widget to display data in formatted columns.
///
/// A `Table` is a collection of [`Row`]s, each composed of [`Cell`]s:
@ -26,7 +30,7 @@ use crate::{
/// Make sure to call the [`Table::widths`] method, otherwise the columns will all have a width of 0
/// and thus not be visible.
///
/// [`Table`] implements [`Widget`] and so it can be drawn using [`Frame::render_widget`].
/// [`Table`] implements [`Widget`] and so it can be drawn using `Frame::render_widget`.
///
/// [`Table`] is also a [`StatefulWidget`], which means you can use it with [`TableState`] to allow
/// the user to scroll through the rows and select one of them. When rendering a [`Table`] with a
@ -232,8 +236,7 @@ use crate::{
/// # }
/// ```
///
/// [`Frame::render_widget`]: crate::Frame::render_widget
/// [`Stylize`]: crate::style::Stylize
/// [`Stylize`]: ratatui_core::style::Stylize
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Table<'a> {
/// Data to display in each row
@ -543,8 +546,8 @@ impl<'a> Table<'a> {
/// let table = Table::new(rows, widths).red().italic();
/// ```
///
/// [`Color`]: crate::style::Color
/// [`Stylize`]: crate::style::Stylize
/// [`Color`]: ratatui_core::style::Color
/// [`Stylize`]: ratatui_core::style::Stylize
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -575,7 +578,7 @@ impl<'a> Table<'a> {
/// let table = Table::new(rows, widths).highlight_style(Style::new().red().italic());
/// ```
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
#[deprecated(note = "use `Table::row_highlight_style` instead")]
pub fn highlight_style<S: Into<Style>>(self, highlight_style: S) -> Self {
@ -600,7 +603,7 @@ impl<'a> Table<'a> {
/// # let widths = [Constraint::Length(5), Constraint::Length(5)];
/// let table = Table::new(rows, widths).row_highlight_style(Style::new().red().italic());
/// ```
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn row_highlight_style<S: Into<Style>>(mut self, highlight_style: S) -> Self {
self.row_highlight_style = highlight_style.into();
@ -625,7 +628,7 @@ impl<'a> Table<'a> {
/// # let widths = [Constraint::Length(5), Constraint::Length(5)];
/// let table = Table::new(rows, widths).column_highlight_style(Style::new().red().italic());
/// ```
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn column_highlight_style<S: Into<Style>>(mut self, highlight_style: S) -> Self {
self.column_highlight_style = highlight_style.into();
@ -650,7 +653,7 @@ impl<'a> Table<'a> {
/// # let widths = [Constraint::Length(5), Constraint::Length(5)];
/// let table = Table::new(rows, widths).cell_highlight_style(Style::new().red().italic());
/// ```
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn cell_highlight_style<S: Into<Style>>(mut self, highlight_style: S) -> Self {
self.cell_highlight_style = highlight_style.into();
@ -1085,15 +1088,15 @@ where
mod tests {
use std::vec;
use rstest::{fixture, rstest};
use super::*;
use crate::{
use ratatui_core::{
layout::Constraint::*,
style::{Color, Modifier, Style, Stylize},
text::Line,
widgets::Cell,
};
use rstest::{fixture, rstest};
use super::*;
use crate::table::Cell;
#[test]
fn new() {
@ -1278,14 +1281,15 @@ mod tests {
#[cfg(test)]
mod state {
use super::*;
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::{Constraint, Rect},
widgets::{Row, StatefulWidget, Table, TableState},
widgets::StatefulWidget,
};
use super::*;
use crate::table::{Row, Table, TableState};
#[fixture]
fn table_buf() -> Buffer {
Buffer::empty(Rect::new(0, 0, 10, 10))
@ -1358,8 +1362,9 @@ mod tests {
#[cfg(test)]
mod render {
use ratatui_core::layout::Alignment;
use super::*;
use crate::layout::Alignment;
#[test]
fn render_empty_area() {

View file

@ -1,4 +1,4 @@
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::Rect,
style::{Style, Styled},
@ -47,9 +47,9 @@ use crate::{
/// Cell::new("Cell 1").red().italic();
/// ```
///
/// [`Row`]: crate::widgets::Row
/// [`Table`]: crate::widgets::Table
/// [`Stylize`]: crate::style::Stylize
/// [`Row`]: super::Row
/// [`Table`]: super::Table
/// [`Stylize`]: ratatui_core::style::Stylize
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Cell<'a> {
content: Text<'a>,
@ -150,9 +150,9 @@ impl<'a> Cell<'a> {
/// Cell::new("Cell 1").red().italic();
/// ```
///
/// [`Row`]: crate::widgets::Row
/// [`Color`]: crate::style::Color
/// [`Stylize`]: crate::style::Stylize
/// [`Row`]: super::Row
/// [`Color`]: ratatui_core::style::Color
/// [`Stylize`]: ratatui_core::style::Stylize
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -193,8 +193,9 @@ impl<'a> Styled for Cell<'a> {
#[cfg(test)]
mod tests {
use ratatui_core::style::{Color, Modifier, Stylize};
use super::*;
use crate::style::{Color, Modifier, Stylize};
#[test]
fn new() {

View file

@ -1,7 +1,6 @@
use crate::{
style::{Style, Styled},
widgets::table::Cell,
};
use ratatui_core::style::{Style, Styled};
use super::Cell;
/// A single row of data to be displayed in a [`Table`] widget.
///
@ -68,9 +67,9 @@ use crate::{
/// Row::new(cells).red().italic();
/// ```
///
/// [`Table`]: crate::widgets::Table
/// [`Text`]: crate::text::Text
/// [`Stylize`]: crate::style::Stylize
/// [`Table`]: super::Table
/// [`Text`]: ratatui_core::text::Text
/// [`Stylize`]: ratatui_core::style::Stylize
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
pub struct Row<'a> {
pub(crate) cells: Vec<Cell<'a>>,
@ -232,9 +231,9 @@ impl<'a> Row<'a> {
/// let row = Row::new(cells).red().italic();
/// ```
///
/// [`Color`]: crate::style::Color
/// [`Stylize`]: crate::style::Stylize
/// [`Text`]: crate::text::Text
/// [`Color`]: ratatui_core::style::Color
/// [`Stylize`]: ratatui_core::style::Stylize
/// [`Text`]: ratatui_core::text::Text
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -277,8 +276,9 @@ where
mod tests {
use std::vec;
use ratatui_core::style::{Color, Modifier, Stylize};
use super::*;
use crate::style::{Color, Modifier, Stylize};
#[test]
fn new() {

View file

@ -3,7 +3,7 @@
/// This state can be used to scroll through the rows and select one of them. When the table is
/// rendered as a stateful widget, the selected row, column and cell will be highlighted and the
/// table will be shifted to ensure that the selected row is visible. This will modify the
/// [`TableState`] object passed to the [`Frame::render_stateful_widget`] method.
/// [`TableState`] object passed to the `Frame::render_stateful_widget` method.
///
/// The state consists of two fields:
/// - [`offset`]: the index of the first row to be displayed
@ -50,9 +50,8 @@
/// Note that if [`Table::widths`] is not called before rendering, the rendered columns will have
/// equal width.
///
/// [`Table`]: crate::widgets::Table
/// [`Table::widths`]: crate::widgets::Table::widths
/// [`Frame::render_stateful_widget`]: crate::Frame::render_stateful_widget
/// [`Table`]: super::Table
/// [`Table::widths`]: crate::table::Table::widths
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct TableState {

View file

@ -1,14 +1,16 @@
//! The [`Tabs`] widget displays a horizontal set of tabs with a single tab selected.
use itertools::Itertools;
use crate::{
use ratatui_core::{
buffer::Buffer,
layout::Rect,
style::{Modifier, Style, Styled},
symbols::{self},
text::{Line, Span},
widgets::{block::BlockExt, Block, Widget, WidgetRef},
widgets::{Widget, WidgetRef},
};
use crate::block::{Block, BlockExt};
const DEFAULT_HIGHLIGHT_STYLE: Style = Style::new().add_modifier(Modifier::REVERSED);
/// A widget that displays a horizontal set of Tabs with a single tab selected.
@ -228,7 +230,7 @@ impl<'a> Tabs<'a> {
/// More precise style can be applied to the titles by styling the ones given to [`Tabs::new`].
/// The selected tab can be styled differently using [`Tabs::highlight_style`].
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
#[must_use = "method moves the value of self and returns the modified value"]
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
self.style = style.into();
@ -243,7 +245,7 @@ impl<'a> Tabs<'a> {
/// Highlighted tab can be selected with [`Tabs::select`].
#[must_use = "method moves the value of self and returns the modified value"]
///
/// [`Color`]: crate::style::Color
/// [`Color`]: ratatui_core::style::Color
pub fn highlight_style<S: Into<Style>>(mut self, style: S) -> Self {
self.highlight_style = style.into();
self
@ -443,8 +445,9 @@ where
#[cfg(test)]
mod tests {
use ratatui_core::style::{Color, Stylize};
use super::*;
use crate::style::{Color, Stylize};
#[test]
fn new() {

View file

@ -15,7 +15,6 @@ edition.workspace = true
rust-version.workspace = true
[dependencies]
bitflags.workspace = true
crossterm = { version = "0.28.1", optional = true }
document-features = { version = "0.2.7", optional = true }
indoc = "2"
@ -23,11 +22,11 @@ instability.workspace = true
itertools.workspace = true
palette = { version = "0.7.6", optional = true }
ratatui-core = { workspace = true, features = ["unstable-widget-ref"] }
ratatui-widgets = { workspace = true, features = ["unstable-widget-ref"] }
serde = { workspace = true, optional = true }
strum.workspace = true
termwiz = { version = "0.22.0", optional = true }
time = { version = "0.3.11", optional = true, features = ["local-offset"] }
unicode-segmentation.workspace = true
# See <https://github.com/ratatui/ratatui/issues/1271> for information about why we pin unicode-width
unicode-width.workspace = true
@ -120,10 +119,7 @@ termwiz = ["dep:termwiz"]
#! The following optional features are available for all backends:
## enables serialization and deserialization of style and color types using the [`serde`] crate.
## This is useful if you want to save themes to a file.
serde = ["dep:serde", "ratatui-core/serde"]
## enables the [`border!`] macro.
macros = []
serde = ["dep:serde", "ratatui-core/serde", "ratatui-widgets/serde"]
## enables conversions from colors in the [`palette`] crate to [`Color`](crate::style::Color).
palette = ["ratatui-core/palette", "dep:palette"]
@ -138,7 +134,7 @@ all-widgets = ["widget-calendar"]
#! Widgets that add dependencies are gated behind feature flags to prevent unused transitive
#! dependencies. The available features are:
## enables the [`calendar`](widgets::calendar) widget module and adds a dependency on [`time`].
widget-calendar = ["dep:time"]
widget-calendar = ["ratatui-widgets/calendar"]
#! The following optional features are only available for some backends:
@ -160,7 +156,7 @@ unstable = [
## [`Paragraph::line_width`](widgets::Paragraph::line_width) methods
## which are experimental and may change in the future.
## See [Issue 293](https://github.com/ratatui/ratatui/issues/293) for more details.
unstable-rendered-line-info = []
unstable-rendered-line-info = ["ratatui-widgets/unstable-rendered-line-info"]
## enables the [`WidgetRef`] and [`StatefulWidgetRef`] traits which are experimental and may change
## in the future.

View file

@ -350,3 +350,4 @@ pub use ratatui_core::{style, symbols};
mod terminal;
pub use ratatui_core::text;
pub mod widgets;
pub use ratatui_widgets::border;

View file

@ -1,8 +1,14 @@
#![warn(missing_docs)]
//! `widgets` is a collection of types that implement [`Widget`] or [`StatefulWidget`] or both.
//!
//! Widgets are created for each frame as they are consumed after rendered.
//! They are not meant to be stored but used as *commands* to draw common figures in the UI.
//! The widgets provided with Ratatui are implemented in the [`ratatui_widgets`] crate, and are
//! re-exported here. The [`Widget`] and [`StatefulWidget`] traits are implemented in the
//! [`ratatui_core`] crate and are also re-exported in this module. This means that you can use
//! these types directly from the `ratatui` crate without having to import the `ratatui_widgets`
//! crate.
//!
//! Widgets are created for each frame as they are consumed after rendered. They are not meant to be
//! stored but used as *commands* to draw common figures in the UI.
//!
//! The available widgets are:
//! - [`Block`]: a basic widget that draws a block with optional borders, titles and styles.
@ -21,32 +27,19 @@
//! - [`Tabs`]: displays a tab bar and allows selection.
//!
//! [`Canvas`]: crate::widgets::canvas::Canvas
mod barchart;
pub mod block;
mod borders;
#[cfg(feature = "widget-calendar")]
pub mod calendar;
pub mod canvas;
mod chart;
mod clear;
mod gauge;
mod list;
mod logo;
mod paragraph;
mod reflow;
mod scrollbar;
mod sparkline;
mod table;
mod tabs;
pub use ratatui_core::widgets::{StatefulWidget, Widget};
#[instability::unstable(feature = "widget-ref")]
pub use ratatui_core::widgets::{StatefulWidgetRef, WidgetRef};
pub use self::{
// TODO remove this module once title etc. are gone
pub use ratatui_widgets::block;
#[cfg(feature = "widget-calendar")]
pub use ratatui_widgets::calendar;
pub use ratatui_widgets::{
barchart::{Bar, BarChart, BarGroup},
block::{Block, BorderType, Padding},
borders::*,
block::{Block, Padding},
borders::{BorderType, Borders},
canvas,
chart::{Axis, Chart, Dataset, GraphType, LegendPosition},
clear::Clear,
gauge::{Gauge, LineGauge},

View file

@ -1,10 +0,0 @@
pub use self::{
item::ListItem,
list::{List, ListDirection},
state::ListState,
};
mod item;
mod list;
mod rendering;
mod state;

View file

@ -1,11 +0,0 @@
mod cell;
mod highlight_spacing;
mod row;
mod table;
mod table_state;
pub use cell::*;
pub use highlight_spacing::*;
pub use row::*;
pub use table::*;
pub use table_state::*;