mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-21 20:23:11 +00:00
refactor: modularize
WIP - this is just a PoC to understand whether this would work fine, termion and termwiz disabled for now
This commit is contained in:
parent
bc10af5931
commit
26163effdf
202 changed files with 1906 additions and 1244 deletions
367
Cargo.toml
367
Cargo.toml
|
@ -1,54 +1,41 @@
|
||||||
[package]
|
[workspace]
|
||||||
name = "ratatui"
|
resolver = "2"
|
||||||
version = "0.28.1" # crate version
|
members = ["ratatui*"]
|
||||||
authors = ["Florian Dehau <work@fdehau.com>", "The Ratatui Developers"]
|
# disabled for now because of the orphan rule on conversions
|
||||||
description = "A library that's all about cooking up terminal user interfaces"
|
# <https://github.com/ratatui/ratatui/issues/1388#issuecomment-2379895747>
|
||||||
documentation = "https://docs.rs/ratatui/latest/ratatui/"
|
exclude = ["ratatui-termion", "ratatui-termwiz"]
|
||||||
repository = "https://github.com/ratatui/ratatui"
|
|
||||||
homepage = "https://ratatui.rs"
|
[workspace.dependencies]
|
||||||
keywords = ["tui", "terminal", "dashboard"]
|
ratatui = { path = "ratatui" }
|
||||||
categories = ["command-line-interface"]
|
ratatui-core = { path = "ratatui-core" }
|
||||||
readme = "README.md"
|
ratatui-crossterm = { path = "ratatui-crossterm" }
|
||||||
license = "MIT"
|
ratatui-termion = { path = "ratatui-termion" }
|
||||||
exclude = [
|
ratatui-termwiz = { path = "ratatui-termwiz" }
|
||||||
"assets/*",
|
ratatui-widgets = { path = "ratatui-widgets" }
|
||||||
".github",
|
|
||||||
"Makefile.toml",
|
|
||||||
"CONTRIBUTING.md",
|
|
||||||
"*.log",
|
|
||||||
"tags",
|
|
||||||
]
|
|
||||||
edition = "2021"
|
|
||||||
rust-version = "1.74.0"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
bitflags = "2.3"
|
bitflags = "2.3"
|
||||||
cassowary = "0.3"
|
cassowary = "0.3"
|
||||||
compact_str = "0.8.0"
|
compact_str = "0.8.0"
|
||||||
crossterm = { version = "0.28.1", optional = true }
|
crossterm = { version = "0.28.1" }
|
||||||
document-features = { version = "0.2.7", optional = true }
|
document-features = { version = "0.2.7" }
|
||||||
instability = "0.3.1"
|
instability = "0.3.1"
|
||||||
itertools = "0.13"
|
itertools = "0.13"
|
||||||
lru = "0.12.0"
|
lru = "0.12.0"
|
||||||
paste = "1.0.2"
|
paste = "1.0.2"
|
||||||
palette = { version = "0.7.6", optional = true }
|
palette = { version = "0.7.6" }
|
||||||
serde = { version = "1", optional = true, features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
strum = { version = "0.26.3", features = ["derive"] }
|
strum = { version = "0.26.3", features = ["derive"] }
|
||||||
termwiz = { version = "0.22.0", optional = true }
|
termion = { version = "4.0.0" }
|
||||||
time = { version = "0.3.11", optional = true, features = ["local-offset"] }
|
termwiz = { version = "0.22.0" }
|
||||||
|
time = { version = "0.3.11", features = ["local-offset"] }
|
||||||
unicode-segmentation = "1.10"
|
unicode-segmentation = "1.10"
|
||||||
unicode-truncate = "1"
|
unicode-truncate = "1"
|
||||||
unicode-width = "=0.1.13"
|
unicode-width = "=0.1.13"
|
||||||
|
|
||||||
[target.'cfg(not(windows))'.dependencies]
|
# dev-dependencies
|
||||||
# termion is not supported on Windows
|
|
||||||
termion = { version = "4.0.0", optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
argh = "0.1.12"
|
argh = "0.1.12"
|
||||||
color-eyre = "0.6.2"
|
color-eyre = "0.6.2"
|
||||||
criterion = { version = "0.5.1", features = ["html_reports"] }
|
criterion = { version = "0.5.1", features = ["html_reports"] }
|
||||||
crossterm = { version = "0.28.1", features = ["event-stream"] }
|
|
||||||
fakeit = "1.1"
|
fakeit = "1.1"
|
||||||
font8x8 = "0.3.1"
|
font8x8 = "0.3.1"
|
||||||
futures = "0.3.30"
|
futures = "0.3.30"
|
||||||
|
@ -68,313 +55,3 @@ tokio = { version = "1.39.2", features = [
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-appender = "0.2.3"
|
tracing-appender = "0.2.3"
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
|
|
||||||
[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"
|
|
||||||
|
|
||||||
[features]
|
|
||||||
#! The crate provides a set of optional features that can be enabled in your `cargo.toml` file.
|
|
||||||
#!
|
|
||||||
## By default, we enable the crossterm backend as this is a reasonable choice for most applications
|
|
||||||
## as it is supported on Linux/Mac/Windows systems. We also enable the `underline-color` feature
|
|
||||||
## which allows you to set the underline color of text.
|
|
||||||
default = ["crossterm", "underline-color"]
|
|
||||||
#! Generally an application will only use one backend, so you should only enable one of the following features:
|
|
||||||
## enables the [`CrosstermBackend`](backend::CrosstermBackend) backend and adds a dependency on [`crossterm`].
|
|
||||||
crossterm = ["dep:crossterm"]
|
|
||||||
## enables the [`TermionBackend`](backend::TermionBackend) backend and adds a dependency on [`termion`].
|
|
||||||
termion = ["dep:termion"]
|
|
||||||
## enables the [`TermwizBackend`](backend::TermwizBackend) backend and adds a dependency on [`termwiz`].
|
|
||||||
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", "bitflags/serde", "compact_str/serde"]
|
|
||||||
|
|
||||||
## enables the [`border!`] macro.
|
|
||||||
macros = []
|
|
||||||
|
|
||||||
## enables conversions from colors in the [`palette`] crate to [`Color`](crate::style::Color).
|
|
||||||
palette = ["dep:palette"]
|
|
||||||
|
|
||||||
## enables all widgets.
|
|
||||||
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"]
|
|
||||||
|
|
||||||
#! The following optional features are only available for some backends:
|
|
||||||
|
|
||||||
## enables the backend code that sets the underline color.
|
|
||||||
## Underline color is only supported by the [`CrosstermBackend`](backend::CrosstermBackend) backend,
|
|
||||||
## and is not supported on Windows 7.
|
|
||||||
underline-color = ["dep:crossterm"]
|
|
||||||
|
|
||||||
#! The following features are unstable and may change in the future:
|
|
||||||
|
|
||||||
## Enable all unstable features.
|
|
||||||
unstable = [
|
|
||||||
"unstable-rendered-line-info",
|
|
||||||
"unstable-widget-ref",
|
|
||||||
"unstable-backend-writer",
|
|
||||||
]
|
|
||||||
|
|
||||||
## 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 = []
|
|
||||||
|
|
||||||
## Enables the [`WidgetRef`](widgets::WidgetRef) and [`StatefulWidgetRef`](widgets::StatefulWidgetRef) traits which are experimental and may change in
|
|
||||||
## the future.
|
|
||||||
unstable-widget-ref = []
|
|
||||||
|
|
||||||
## Enables getting access to backends' writers.
|
|
||||||
unstable-backend-writer = []
|
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
|
||||||
all-features = true
|
|
||||||
# see https://doc.rust-lang.org/nightly/rustdoc/scraped-examples.html
|
|
||||||
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
|
|
||||||
rustdoc-args = ["--cfg", "docsrs"]
|
|
||||||
|
|
||||||
# Improve benchmark consistency
|
|
||||||
[profile.bench]
|
|
||||||
codegen-units = 1
|
|
||||||
lto = true
|
|
||||||
|
|
||||||
[lib]
|
|
||||||
bench = false
|
|
||||||
|
|
||||||
[[bench]]
|
|
||||||
name = "main"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "async"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "barchart"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "barchart-grouped"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "block"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "calendar"
|
|
||||||
required-features = ["crossterm", "widget-calendar"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "canvas"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "chart"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "colors"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
# this example is a bit verbose, so we don't want to include it in the docs
|
|
||||||
doc-scrape-examples = false
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "colors_rgb"
|
|
||||||
required-features = ["crossterm", "palette"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "constraint-explorer"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "constraints"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = false
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "custom_widget"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "demo"
|
|
||||||
# this runs for all of the terminal backends, so it can't be built using --all-features or scraped
|
|
||||||
doc-scrape-examples = false
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "demo2"
|
|
||||||
required-features = ["crossterm", "palette", "widget-calendar"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "docsrs"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = false
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "flex"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "gauge"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "hello_world"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "inline"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "layout"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "line_gauge"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "hyperlink"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "list"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "minimal"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
# prefer to show the more featureful examples in the docs
|
|
||||||
doc-scrape-examples = false
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "modifiers"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
# this example is a bit verbose, so we don't want to include it in the docs
|
|
||||||
doc-scrape-examples = false
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "panic"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "paragraph"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "popup"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "ratatui-logo"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "scrollbar"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "sparkline"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "table"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "tabs"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "tracing"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "user_input"
|
|
||||||
required-features = ["crossterm"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[example]]
|
|
||||||
name = "widget_impl"
|
|
||||||
required-features = ["crossterm", "unstable-widget-ref"]
|
|
||||||
doc-scrape-examples = true
|
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "state_serde"
|
|
||||||
required-features = ["serde"]
|
|
||||||
|
|
50
ratatui-core/Cargo.toml
Normal file
50
ratatui-core/Cargo.toml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
[package]
|
||||||
|
name = "ratatui-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
underline-color = []
|
||||||
|
unstable-widget-ref = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags.workspace = true
|
||||||
|
cassowary.workspace = true
|
||||||
|
compact_str.workspace = true
|
||||||
|
document-features.workspace = true
|
||||||
|
instability.workspace = true
|
||||||
|
itertools.workspace = true
|
||||||
|
lru.workspace = true
|
||||||
|
paste.workspace = true
|
||||||
|
palette = { workspace = true, optional = true }
|
||||||
|
serde = { workspace = true, optional = true, features = ["derive"] }
|
||||||
|
strum = { workspace = true, features = ["derive"] }
|
||||||
|
termwiz = { workspace = true, optional = true }
|
||||||
|
unicode-segmentation.workspace = true
|
||||||
|
unicode-truncate.workspace = true
|
||||||
|
unicode-width.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
argh = "0.1.12"
|
||||||
|
color-eyre = "0.6.2"
|
||||||
|
criterion = { version = "0.5.1", features = ["html_reports"] }
|
||||||
|
crossterm = { version = "0.28.1", features = ["event-stream"] }
|
||||||
|
fakeit = "1.1"
|
||||||
|
font8x8 = "0.3.1"
|
||||||
|
futures = "0.3.30"
|
||||||
|
indoc = "2"
|
||||||
|
octocrab = "0.40.0"
|
||||||
|
pretty_assertions = "1.4.0"
|
||||||
|
rand = "0.8.5"
|
||||||
|
rand_chacha = "0.3.1"
|
||||||
|
rstest = "0.22.0"
|
||||||
|
serde_json = "1.0.109"
|
||||||
|
tokio = { version = "1.39.2", features = [
|
||||||
|
"rt",
|
||||||
|
"macros",
|
||||||
|
"time",
|
||||||
|
"rt-multi-thread",
|
||||||
|
] }
|
||||||
|
tracing = "0.1.40"
|
||||||
|
tracing-appender = "0.2.3"
|
||||||
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
|
@ -109,21 +109,6 @@ use crate::{
|
||||||
layout::{Position, Size},
|
layout::{Position, Size},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(all(not(windows), feature = "termion"))]
|
|
||||||
mod termion;
|
|
||||||
#[cfg(all(not(windows), feature = "termion"))]
|
|
||||||
pub use self::termion::TermionBackend;
|
|
||||||
|
|
||||||
#[cfg(feature = "crossterm")]
|
|
||||||
mod crossterm;
|
|
||||||
#[cfg(feature = "crossterm")]
|
|
||||||
pub use self::crossterm::CrosstermBackend;
|
|
||||||
|
|
||||||
#[cfg(feature = "termwiz")]
|
|
||||||
mod termwiz;
|
|
||||||
#[cfg(feature = "termwiz")]
|
|
||||||
pub use self::termwiz::TermwizBackend;
|
|
||||||
|
|
||||||
mod test;
|
mod test;
|
||||||
pub use self::test::TestBackend;
|
pub use self::test::TestBackend;
|
||||||
|
|
|
@ -1295,7 +1295,7 @@ mod tests {
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::flex::Flex,
|
layout::flex::Flex,
|
||||||
prelude::{Constraint::*, *},
|
prelude::{Constraint::*, *},
|
||||||
widgets::Paragraph,
|
// widgets::Paragraph, // TODO
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Test that the given constraints applied to the given area result in the expected layout.
|
/// Test that the given constraints applied to the given area result in the expected layout.
|
||||||
|
@ -1317,7 +1317,7 @@ mod tests {
|
||||||
let mut buffer = Buffer::empty(area);
|
let mut buffer = Buffer::empty(area);
|
||||||
for (c, &area) in ('a'..='z').take(constraints.len()).zip(layout.iter()) {
|
for (c, &area) in ('a'..='z').take(constraints.len()).zip(layout.iter()) {
|
||||||
let s = c.to_string().repeat(area.width as usize);
|
let s = c.to_string().repeat(area.width as usize);
|
||||||
Paragraph::new(s).render(area, &mut buffer);
|
// Paragraph::new(s).render(area, &mut buffer); // TODO
|
||||||
}
|
}
|
||||||
assert_eq!(buffer, Buffer::with_lines([expected]));
|
assert_eq!(buffer, Buffer::with_lines([expected]));
|
||||||
}
|
}
|
41
ratatui-core/src/prelude.rs
Normal file
41
ratatui-core/src/prelude.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//! A prelude for conveniently writing applications using this library.
|
||||||
|
//!
|
||||||
|
//! ```rust,no_run
|
||||||
|
//! use ratatui::prelude::*;
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Aside from the main types that are used in the library, this prelude also re-exports several
|
||||||
|
//! modules to make it easy to qualify types that would otherwise collide. E.g.:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! use ratatui::{prelude::*, widgets::*};
|
||||||
|
//!
|
||||||
|
//! #[derive(Debug, Default, PartialEq, Eq)]
|
||||||
|
//! struct Line;
|
||||||
|
//!
|
||||||
|
//! assert_eq!(Line::default(), Line);
|
||||||
|
//! assert_eq!(text::Line::default(), ratatui::text::Line::from(vec![]));
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
// TODO: re-export the following modules:
|
||||||
|
// #[cfg(feature = "crossterm")]
|
||||||
|
// pub use crate::backend::CrosstermBackend;
|
||||||
|
// #[cfg(all(not(windows), feature = "termion"))]
|
||||||
|
// pub use crate::backend::TermionBackend;
|
||||||
|
// #[cfg(feature = "termwiz")]
|
||||||
|
// pub use crate::backend::TermwizBackend;
|
||||||
|
pub(crate) use crate::widgets::{StatefulWidgetRef, WidgetRef};
|
||||||
|
pub use crate::{
|
||||||
|
backend::{self, Backend},
|
||||||
|
buffer::{self, Buffer},
|
||||||
|
layout::{self, Alignment, Constraint, Direction, Layout, Margin, Position, Rect, Size},
|
||||||
|
style::{self, Color, Modifier, Style, Stylize},
|
||||||
|
symbols::{self},
|
||||||
|
text::{self, Line, Masked, Span, Text},
|
||||||
|
widgets::{
|
||||||
|
// block::BlockExt, // TODO
|
||||||
|
StatefulWidget,
|
||||||
|
Widget,
|
||||||
|
},
|
||||||
|
Frame, Terminal,
|
||||||
|
};
|
|
@ -32,15 +32,9 @@
|
||||||
//! [`Buffer`]: crate::buffer::Buffer
|
//! [`Buffer`]: crate::buffer::Buffer
|
||||||
|
|
||||||
mod frame;
|
mod frame;
|
||||||
#[cfg(feature = "crossterm")]
|
|
||||||
mod init;
|
|
||||||
mod terminal;
|
mod terminal;
|
||||||
mod viewport;
|
mod viewport;
|
||||||
|
|
||||||
pub use frame::{CompletedFrame, Frame};
|
pub use frame::{CompletedFrame, Frame};
|
||||||
#[cfg(feature = "crossterm")]
|
|
||||||
pub use init::{
|
|
||||||
init, init_with_options, restore, try_init, try_init_with_options, try_restore, DefaultTerminal,
|
|
||||||
};
|
|
||||||
pub use terminal::{Options as TerminalOptions, Terminal};
|
pub use terminal::{Options as TerminalOptions, Terminal};
|
||||||
pub use viewport::Viewport;
|
pub use viewport::Viewport;
|
|
@ -26,7 +26,7 @@ impl<'a> StyledGrapheme<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_whitespace(&self) -> bool {
|
pub fn is_whitespace(&self) -> bool {
|
||||||
let symbol = self.symbol;
|
let symbol = self.symbol;
|
||||||
symbol == ZWSP || symbol.chars().all(char::is_whitespace) && symbol != NBSP
|
symbol == ZWSP || symbol.chars().all(char::is_whitespace) && symbol != NBSP
|
||||||
}
|
}
|
|
@ -21,37 +21,7 @@
|
||||||
//! - [`Tabs`]: displays a tab bar and allows selection.
|
//! - [`Tabs`]: displays a tab bar and allows selection.
|
||||||
//!
|
//!
|
||||||
//! [`Canvas`]: crate::widgets::canvas::Canvas
|
//! [`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 paragraph;
|
|
||||||
mod reflow;
|
|
||||||
mod scrollbar;
|
|
||||||
mod sparkline;
|
|
||||||
mod table;
|
|
||||||
mod tabs;
|
|
||||||
|
|
||||||
pub use self::{
|
|
||||||
barchart::{Bar, BarChart, BarGroup},
|
|
||||||
block::{Block, BorderType, Padding},
|
|
||||||
borders::*,
|
|
||||||
chart::{Axis, Chart, Dataset, GraphType, LegendPosition},
|
|
||||||
clear::Clear,
|
|
||||||
gauge::{Gauge, LineGauge},
|
|
||||||
list::{List, ListDirection, ListItem, ListState},
|
|
||||||
paragraph::{Paragraph, Wrap},
|
|
||||||
scrollbar::{ScrollDirection, Scrollbar, ScrollbarOrientation, ScrollbarState},
|
|
||||||
sparkline::{RenderDirection, Sparkline},
|
|
||||||
table::{Cell, HighlightSpacing, Row, Table, TableState},
|
|
||||||
tabs::Tabs,
|
|
||||||
};
|
|
||||||
use crate::{buffer::Buffer, layout::Rect, style::Style};
|
use crate::{buffer::Buffer, layout::Rect, style::Style};
|
||||||
|
|
||||||
/// A `Widget` is a type that can be drawn on a [`Buffer`] in a given [`Rect`].
|
/// A `Widget` is a type that can be drawn on a [`Buffer`] in a given [`Rect`].
|
20
ratatui-crossterm/Cargo.toml
Normal file
20
ratatui-crossterm/Cargo.toml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "ratatui-crossterm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["underline-color"]
|
||||||
|
|
||||||
|
## enables the backend code that sets the underline color.
|
||||||
|
## Underline color is only supported by the [`CrosstermBackend`](backend::CrosstermBackend) backend,
|
||||||
|
## and is not supported on Windows 7.
|
||||||
|
underline-color = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ratatui-core = { workspace = true }
|
||||||
|
crossterm.workspace = true
|
||||||
|
instability.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
rstest.workspace = true
|
681
ratatui-crossterm/src/lib.rs
Normal file
681
ratatui-crossterm/src/lib.rs
Normal file
|
@ -0,0 +1,681 @@
|
||||||
|
//! This module provides the [`CrosstermBackend`] implementation for the [`Backend`] trait. It uses
|
||||||
|
//! the [Crossterm] crate to interact with the terminal.
|
||||||
|
//!
|
||||||
|
//! [Crossterm]: https://crates.io/crates/crossterm
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
#[cfg(feature = "underline-color")]
|
||||||
|
use crossterm::style::SetUnderlineColor;
|
||||||
|
use crossterm::{
|
||||||
|
cursor::{Hide, MoveTo, Show},
|
||||||
|
execute, queue,
|
||||||
|
style::{
|
||||||
|
Attribute as CrosstermAttribute, Attributes as CrosstermAttributes,
|
||||||
|
Color as CrosstermColor, Colors, ContentStyle, Print, SetAttribute, SetBackgroundColor,
|
||||||
|
SetColors, SetForegroundColor,
|
||||||
|
},
|
||||||
|
terminal::{self, Clear},
|
||||||
|
};
|
||||||
|
use ratatui_core::{
|
||||||
|
backend::{Backend, ClearType, WindowSize},
|
||||||
|
buffer::Cell,
|
||||||
|
layout::{Position, Size},
|
||||||
|
style::{Color, Modifier, Style},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A [`Backend`] implementation that uses [Crossterm] to render to the terminal.
|
||||||
|
///
|
||||||
|
/// The `CrosstermBackend` struct is a wrapper around a writer implementing [`Write`], which is
|
||||||
|
/// used to send commands to the terminal. It provides methods for drawing content, manipulating
|
||||||
|
/// the cursor, and clearing the terminal screen.
|
||||||
|
///
|
||||||
|
/// Most applications should not call the methods on `CrosstermBackend` directly, but will instead
|
||||||
|
/// use the [`Terminal`] struct, which provides a more ergonomic interface.
|
||||||
|
///
|
||||||
|
/// Usually applications will enable raw mode and switch to alternate screen mode after creating
|
||||||
|
/// a `CrosstermBackend`. This is done by calling [`crossterm::terminal::enable_raw_mode`] and
|
||||||
|
/// [`crossterm::terminal::EnterAlternateScreen`] (and the corresponding disable/leave functions
|
||||||
|
/// when the application exits). This is not done automatically by the backend because it is
|
||||||
|
/// possible that the application may want to use the terminal for other purposes (like showing
|
||||||
|
/// help text) before entering alternate screen mode.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// use std::io::{stderr, stdout};
|
||||||
|
///
|
||||||
|
/// use ratatui::{
|
||||||
|
/// crossterm::{
|
||||||
|
/// terminal::{
|
||||||
|
/// disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
|
||||||
|
/// },
|
||||||
|
/// ExecutableCommand,
|
||||||
|
/// },
|
||||||
|
/// prelude::*,
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// let mut backend = CrosstermBackend::new(stdout());
|
||||||
|
/// // or
|
||||||
|
/// let backend = CrosstermBackend::new(stderr());
|
||||||
|
/// let mut terminal = Terminal::new(backend)?;
|
||||||
|
///
|
||||||
|
/// enable_raw_mode()?;
|
||||||
|
/// stdout().execute(EnterAlternateScreen)?;
|
||||||
|
///
|
||||||
|
/// terminal.clear()?;
|
||||||
|
/// terminal.draw(|frame| {
|
||||||
|
/// // -- snip --
|
||||||
|
/// })?;
|
||||||
|
///
|
||||||
|
/// stdout().execute(LeaveAlternateScreen)?;
|
||||||
|
/// disable_raw_mode()?;
|
||||||
|
///
|
||||||
|
/// # std::io::Result::Ok(())
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// See the the [Examples] directory for more examples. See the [`backend`] module documentation
|
||||||
|
/// for more details on raw mode and alternate screen.
|
||||||
|
///
|
||||||
|
/// [`Write`]: std::io::Write
|
||||||
|
/// [`Terminal`]: crate::terminal::Terminal
|
||||||
|
/// [`backend`]: crate::backend
|
||||||
|
/// [Crossterm]: https://crates.io/crates/crossterm
|
||||||
|
/// [Examples]: https://github.com/ratatui/ratatui/tree/main/examples/README.md
|
||||||
|
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||||
|
pub struct CrosstermBackend<W: Write> {
|
||||||
|
/// The writer used to send commands to the terminal.
|
||||||
|
writer: W,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W> CrosstermBackend<W>
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
/// Creates a new `CrosstermBackend` with the given writer.
|
||||||
|
///
|
||||||
|
/// Most applications will use either [`stdout`](std::io::stdout) or
|
||||||
|
/// [`stderr`](std::io::stderr) as writer. See the [FAQ] to determine which one to use.
|
||||||
|
///
|
||||||
|
/// [FAQ]: https://ratatui.rs/faq/#should-i-use-stdout-or-stderr
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
|
/// ```rust,no_run
|
||||||
|
/// # use std::io::stdout;
|
||||||
|
/// # use ratatui::prelude::*;
|
||||||
|
/// let backend = CrosstermBackend::new(stdout());
|
||||||
|
/// ```
|
||||||
|
pub const fn new(writer: W) -> Self {
|
||||||
|
Self { writer }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the writer.
|
||||||
|
#[instability::unstable(
|
||||||
|
feature = "backend-writer",
|
||||||
|
issue = "https://github.com/ratatui/ratatui/pull/991"
|
||||||
|
)]
|
||||||
|
pub const fn writer(&self) -> &W {
|
||||||
|
&self.writer
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the writer as a mutable reference.
|
||||||
|
///
|
||||||
|
/// Note: writing to the writer may cause incorrect output after the write. This is due to the
|
||||||
|
/// way that the Terminal implements diffing Buffers.
|
||||||
|
#[instability::unstable(
|
||||||
|
feature = "backend-writer",
|
||||||
|
issue = "https://github.com/ratatui/ratatui/pull/991"
|
||||||
|
)]
|
||||||
|
pub fn writer_mut(&mut self) -> &mut W {
|
||||||
|
&mut self.writer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W> Write for CrosstermBackend<W>
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
/// Writes a buffer of bytes to the underlying buffer.
|
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
self.writer.write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Flushes the underlying buffer.
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
self.writer.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<W> Backend for CrosstermBackend<W>
|
||||||
|
where
|
||||||
|
W: Write,
|
||||||
|
{
|
||||||
|
fn draw<'a, I>(&mut self, content: I) -> io::Result<()>
|
||||||
|
where
|
||||||
|
I: Iterator<Item = (u16, u16, &'a Cell)>,
|
||||||
|
{
|
||||||
|
let mut fg = Color::Reset;
|
||||||
|
let mut bg = Color::Reset;
|
||||||
|
#[cfg(feature = "underline-color")]
|
||||||
|
let mut underline_color = Color::Reset;
|
||||||
|
let mut modifier = Modifier::empty();
|
||||||
|
let mut last_pos: Option<Position> = None;
|
||||||
|
for (x, y, cell) in content {
|
||||||
|
// Move the cursor if the previous location was not (x - 1, y)
|
||||||
|
if !matches!(last_pos, Some(p) if x == p.x + 1 && y == p.y) {
|
||||||
|
queue!(self.writer, MoveTo(x, y))?;
|
||||||
|
}
|
||||||
|
last_pos = Some(Position { x, y });
|
||||||
|
if cell.modifier != modifier {
|
||||||
|
let diff = ModifierDiff {
|
||||||
|
from: modifier,
|
||||||
|
to: cell.modifier,
|
||||||
|
};
|
||||||
|
diff.queue(&mut self.writer)?;
|
||||||
|
modifier = cell.modifier;
|
||||||
|
}
|
||||||
|
if cell.fg != fg || cell.bg != bg {
|
||||||
|
queue!(
|
||||||
|
self.writer,
|
||||||
|
SetColors(Colors::new(
|
||||||
|
from_ratatui_color(cell.fg),
|
||||||
|
from_ratatui_color(cell.bg)
|
||||||
|
))
|
||||||
|
)?;
|
||||||
|
fg = cell.fg;
|
||||||
|
bg = cell.bg;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "underline-color")]
|
||||||
|
if cell.underline_color != underline_color {
|
||||||
|
let color = from_ratatui_color(cell.underline_color);
|
||||||
|
queue!(self.writer, SetUnderlineColor(color))?;
|
||||||
|
underline_color = cell.underline_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
queue!(self.writer, Print(cell.symbol()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "underline-color")]
|
||||||
|
return queue!(
|
||||||
|
self.writer,
|
||||||
|
SetForegroundColor(CrosstermColor::Reset),
|
||||||
|
SetBackgroundColor(CrosstermColor::Reset),
|
||||||
|
SetUnderlineColor(CrosstermColor::Reset),
|
||||||
|
SetAttribute(CrosstermAttribute::Reset),
|
||||||
|
);
|
||||||
|
#[cfg(not(feature = "underline-color"))]
|
||||||
|
return queue!(
|
||||||
|
self.writer,
|
||||||
|
SetForegroundColor(CrosstermColor::Reset),
|
||||||
|
SetBackgroundColor(CrosstermColor::Reset),
|
||||||
|
SetAttribute(CrosstermAttribute::Reset),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hide_cursor(&mut self) -> io::Result<()> {
|
||||||
|
execute!(self.writer, Hide)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_cursor(&mut self) -> io::Result<()> {
|
||||||
|
execute!(self.writer, Show)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_cursor_position(&mut self) -> io::Result<Position> {
|
||||||
|
crossterm::cursor::position()
|
||||||
|
.map(|(x, y)| Position { x, y })
|
||||||
|
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> io::Result<()> {
|
||||||
|
let Position { x, y } = position.into();
|
||||||
|
execute!(self.writer, MoveTo(x, y))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) -> io::Result<()> {
|
||||||
|
self.clear_region(ClearType::All)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_region(&mut self, clear_type: ClearType) -> io::Result<()> {
|
||||||
|
execute!(
|
||||||
|
self.writer,
|
||||||
|
Clear(match clear_type {
|
||||||
|
ClearType::All => crossterm::terminal::ClearType::All,
|
||||||
|
ClearType::AfterCursor => crossterm::terminal::ClearType::FromCursorDown,
|
||||||
|
ClearType::BeforeCursor => crossterm::terminal::ClearType::FromCursorUp,
|
||||||
|
ClearType::CurrentLine => crossterm::terminal::ClearType::CurrentLine,
|
||||||
|
ClearType::UntilNewLine => crossterm::terminal::ClearType::UntilNewLine,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn append_lines(&mut self, n: u16) -> io::Result<()> {
|
||||||
|
for _ in 0..n {
|
||||||
|
queue!(self.writer, Print("\n"))?;
|
||||||
|
}
|
||||||
|
self.writer.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> io::Result<Size> {
|
||||||
|
let (width, height) = terminal::size()?;
|
||||||
|
Ok(Size { width, height })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_size(&mut self) -> io::Result<WindowSize> {
|
||||||
|
let crossterm::terminal::WindowSize {
|
||||||
|
columns,
|
||||||
|
rows,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
} = terminal::window_size()?;
|
||||||
|
Ok(WindowSize {
|
||||||
|
columns_rows: Size {
|
||||||
|
width: columns,
|
||||||
|
height: rows,
|
||||||
|
},
|
||||||
|
pixels: Size { width, height },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
self.writer.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_ratatui_color(color: Color) -> CrosstermColor {
|
||||||
|
match color {
|
||||||
|
Color::Reset => CrosstermColor::Reset,
|
||||||
|
Color::Black => CrosstermColor::Black,
|
||||||
|
Color::Red => CrosstermColor::DarkRed,
|
||||||
|
Color::Green => CrosstermColor::DarkGreen,
|
||||||
|
Color::Yellow => CrosstermColor::DarkYellow,
|
||||||
|
Color::Blue => CrosstermColor::DarkBlue,
|
||||||
|
Color::Magenta => CrosstermColor::DarkMagenta,
|
||||||
|
Color::Cyan => CrosstermColor::DarkCyan,
|
||||||
|
Color::Gray => CrosstermColor::Grey,
|
||||||
|
Color::DarkGray => CrosstermColor::DarkGrey,
|
||||||
|
Color::LightRed => CrosstermColor::Red,
|
||||||
|
Color::LightGreen => CrosstermColor::Green,
|
||||||
|
Color::LightBlue => CrosstermColor::Blue,
|
||||||
|
Color::LightYellow => CrosstermColor::Yellow,
|
||||||
|
Color::LightMagenta => CrosstermColor::Magenta,
|
||||||
|
Color::LightCyan => CrosstermColor::Cyan,
|
||||||
|
Color::White => CrosstermColor::White,
|
||||||
|
Color::Indexed(i) => CrosstermColor::AnsiValue(i),
|
||||||
|
Color::Rgb(r, g, b) => CrosstermColor::Rgb { r, g, b },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_crossterm_color(value: CrosstermColor) -> Color {
|
||||||
|
match value {
|
||||||
|
CrosstermColor::Reset => Color::Reset,
|
||||||
|
CrosstermColor::Black => Color::Black,
|
||||||
|
CrosstermColor::DarkRed => Color::Red,
|
||||||
|
CrosstermColor::DarkGreen => Color::Green,
|
||||||
|
CrosstermColor::DarkYellow => Color::Yellow,
|
||||||
|
CrosstermColor::DarkBlue => Color::Blue,
|
||||||
|
CrosstermColor::DarkMagenta => Color::Magenta,
|
||||||
|
CrosstermColor::DarkCyan => Color::Cyan,
|
||||||
|
CrosstermColor::Grey => Color::Gray,
|
||||||
|
CrosstermColor::DarkGrey => Color::DarkGray,
|
||||||
|
CrosstermColor::Red => Color::LightRed,
|
||||||
|
CrosstermColor::Green => Color::LightGreen,
|
||||||
|
CrosstermColor::Blue => Color::LightBlue,
|
||||||
|
CrosstermColor::Yellow => Color::LightYellow,
|
||||||
|
CrosstermColor::Magenta => Color::LightMagenta,
|
||||||
|
CrosstermColor::Cyan => Color::LightCyan,
|
||||||
|
CrosstermColor::White => Color::White,
|
||||||
|
CrosstermColor::Rgb { r, g, b } => Color::Rgb(r, g, b),
|
||||||
|
CrosstermColor::AnsiValue(v) => Color::Indexed(v),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The `ModifierDiff` struct is used to calculate the difference between two `Modifier`
|
||||||
|
/// values. This is useful when updating the terminal display, as it allows for more
|
||||||
|
/// efficient updates by only sending the necessary changes.
|
||||||
|
struct ModifierDiff {
|
||||||
|
pub from: Modifier,
|
||||||
|
pub to: Modifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModifierDiff {
|
||||||
|
fn queue<W>(self, mut w: W) -> io::Result<()>
|
||||||
|
where
|
||||||
|
W: io::Write,
|
||||||
|
{
|
||||||
|
//use crossterm::Attribute;
|
||||||
|
let removed = self.from - self.to;
|
||||||
|
if removed.contains(Modifier::REVERSED) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::NoReverse))?;
|
||||||
|
}
|
||||||
|
if removed.contains(Modifier::BOLD) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::NormalIntensity))?;
|
||||||
|
if self.to.contains(Modifier::DIM) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::Dim))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if removed.contains(Modifier::ITALIC) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::NoItalic))?;
|
||||||
|
}
|
||||||
|
if removed.contains(Modifier::UNDERLINED) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::NoUnderline))?;
|
||||||
|
}
|
||||||
|
if removed.contains(Modifier::DIM) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::NormalIntensity))?;
|
||||||
|
}
|
||||||
|
if removed.contains(Modifier::CROSSED_OUT) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::NotCrossedOut))?;
|
||||||
|
}
|
||||||
|
if removed.contains(Modifier::SLOW_BLINK) || removed.contains(Modifier::RAPID_BLINK) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::NoBlink))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let added = self.to - self.from;
|
||||||
|
if added.contains(Modifier::REVERSED) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::Reverse))?;
|
||||||
|
}
|
||||||
|
if added.contains(Modifier::BOLD) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::Bold))?;
|
||||||
|
}
|
||||||
|
if added.contains(Modifier::ITALIC) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::Italic))?;
|
||||||
|
}
|
||||||
|
if added.contains(Modifier::UNDERLINED) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::Underlined))?;
|
||||||
|
}
|
||||||
|
if added.contains(Modifier::DIM) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::Dim))?;
|
||||||
|
}
|
||||||
|
if added.contains(Modifier::CROSSED_OUT) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::CrossedOut))?;
|
||||||
|
}
|
||||||
|
if added.contains(Modifier::SLOW_BLINK) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::SlowBlink))?;
|
||||||
|
}
|
||||||
|
if added.contains(Modifier::RAPID_BLINK) {
|
||||||
|
queue!(w, SetAttribute(CrosstermAttribute::RapidBlink))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_crossterm_attribute(value: CrosstermAttribute) -> Modifier {
|
||||||
|
// `Attribute*s*` (note the *s*) contains multiple `Attribute`
|
||||||
|
// We convert `Attribute` to `Attribute*s*` (containing only 1 value) to avoid implementing
|
||||||
|
// the conversion again
|
||||||
|
from_crossterm_attributes(CrosstermAttributes::from(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_crossterm_attributes(value: CrosstermAttributes) -> Modifier {
|
||||||
|
let mut res = Modifier::empty();
|
||||||
|
|
||||||
|
if value.has(CrosstermAttribute::Bold) {
|
||||||
|
res |= Modifier::BOLD;
|
||||||
|
}
|
||||||
|
if value.has(CrosstermAttribute::Dim) {
|
||||||
|
res |= Modifier::DIM;
|
||||||
|
}
|
||||||
|
if value.has(CrosstermAttribute::Italic) {
|
||||||
|
res |= Modifier::ITALIC;
|
||||||
|
}
|
||||||
|
if value.has(CrosstermAttribute::Underlined)
|
||||||
|
|| value.has(CrosstermAttribute::DoubleUnderlined)
|
||||||
|
|| value.has(CrosstermAttribute::Undercurled)
|
||||||
|
|| value.has(CrosstermAttribute::Underdotted)
|
||||||
|
|| value.has(CrosstermAttribute::Underdashed)
|
||||||
|
{
|
||||||
|
res |= Modifier::UNDERLINED;
|
||||||
|
}
|
||||||
|
if value.has(CrosstermAttribute::SlowBlink) {
|
||||||
|
res |= Modifier::SLOW_BLINK;
|
||||||
|
}
|
||||||
|
if value.has(CrosstermAttribute::RapidBlink) {
|
||||||
|
res |= Modifier::RAPID_BLINK;
|
||||||
|
}
|
||||||
|
if value.has(CrosstermAttribute::Reverse) {
|
||||||
|
res |= Modifier::REVERSED;
|
||||||
|
}
|
||||||
|
if value.has(CrosstermAttribute::Hidden) {
|
||||||
|
res |= Modifier::HIDDEN;
|
||||||
|
}
|
||||||
|
if value.has(CrosstermAttribute::CrossedOut) {
|
||||||
|
res |= Modifier::CROSSED_OUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_crossterm_style(value: ContentStyle) -> Style {
|
||||||
|
let mut sub_modifier = Modifier::empty();
|
||||||
|
|
||||||
|
if value.attributes.has(CrosstermAttribute::NoBold) {
|
||||||
|
sub_modifier |= Modifier::BOLD;
|
||||||
|
}
|
||||||
|
if value.attributes.has(CrosstermAttribute::NoItalic) {
|
||||||
|
sub_modifier |= Modifier::ITALIC;
|
||||||
|
}
|
||||||
|
if value.attributes.has(CrosstermAttribute::NotCrossedOut) {
|
||||||
|
sub_modifier |= Modifier::CROSSED_OUT;
|
||||||
|
}
|
||||||
|
if value.attributes.has(CrosstermAttribute::NoUnderline) {
|
||||||
|
sub_modifier |= Modifier::UNDERLINED;
|
||||||
|
}
|
||||||
|
if value.attributes.has(CrosstermAttribute::NoHidden) {
|
||||||
|
sub_modifier |= Modifier::HIDDEN;
|
||||||
|
}
|
||||||
|
if value.attributes.has(CrosstermAttribute::NoBlink) {
|
||||||
|
sub_modifier |= Modifier::RAPID_BLINK | Modifier::SLOW_BLINK;
|
||||||
|
}
|
||||||
|
if value.attributes.has(CrosstermAttribute::NoReverse) {
|
||||||
|
sub_modifier |= Modifier::REVERSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
Style {
|
||||||
|
fg: value.foreground_color.map(from_crossterm_color),
|
||||||
|
bg: value.background_color.map(from_crossterm_color),
|
||||||
|
#[cfg(feature = "underline-color")]
|
||||||
|
underline_color: value.underline_color.map(from_crossterm_color),
|
||||||
|
add_modifier: from_crossterm_attributes(value.attributes),
|
||||||
|
sub_modifier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(CrosstermColor::Reset, Color::Reset)]
|
||||||
|
#[case(CrosstermColor::Black, Color::Black)]
|
||||||
|
#[case(CrosstermColor::DarkGrey, Color::DarkGray)]
|
||||||
|
#[case(CrosstermColor::Red, Color::LightRed)]
|
||||||
|
#[case(CrosstermColor::DarkRed, Color::Red)]
|
||||||
|
#[case(CrosstermColor::Green, Color::LightGreen)]
|
||||||
|
#[case(CrosstermColor::DarkGreen, Color::Green)]
|
||||||
|
#[case(CrosstermColor::Yellow, Color::LightYellow)]
|
||||||
|
#[case(CrosstermColor::DarkYellow, Color::Yellow)]
|
||||||
|
#[case(CrosstermColor::Blue, Color::LightBlue)]
|
||||||
|
#[case(CrosstermColor::DarkBlue, Color::Blue)]
|
||||||
|
#[case(CrosstermColor::Magenta, Color::LightMagenta)]
|
||||||
|
#[case(CrosstermColor::DarkMagenta, Color::Magenta)]
|
||||||
|
#[case(CrosstermColor::Cyan, Color::LightCyan)]
|
||||||
|
#[case(CrosstermColor::DarkCyan, Color::Cyan)]
|
||||||
|
#[case(CrosstermColor::White, Color::White)]
|
||||||
|
#[case(CrosstermColor::Grey, Color::Gray)]
|
||||||
|
#[case(CrosstermColor::Rgb { r: 0, g: 0, b: 0 }, Color::Rgb(0, 0, 0))]
|
||||||
|
#[case(CrosstermColor::Rgb { r: 10, g: 20, b: 30 }, Color::Rgb(10, 20, 30))]
|
||||||
|
#[case(CrosstermColor::AnsiValue(32), Color::Indexed(32))]
|
||||||
|
#[case(CrosstermColor::AnsiValue(37), Color::Indexed(37))]
|
||||||
|
fn convert_from_crossterm_color(#[case] value: CrosstermColor, #[case] expected: Color) {
|
||||||
|
assert_eq!(from_crossterm_color(value), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
mod modifier {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[rstest]
|
||||||
|
#[case(CrosstermAttribute::Reset, Modifier::empty())]
|
||||||
|
#[case(CrosstermAttribute::Bold, Modifier::BOLD)]
|
||||||
|
#[case(CrosstermAttribute::Italic, Modifier::ITALIC)]
|
||||||
|
#[case(CrosstermAttribute::Underlined, Modifier::UNDERLINED)]
|
||||||
|
#[case(CrosstermAttribute::DoubleUnderlined, Modifier::UNDERLINED)]
|
||||||
|
#[case(CrosstermAttribute::Underdotted, Modifier::UNDERLINED)]
|
||||||
|
#[case(CrosstermAttribute::Dim, Modifier::DIM)]
|
||||||
|
#[case(CrosstermAttribute::NormalIntensity, Modifier::empty())]
|
||||||
|
#[case(CrosstermAttribute::CrossedOut, Modifier::CROSSED_OUT)]
|
||||||
|
#[case(CrosstermAttribute::NoUnderline, Modifier::empty())]
|
||||||
|
#[case(CrosstermAttribute::OverLined, Modifier::empty())]
|
||||||
|
#[case(CrosstermAttribute::SlowBlink, Modifier::SLOW_BLINK)]
|
||||||
|
#[case(CrosstermAttribute::RapidBlink, Modifier::RAPID_BLINK)]
|
||||||
|
#[case(CrosstermAttribute::Hidden, Modifier::HIDDEN)]
|
||||||
|
#[case(CrosstermAttribute::NoHidden, Modifier::empty())]
|
||||||
|
#[case(CrosstermAttribute::Reverse, Modifier::REVERSED)]
|
||||||
|
fn convert_from_crossterm_attribute(
|
||||||
|
#[case] value: CrosstermAttribute,
|
||||||
|
#[case] expected: Modifier,
|
||||||
|
) {
|
||||||
|
assert_eq!(from_crossterm_attribute(value), expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(&[CrosstermAttribute::Bold], Modifier::BOLD)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::Bold, CrosstermAttribute::Italic],
|
||||||
|
Modifier::BOLD | Modifier::ITALIC
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::Bold, CrosstermAttribute::NotCrossedOut],
|
||||||
|
Modifier::BOLD
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::Dim, CrosstermAttribute::Underdotted],
|
||||||
|
Modifier::DIM | Modifier::UNDERLINED
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::Dim, CrosstermAttribute::SlowBlink, CrosstermAttribute::Italic],
|
||||||
|
Modifier::DIM | Modifier::SLOW_BLINK | Modifier::ITALIC
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::Hidden, CrosstermAttribute::NoUnderline, CrosstermAttribute::NotCrossedOut],
|
||||||
|
Modifier::HIDDEN
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::Reverse],
|
||||||
|
Modifier::REVERSED
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::Reset],
|
||||||
|
Modifier::empty()
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::RapidBlink, CrosstermAttribute::CrossedOut],
|
||||||
|
Modifier::RAPID_BLINK | Modifier::CROSSED_OUT
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::DoubleUnderlined, CrosstermAttribute::OverLined],
|
||||||
|
Modifier::UNDERLINED
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::Undercurled, CrosstermAttribute::Underdashed],
|
||||||
|
Modifier::UNDERLINED
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::NoBold, CrosstermAttribute::NoItalic],
|
||||||
|
Modifier::empty()
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
&[CrosstermAttribute::NoBlink, CrosstermAttribute::NoReverse],
|
||||||
|
Modifier::empty()
|
||||||
|
)]
|
||||||
|
fn convert_from_crossterm_attributes(
|
||||||
|
#[case] value: &[CrosstermAttribute],
|
||||||
|
#[case] expected: Modifier,
|
||||||
|
) {
|
||||||
|
assert_eq!(
|
||||||
|
from_crossterm_attributes(CrosstermAttributes::from(value)),
|
||||||
|
expected
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(ContentStyle::default(), Style::default())]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
foreground_color: Some(CrosstermColor::DarkYellow),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default().fg(Color::Yellow)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
background_color: Some(CrosstermColor::DarkYellow),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default().bg(Color::Yellow)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
attributes: CrosstermAttributes::from(CrosstermAttribute::Bold),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default().add_modifier(Modifier::BOLD)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
attributes: CrosstermAttributes::from(CrosstermAttribute::NoBold),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default().remove_modifier(Modifier::BOLD)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
attributes: CrosstermAttributes::from(CrosstermAttribute::Italic),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default().add_modifier(Modifier::ITALIC)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
attributes: CrosstermAttributes::from(CrosstermAttribute::NoItalic),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default().remove_modifier(Modifier::ITALIC)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
attributes: CrosstermAttributes::from(
|
||||||
|
[CrosstermAttribute::Bold, CrosstermAttribute::Italic].as_ref()
|
||||||
|
),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default()
|
||||||
|
.add_modifier(Modifier::BOLD)
|
||||||
|
.add_modifier(Modifier::ITALIC)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
attributes: CrosstermAttributes::from(
|
||||||
|
[CrosstermAttribute::NoBold, CrosstermAttribute::NoItalic].as_ref()
|
||||||
|
),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default()
|
||||||
|
.remove_modifier(Modifier::BOLD)
|
||||||
|
.remove_modifier(Modifier::ITALIC)
|
||||||
|
)]
|
||||||
|
#[cfg(feature = "underline-color")]
|
||||||
|
#[case(
|
||||||
|
ContentStyle {
|
||||||
|
underline_color: Some(CrosstermColor::DarkRed),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
Style::default().underline_color(Color::Red)
|
||||||
|
)]
|
||||||
|
fn convert_from_crossterm_content_style(#[case] value: ContentStyle, #[case] expected: Style) {
|
||||||
|
assert_eq!(from_crossterm_style(value), expected);
|
||||||
|
}
|
||||||
|
}
|
9
ratatui-termion/Cargo.toml
Normal file
9
ratatui-termion/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "ratatui-termion"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
instability = { workspace = true }
|
||||||
|
ratatui-core = { workspace = true }
|
||||||
|
termion.workspace = true
|
|
@ -9,13 +9,13 @@ use std::{
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use ratatui_core::{
|
||||||
backend::{Backend, ClearType, WindowSize},
|
backend::{Backend, ClearType, WindowSize},
|
||||||
buffer::Cell,
|
buffer::Cell,
|
||||||
layout::{Position, Size},
|
layout::{Position, Size},
|
||||||
style::{Color, Modifier, Style},
|
style::{Color, Modifier, Style},
|
||||||
termion::{self, color as tcolor, color::Color as _, style as tstyle},
|
|
||||||
};
|
};
|
||||||
|
use termion::{color as tcolor, color::Color as _, style as tstyle};
|
||||||
|
|
||||||
/// A [`Backend`] implementation that uses [Termion] to render to the terminal.
|
/// A [`Backend`] implementation that uses [Termion] to render to the terminal.
|
||||||
///
|
///
|
7
ratatui-termwiz/Cargo.toml
Normal file
7
ratatui-termwiz/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "ratatui-termwiz"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ratatui-core = { workspace = true }
|
40
ratatui-widgets/Cargo.toml
Normal file
40
ratatui-widgets/Cargo.toml
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
[package]
|
||||||
|
name = "ratatui-widgets"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# TODO: remove unstable-widget-ref, consider whether to keep all-widgets
|
||||||
|
default = ["all-widgets", "unstable-widget-ref"]
|
||||||
|
|
||||||
|
## 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", "bitflags/serde"]
|
||||||
|
|
||||||
|
|
||||||
|
## enables all widgets.
|
||||||
|
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"]
|
||||||
|
|
||||||
|
unstable-widget-ref = ["ratatui-core/unstable-widget-ref"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bitflags.workspace = true
|
||||||
|
instability.workspace = true
|
||||||
|
itertools.workspace = true
|
||||||
|
ratatui-core.workspace = true
|
||||||
|
serde = { workspace = true, optional = true }
|
||||||
|
strum.workspace = true
|
||||||
|
time = { workspace = true, optional = true }
|
||||||
|
unicode-segmentation.workspace = true
|
||||||
|
unicode-width.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
rstest.workspace = true
|
||||||
|
indoc.workspace = true
|
||||||
|
pretty_assertions.workspace = true
|
||||||
|
time.workspace = true
|
|
@ -1,4 +1,8 @@
|
||||||
use crate::{prelude::*, style::Styled, widgets::Block};
|
use ratatui_core::{
|
||||||
|
prelude::{symbols, Buffer, Direction, Line, Rect, Style, Stylize, Widget},
|
||||||
|
style::Styled,
|
||||||
|
widgets::WidgetRef,
|
||||||
|
};
|
||||||
|
|
||||||
mod bar;
|
mod bar;
|
||||||
mod bar_group;
|
mod bar_group;
|
||||||
|
@ -6,6 +10,8 @@ mod bar_group;
|
||||||
pub use bar::Bar;
|
pub use bar::Bar;
|
||||||
pub use bar_group::BarGroup;
|
pub use bar_group::BarGroup;
|
||||||
|
|
||||||
|
use crate::{block::BlockExt, Block};
|
||||||
|
|
||||||
/// A chart showing values as [bars](Bar).
|
/// A chart showing values as [bars](Bar).
|
||||||
///
|
///
|
||||||
/// Here is a possible `BarChart` output.
|
/// Here is a possible `BarChart` output.
|
||||||
|
@ -613,9 +619,14 @@ impl<'a> Styled for BarChart<'a> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use itertools::iproduct;
|
use itertools::iproduct;
|
||||||
|
use ratatui_core::{
|
||||||
|
layout::Alignment,
|
||||||
|
style::{Color, Modifier},
|
||||||
|
text::Span,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::widgets::BorderType;
|
use crate::BorderType;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn default() {
|
fn default() {
|
|
@ -1,8 +1,7 @@
|
||||||
|
use ratatui_core::prelude::{Buffer, Line, Rect, Style, Widget};
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use crate::prelude::*;
|
/// A bar to be shown by the [`BarChart`](crate::BarChart) widget.
|
||||||
|
|
||||||
/// A bar to be shown by the [`BarChart`](crate::widgets::BarChart) widget.
|
|
||||||
///
|
///
|
||||||
/// Here is an explanation of a `Bar`'s components.
|
/// Here is an explanation of a `Bar`'s components.
|
||||||
/// ```plain
|
/// ```plain
|
||||||
|
@ -61,7 +60,7 @@ impl<'a> Bar<'a> {
|
||||||
/// display the label **under** the bar.
|
/// display the label **under** the bar.
|
||||||
/// For [`Horizontal`](crate::layout::Direction::Horizontal) bars,
|
/// For [`Horizontal`](crate::layout::Direction::Horizontal) bars,
|
||||||
/// display the label **in** the bar.
|
/// display the label **in** the bar.
|
||||||
/// See [`BarChart::direction`](crate::widgets::BarChart::direction) to set the direction.
|
/// See [`BarChart::direction`](crate::BarChart::direction) to set the direction.
|
||||||
#[must_use = "method moves the value of self and returns the modified value"]
|
#[must_use = "method moves the value of self and returns the modified value"]
|
||||||
pub fn label(mut self, label: Line<'a>) -> Self {
|
pub fn label(mut self, label: Line<'a>) -> Self {
|
||||||
self.label = Some(label);
|
self.label = Some(label);
|
|
@ -1,5 +1,6 @@
|
||||||
|
use ratatui_core::prelude::*;
|
||||||
|
|
||||||
use super::Bar;
|
use super::Bar;
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
/// A group of bars to be shown by the Barchart.
|
/// A group of bars to be shown by the Barchart.
|
||||||
///
|
///
|
|
@ -6,15 +6,23 @@
|
||||||
//! [title](Block::title) and [padding](Block::padding).
|
//! [title](Block::title) and [padding](Block::padding).
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use ratatui_core::{
|
||||||
|
prelude::{Alignment, Buffer, Line, Rect, Style, Stylize, Widget},
|
||||||
|
style::Styled,
|
||||||
|
symbols::border,
|
||||||
|
widgets::WidgetRef,
|
||||||
|
};
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
|
|
||||||
use crate::{prelude::*, style::Styled, symbols::border, widgets::Borders};
|
use self::title::Position;
|
||||||
|
|
||||||
mod padding;
|
mod padding;
|
||||||
pub mod title;
|
pub mod title;
|
||||||
|
|
||||||
pub use padding::Padding;
|
pub use padding::Padding;
|
||||||
pub use title::{Position, Title};
|
pub use title::Title;
|
||||||
|
|
||||||
|
use crate::Borders;
|
||||||
|
|
||||||
/// 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 [upper level ones](crate::widgets).
|
||||||
///
|
///
|
||||||
|
@ -495,7 +503,7 @@ impl<'a> Block<'a> {
|
||||||
/// .style(Style::new().white().not_bold()); // will be white, and italic
|
/// .style(Style::new().white().not_bold()); // will be white, and italic
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Paragraph`]: crate::widgets::Paragraph
|
/// [`Paragraph`]: crate::Paragraph
|
||||||
#[must_use = "method moves the value of self and returns the modified value"]
|
#[must_use = "method moves the value of self and returns the modified value"]
|
||||||
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
|
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
|
||||||
self.style = style.into();
|
self.style = style.into();
|
||||||
|
@ -986,6 +994,7 @@ impl<'a> Styled for Block<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use ratatui_core::style::{Color, Modifier};
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use strum::ParseError;
|
use strum::ParseError;
|
||||||
|
|
||||||
|
@ -1244,7 +1253,7 @@ mod tests {
|
||||||
// .border_style(_DEFAULT_STYLE) // no longer const
|
// .border_style(_DEFAULT_STYLE) // no longer const
|
||||||
// .title_style(_DEFAULT_STYLE) // no longer const
|
// .title_style(_DEFAULT_STYLE) // no longer const
|
||||||
.title_alignment(Alignment::Left)
|
.title_alignment(Alignment::Left)
|
||||||
.title_position(Position::Top)
|
.title_position(crate::block::Position::Top)
|
||||||
.padding(_DEFAULT_PADDING);
|
.padding(_DEFAULT_PADDING);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
/// Padding::symmetric(5, 6);
|
/// Padding::symmetric(5, 6);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Block`]: crate::widgets::Block
|
/// [`Block`]: crate::Block
|
||||||
/// [`padding`]: crate::widgets::Block::padding
|
/// [`padding`]: crate::Block::padding
|
||||||
/// [CSS padding]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding
|
/// [CSS padding]: https://developer.mozilla.org/en-US/docs/Web/CSS/padding
|
||||||
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Padding {
|
pub struct Padding {
|
|
@ -1,11 +1,10 @@
|
||||||
//! This module holds the [`Title`] element and its related configuration types.
|
//! 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) configuration.
|
||||||
|
|
||||||
|
use ratatui_core::{layout::Alignment, text::Line};
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
|
|
||||||
use crate::{layout::Alignment, text::Line};
|
/// A [`Block`](crate::Block) title.
|
||||||
|
|
||||||
/// A [`Block`](crate::widgets::Block) title.
|
|
||||||
///
|
///
|
||||||
/// It can be aligned (see [`Alignment`]) and positioned (see [`Position`]).
|
/// 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>.
|
/// <https://github.com/ratatui/ratatui/issues/738>.
|
||||||
///
|
///
|
||||||
/// Use [`Line`] instead, when the position is not defined as part of the title. When a specific
|
/// 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
|
/// position is needed, use [`Block::title_top`](crate::Block::title_top) or
|
||||||
/// [`Block::title_bottom`](crate::widgets::Block::title_bottom) instead.
|
/// [`Block::title_bottom`](crate::Block::title_bottom) instead.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
|
@ -64,19 +63,19 @@ pub struct Title<'a> {
|
||||||
/// Title alignment
|
/// Title alignment
|
||||||
///
|
///
|
||||||
/// If [`None`], defaults to the alignment defined with
|
/// If [`None`], defaults to the alignment defined with
|
||||||
/// [`Block::title_alignment`](crate::widgets::Block::title_alignment) in the associated
|
/// [`Block::title_alignment`](crate::Block::title_alignment) in the associated
|
||||||
/// [`Block`](crate::widgets::Block).
|
/// [`Block`](crate::Block).
|
||||||
pub alignment: Option<Alignment>,
|
pub alignment: Option<Alignment>,
|
||||||
|
|
||||||
/// Title position
|
/// Title position
|
||||||
///
|
///
|
||||||
/// If [`None`], defaults to the position defined with
|
/// If [`None`], defaults to the position defined with
|
||||||
/// [`Block::title_position`](crate::widgets::Block::title_position) in the associated
|
/// [`Block::title_position`](crate::Block::title_position) in the associated
|
||||||
/// [`Block`](crate::widgets::Block).
|
/// [`Block`](crate::Block).
|
||||||
pub position: Option<Position>,
|
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.
|
/// The title can be positioned on top or at the bottom of the block.
|
||||||
/// Defaults to [`Position::Top`].
|
/// Defaults to [`Position::Top`].
|
|
@ -55,7 +55,7 @@ impl fmt::Debug for Borders {
|
||||||
/// and RIGHT.
|
/// and RIGHT.
|
||||||
///
|
///
|
||||||
/// When used with NONE you should consider omitting this completely. For ALL you should consider
|
/// 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::bordered) instead.
|
||||||
///
|
///
|
||||||
/// ## Examples
|
/// ## Examples
|
||||||
///
|
///
|
|
@ -10,9 +10,13 @@
|
||||||
//! [`Monthly`] has several controls for what should be displayed
|
//! [`Monthly`] has several controls for what should be displayed
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use ratatui_core::{
|
||||||
|
prelude::{Alignment, Buffer, Color, Constraint, Layout, Line, Rect, Span, Style, Widget},
|
||||||
|
widgets::WidgetRef,
|
||||||
|
};
|
||||||
use time::{Date, Duration, OffsetDateTime};
|
use time::{Date, Duration, OffsetDateTime};
|
||||||
|
|
||||||
use crate::{prelude::*, widgets::Block};
|
use crate::{block::BlockExt, Block};
|
||||||
|
|
||||||
/// Display a month calendar for the month containing `display_date`
|
/// Display a month calendar for the month containing `display_date`
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
|
@ -22,6 +22,12 @@ mod world;
|
||||||
use std::{fmt, iter::zip};
|
use std::{fmt, iter::zip};
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use ratatui_core::{
|
||||||
|
prelude::{Buffer, Color, Rect, Style, Widget},
|
||||||
|
symbols::{self, Marker},
|
||||||
|
text::Line as TextLine,
|
||||||
|
widgets::WidgetRef,
|
||||||
|
};
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
circle::Circle,
|
circle::Circle,
|
||||||
|
@ -30,7 +36,7 @@ pub use self::{
|
||||||
points::Points,
|
points::Points,
|
||||||
rectangle::Rectangle,
|
rectangle::Rectangle,
|
||||||
};
|
};
|
||||||
use crate::{prelude::*, symbols::Marker, text::Line as TextLine, widgets::Block};
|
use crate::block::{Block, BlockExt};
|
||||||
|
|
||||||
/// Something that can be drawn on a [`Canvas`].
|
/// Something that can be drawn on a [`Canvas`].
|
||||||
///
|
///
|
||||||
|
@ -425,7 +431,7 @@ impl<'a, 'b> From<&'a mut Context<'b>> for Painter<'a, 'b> {
|
||||||
/// This is used by the [`Canvas`] widget to draw shapes on the grid. It can be useful to think of
|
/// 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.
|
/// this as similar to the [`Frame`] struct that is used to draw widgets on the terminal.
|
||||||
///
|
///
|
||||||
/// [`Frame`]: crate::prelude::Frame
|
/// [`Frame`]: ratatui_core::prelude::Frame
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Context<'a> {
|
pub struct Context<'a> {
|
||||||
x_bounds: [f64; 2],
|
x_bounds: [f64; 2],
|
||||||
|
@ -809,9 +815,9 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
|
use ratatui_core::buffer::Cell;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::buffer::Cell;
|
|
||||||
|
|
||||||
// helper to test the canvas checks that drawing a vertical and horizontal line
|
// helper to test the canvas checks that drawing a vertical and horizontal line
|
||||||
// results in the expected output
|
// results in the expected output
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{
|
use ratatui_core::style::Color;
|
||||||
style::Color,
|
|
||||||
widgets::canvas::{Painter, Shape},
|
use crate::canvas::{Painter, Shape};
|
||||||
};
|
|
||||||
|
|
||||||
/// A circle with a given center and radius and with a given color
|
/// A circle with a given center and radius and with a given color
|
||||||
#[derive(Debug, Default, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone, PartialEq)]
|
||||||
|
@ -31,17 +30,12 @@ impl Shape for Circle {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{
|
use ratatui_core::{
|
||||||
buffer::Buffer,
|
buffer::Buffer, layout::Rect, style::Color, symbols::Marker, widgets::Widget,
|
||||||
layout::Rect,
|
|
||||||
style::Color,
|
|
||||||
symbols::Marker,
|
|
||||||
widgets::{
|
|
||||||
canvas::{Canvas, Circle},
|
|
||||||
Widget,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::canvas::{Canvas, Circle};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_it_draws_a_circle() {
|
fn test_it_draws_a_circle() {
|
||||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 5));
|
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 5));
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{
|
use ratatui_core::style::Color;
|
||||||
style::Color,
|
|
||||||
widgets::canvas::{Painter, Shape},
|
use crate::canvas::{Painter, Shape};
|
||||||
};
|
|
||||||
|
|
||||||
/// A line from `(x1, y1)` to `(x2, y2)` with the given color
|
/// A line from `(x1, y1)` to `(x2, y2)` with the given color
|
||||||
#[derive(Debug, Default, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone, PartialEq)]
|
||||||
|
@ -112,16 +111,18 @@ fn draw_line_high(painter: &mut Painter, x1: usize, y1: usize, x2: usize, y2: us
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use rstest::rstest;
|
use ratatui_core::{
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::{
|
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
layout::Rect,
|
layout::Rect,
|
||||||
style::{Style, Stylize},
|
style::{Style, Stylize},
|
||||||
symbols::Marker,
|
symbols::Marker,
|
||||||
widgets::{canvas::Canvas, Widget},
|
text,
|
||||||
|
widgets::Widget,
|
||||||
};
|
};
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::canvas::Canvas;
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::off_grid(&Line::new(-1.0, -1.0, 10.0, 10.0, Color::Red), [" "; 10])]
|
#[case::off_grid(&Line::new(-1.0, -1.0, 10.0, 10.0, Color::Red), [" "; 10])]
|
||||||
|
@ -207,7 +208,7 @@ mod tests {
|
||||||
fn tests<'expected_line, ExpectedLines>(#[case] line: &Line, #[case] expected: ExpectedLines)
|
fn tests<'expected_line, ExpectedLines>(#[case] line: &Line, #[case] expected: ExpectedLines)
|
||||||
where
|
where
|
||||||
ExpectedLines: IntoIterator,
|
ExpectedLines: IntoIterator,
|
||||||
ExpectedLines::Item: Into<crate::text::Line<'expected_line>>,
|
ExpectedLines::Item: Into<text::Line<'expected_line>>,
|
||||||
{
|
{
|
||||||
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 10));
|
let mut buffer = Buffer::empty(Rect::new(0, 0, 10, 10));
|
||||||
let canvas = Canvas::default()
|
let canvas = Canvas::default()
|
|
@ -1,13 +1,10 @@
|
||||||
|
use ratatui_core::style::Color;
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
|
|
||||||
use crate::{
|
use crate::canvas::{
|
||||||
style::Color,
|
world::{WORLD_HIGH_RESOLUTION, WORLD_LOW_RESOLUTION},
|
||||||
widgets::canvas::{
|
Painter, Shape,
|
||||||
world::{WORLD_HIGH_RESOLUTION, WORLD_LOW_RESOLUTION},
|
|
||||||
Painter, Shape,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Defines how many points are going to be used to draw a [`Map`].
|
/// Defines how many points are going to be used to draw a [`Map`].
|
||||||
///
|
///
|
||||||
/// You generally want a [high](MapResolution::High) resolution map.
|
/// You generally want a [high](MapResolution::High) resolution map.
|
||||||
|
@ -62,10 +59,14 @@ impl Shape for Map {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use ratatui_core::{
|
||||||
|
prelude::{Buffer, Color, Rect, Widget},
|
||||||
|
symbols::Marker,
|
||||||
|
};
|
||||||
use strum::ParseError;
|
use strum::ParseError;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{prelude::*, symbols::Marker, widgets::canvas::Canvas};
|
use crate::canvas::Canvas;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn map_resolution_to_string() {
|
fn map_resolution_to_string() {
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{
|
use ratatui_core::style::Color;
|
||||||
style::Color,
|
|
||||||
widgets::canvas::{Painter, Shape},
|
use crate::canvas::{Painter, Shape};
|
||||||
};
|
|
||||||
|
|
||||||
/// A group of points with a given color
|
/// A group of points with a given color
|
||||||
#[derive(Debug, Default, Clone, PartialEq)]
|
#[derive(Debug, Default, Clone, PartialEq)]
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{
|
use ratatui_core::style::Color;
|
||||||
style::Color,
|
|
||||||
widgets::canvas::{Line, Painter, Shape},
|
use crate::canvas::{Line, Painter, Shape};
|
||||||
};
|
|
||||||
|
|
||||||
/// A rectangle to draw on a [`Canvas`](super::Canvas)
|
/// A rectangle to draw on a [`Canvas`](super::Canvas)
|
||||||
///
|
///
|
||||||
|
@ -65,8 +64,10 @@ impl Shape for Rectangle {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use ratatui_core::{prelude::*, symbols::Marker};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{prelude::*, symbols::Marker, widgets::canvas::Canvas};
|
use crate::canvas::Canvas;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn draw_block_lines() {
|
fn draw_block_lines() {
|
|
@ -1,17 +1,13 @@
|
||||||
use std::{cmp::max, ops::Not};
|
use std::{cmp::max, ops::Not};
|
||||||
|
|
||||||
|
use ratatui_core::{layout::Flex, prelude::*, style::Styled, widgets::WidgetRef};
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
layout::Flex,
|
block::BlockExt,
|
||||||
prelude::*,
|
canvas::{Canvas, Line as CanvasLine, Points},
|
||||||
style::Styled,
|
Block,
|
||||||
widgets::{
|
|
||||||
canvas::{Canvas, Line as CanvasLine, Points},
|
|
||||||
Block,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An X or Y axis for the [`Chart`] widget
|
/// An X or Y axis for the [`Chart`] widget
|
||||||
///
|
///
|
||||||
/// An axis can have a [title](Axis::title) which will be displayed at the end of the axis. For an
|
/// An axis can have a [title](Axis::title) which will be displayed at the end of the axis. For an
|
||||||
|
@ -1074,7 +1070,7 @@ impl WidgetRef for Chart<'_> {
|
||||||
for (i, (dataset_name, dataset_style)) in self
|
for (i, (dataset_name, dataset_style)) in self
|
||||||
.datasets
|
.datasets
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|ds| Some((ds.name.as_ref()?, ds.style())))
|
.filter_map(|ds| Some((ds.name.as_ref()?, ds.style)))
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
let name = dataset_name.clone().patch_style(dataset_style);
|
let name = dataset_name.clone().patch_style(dataset_style);
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::prelude::*;
|
use ratatui_core::{prelude::*, widgets::WidgetRef};
|
||||||
|
|
||||||
/// A widget to clear/reset a certain area to allow overdrawing (e.g. for popups).
|
/// A widget to clear/reset a certain area to allow overdrawing (e.g. for popups).
|
||||||
///
|
///
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::{prelude::*, style::Styled, widgets::Block};
|
use ratatui_core::{prelude::*, style::Styled, widgets::WidgetRef};
|
||||||
|
|
||||||
|
use crate::{block::BlockExt, Block};
|
||||||
|
|
||||||
/// A widget to display a progress bar.
|
/// A widget to display a progress bar.
|
||||||
///
|
///
|
31
ratatui-widgets/src/lib.rs
Normal file
31
ratatui-widgets/src/lib.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
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 paragraph;
|
||||||
|
mod reflow;
|
||||||
|
mod scrollbar;
|
||||||
|
mod sparkline;
|
||||||
|
mod table;
|
||||||
|
mod tabs;
|
||||||
|
|
||||||
|
pub use self::{
|
||||||
|
barchart::{Bar, BarChart, BarGroup},
|
||||||
|
block::{Block, BorderType, Padding},
|
||||||
|
borders::*,
|
||||||
|
chart::{Axis, Chart, Dataset, GraphType, LegendPosition},
|
||||||
|
clear::Clear,
|
||||||
|
gauge::{Gauge, LineGauge},
|
||||||
|
list::{List, ListDirection, ListItem, ListState},
|
||||||
|
paragraph::{Paragraph, Wrap},
|
||||||
|
scrollbar::{ScrollDirection, Scrollbar, ScrollbarOrientation, ScrollbarState},
|
||||||
|
sparkline::{RenderDirection, Sparkline},
|
||||||
|
table::{Cell, HighlightSpacing, Row, Table, TableState},
|
||||||
|
tabs::Tabs,
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::prelude::*;
|
use ratatui_core::prelude::*;
|
||||||
|
|
||||||
/// A single item in a [`List`]
|
/// A single item in a [`List`]
|
||||||
///
|
///
|
||||||
|
@ -55,7 +55,7 @@ use crate::prelude::*;
|
||||||
/// ListItem::new(Text::from("foo").alignment(Alignment::Right));
|
/// ListItem::new(Text::from("foo").alignment(Alignment::Right));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`List`]: crate::widgets::List
|
/// [`List`]: crate::List
|
||||||
/// [`Stylize`]: crate::style::Stylize
|
/// [`Stylize`]: crate::style::Stylize
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct ListItem<'a> {
|
pub struct ListItem<'a> {
|
||||||
|
@ -94,8 +94,8 @@ impl<'a> ListItem<'a> {
|
||||||
///
|
///
|
||||||
/// # See also
|
/// # See also
|
||||||
///
|
///
|
||||||
/// - [`List::new`](crate::widgets::List::new) to create a list of items that can be converted
|
/// - [`List::new`](crate::List::new) to create a list of items that can be converted to
|
||||||
/// to [`ListItem`]
|
/// [`ListItem`]
|
||||||
pub fn new<T>(content: T) -> Self
|
pub fn new<T>(content: T) -> Self
|
||||||
where
|
where
|
||||||
T: Into<Text<'a>>,
|
T: Into<Text<'a>>,
|
||||||
|
@ -132,7 +132,7 @@ impl<'a> ListItem<'a> {
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`Styled`]: crate::style::Styled
|
/// [`Styled`]: crate::style::Styled
|
||||||
/// [`ListState`]: crate::widgets::list::ListState
|
/// [`ListState`]: crate::list::ListState
|
||||||
#[must_use = "method moves the value of self and returns the modified value"]
|
#[must_use = "method moves the value of self and returns the modified value"]
|
||||||
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
|
pub fn style<S: Into<Style>>(mut self, style: S) -> Self {
|
||||||
self.style = style.into();
|
self.style = style.into();
|
|
@ -1,11 +1,8 @@
|
||||||
|
use ratatui_core::{prelude::Style, style::Styled};
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
|
|
||||||
use super::ListItem;
|
use super::ListItem;
|
||||||
use crate::{
|
use crate::{Block, HighlightSpacing};
|
||||||
prelude::*,
|
|
||||||
style::Styled,
|
|
||||||
widgets::{Block, HighlightSpacing},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A widget to display several items among which one can be selected (optional)
|
/// A widget to display several items among which one can be selected (optional)
|
||||||
///
|
///
|
||||||
|
@ -15,7 +12,7 @@ use crate::{
|
||||||
/// the item's height is automatically determined. A `List` can also be put in reverse order (i.e.
|
/// 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.
|
/// *bottom to top*) whereas a [`Table`] cannot.
|
||||||
///
|
///
|
||||||
/// [`Table`]: crate::widgets::Table
|
/// [`Table`]: crate::Table
|
||||||
///
|
///
|
||||||
/// List items can be aligned using [`Text::alignment`], for more details see [`ListItem`].
|
/// List items can be aligned using [`Text::alignment`], for more details see [`ListItem`].
|
||||||
///
|
///
|
||||||
|
@ -85,9 +82,9 @@ use crate::{
|
||||||
/// (0..5).map(|i| format!("Item{i}")).collect::<List>();
|
/// (0..5).map(|i| format!("Item{i}")).collect::<List>();
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`ListState`]: crate::widgets::list::ListState
|
/// [`ListState`]: crate::list::ListState
|
||||||
/// [scroll]: crate::widgets::list::ListState::offset
|
/// [scroll]: crate::list::ListState::offset
|
||||||
/// [select]: crate::widgets::list::ListState::select
|
/// [select]: crate::list::ListState::select
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
|
||||||
pub struct List<'a> {
|
pub struct List<'a> {
|
||||||
/// An optional block to wrap the widget in
|
/// An optional block to wrap the widget in
|
||||||
|
@ -421,6 +418,7 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
use ratatui_core::style::{Color, Modifier, Stylize};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
use ratatui_core::{
|
||||||
|
prelude::{Buffer, Rect, StatefulWidget, Widget},
|
||||||
|
widgets::{StatefulWidgetRef, WidgetRef},
|
||||||
|
};
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{block::BlockExt, List, ListDirection, ListState};
|
||||||
prelude::{Buffer, Rect, StatefulWidget, StatefulWidgetRef, Widget, WidgetRef},
|
|
||||||
widgets::{block::BlockExt, List, ListDirection, ListState},
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Widget for List<'_> {
|
impl Widget for List<'_> {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
|
@ -269,13 +270,11 @@ impl List<'_> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
use ratatui_core::prelude::*;
|
||||||
use rstest::{fixture, rstest};
|
use rstest::{fixture, rstest};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{Block, HighlightSpacing, ListItem};
|
||||||
prelude::*,
|
|
||||||
widgets::{Block, HighlightSpacing, ListItem},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[fixture]
|
#[fixture]
|
||||||
fn single_line_buf() -> Buffer {
|
fn single_line_buf() -> Buffer {
|
|
@ -36,7 +36,7 @@
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// [`List`]: crate::widgets::List
|
/// [`List`]: crate::List
|
||||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct ListState {
|
pub struct ListState {
|
||||||
|
@ -258,7 +258,7 @@ impl ListState {
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
use crate::widgets::ListState;
|
use crate::ListState;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn selected() {
|
fn selected() {
|
|
@ -1,13 +1,10 @@
|
||||||
|
use ratatui_core::{prelude::*, style::Styled, text::StyledGrapheme, widgets::WidgetRef};
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
block::BlockExt,
|
||||||
style::Styled,
|
reflow::{LineComposer, LineTruncator, WordWrapper, WrappedLine},
|
||||||
text::StyledGrapheme,
|
Block,
|
||||||
widgets::{
|
|
||||||
reflow::{LineComposer, LineTruncator, WordWrapper, WrappedLine},
|
|
||||||
Block,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const fn get_line_offset(line_width: u16, text_area_width: u16, alignment: Alignment) -> u16 {
|
const fn get_line_offset(line_width: u16, text_area_width: u16, alignment: Alignment) -> u16 {
|
||||||
|
@ -470,11 +467,10 @@ impl<'a> Styled for Paragraph<'a> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use ratatui_core::backend::TestBackend;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{block::title::Position, Borders};
|
||||||
backend::TestBackend,
|
|
||||||
widgets::{block::Position, Borders},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Tests the [`Paragraph`] widget against the expected [`Buffer`] by rendering it onto an equal
|
/// Tests the [`Paragraph`] widget against the expected [`Buffer`] by rendering it onto an equal
|
||||||
/// area and comparing the rendered and expected content.
|
/// area and comparing the rendered and expected content.
|
|
@ -1,10 +1,9 @@
|
||||||
use std::{collections::VecDeque, mem};
|
use std::{collections::VecDeque, mem};
|
||||||
|
|
||||||
|
use ratatui_core::{layout::Alignment, text::StyledGrapheme};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use crate::{layout::Alignment, text::StyledGrapheme};
|
|
||||||
|
|
||||||
/// A state machine to pack styled symbols into lines.
|
/// A state machine to pack styled symbols into lines.
|
||||||
/// Cannot implement it as Iterator since it yields slices of the internal buffer (need streaming
|
/// Cannot implement it as Iterator since it yields slices of the internal buffer (need streaming
|
||||||
/// iterators for that).
|
/// iterators for that).
|
||||||
|
@ -344,12 +343,13 @@ fn trim_offset(src: &str, mut offset: usize) -> &str {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use ratatui_core::{
|
||||||
use crate::{
|
|
||||||
style::Style,
|
style::Style,
|
||||||
text::{Line, Text},
|
text::{Line, Text},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum Composer {
|
enum Composer {
|
||||||
WordWrapper { trim: bool },
|
WordWrapper { trim: bool },
|
|
@ -8,13 +8,12 @@
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use strum::{Display, EnumString};
|
use ratatui_core::{
|
||||||
use unicode_width::UnicodeWidthStr;
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
symbols::scrollbar::{Set, DOUBLE_HORIZONTAL, DOUBLE_VERTICAL},
|
symbols::scrollbar::{Set, DOUBLE_HORIZONTAL, DOUBLE_VERTICAL},
|
||||||
};
|
};
|
||||||
|
use strum::{Display, EnumString};
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
/// A widget to display a scrollbar
|
/// A widget to display a scrollbar
|
||||||
///
|
///
|
|
@ -1,8 +1,9 @@
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
|
use ratatui_core::{prelude::*, style::Styled, widgets::WidgetRef};
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
|
|
||||||
use crate::{prelude::*, style::Styled, widgets::Block};
|
use crate::{block::BlockExt, Block};
|
||||||
|
|
||||||
/// Widget to render a sparkline over one or more lines.
|
/// Widget to render a sparkline over one or more lines.
|
||||||
///
|
///
|
||||||
|
@ -208,10 +209,10 @@ impl Sparkline<'_> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use ratatui_core::buffer::Cell;
|
||||||
use strum::ParseError;
|
use strum::ParseError;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::buffer::Cell;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn render_direction_to_string() {
|
fn render_direction_to_string() {
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{prelude::*, style::Styled};
|
use ratatui_core::{prelude::*, style::Styled, widgets::WidgetRef};
|
||||||
|
|
||||||
/// A [`Cell`] contains the [`Text`] to be displayed in a [`Row`] of a [`Table`].
|
/// A [`Cell`] contains the [`Text`] to be displayed in a [`Row`] of a [`Table`].
|
||||||
///
|
///
|
|
@ -1,5 +1,6 @@
|
||||||
|
use ratatui_core::{prelude::*, style::Styled};
|
||||||
|
|
||||||
use super::Cell;
|
use super::Cell;
|
||||||
use crate::{prelude::*, style::Styled};
|
|
||||||
|
|
||||||
/// A single row of data to be displayed in a [`Table`] widget.
|
/// A single row of data to be displayed in a [`Table`] widget.
|
||||||
///
|
///
|
|
@ -1,9 +1,15 @@
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use ratatui_core::{
|
||||||
|
layout::Flex,
|
||||||
|
prelude::*,
|
||||||
|
style::Styled,
|
||||||
|
widgets::{StatefulWidgetRef, WidgetRef},
|
||||||
|
};
|
||||||
|
|
||||||
#[allow(unused_imports)] // `Cell` is used in the doc comment but not the code
|
#[allow(unused_imports)] // `Cell` is used in the doc comment but not the code
|
||||||
use super::Cell;
|
use super::Cell;
|
||||||
use super::{HighlightSpacing, Row, TableState};
|
use super::{HighlightSpacing, Row, TableState};
|
||||||
use crate::{layout::Flex, prelude::*, style::Styled, widgets::Block};
|
use crate::{block::BlockExt, Block};
|
||||||
|
|
||||||
/// A widget to display data in formatted columns.
|
/// A widget to display data in formatted columns.
|
||||||
///
|
///
|
||||||
|
@ -867,8 +873,10 @@ where
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
|
use ratatui_core::{layout::Constraint::*, style::Style, text::Line};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{layout::Constraint::*, style::Style, text::Line, widgets::Cell};
|
use crate::table::Cell;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn new() {
|
fn new() {
|
||||||
|
@ -1031,14 +1039,15 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod state {
|
mod state {
|
||||||
|
use ratatui_core::{
|
||||||
|
buffer::Buffer,
|
||||||
|
layout::{Constraint, Rect},
|
||||||
|
widgets::StatefulWidget,
|
||||||
|
};
|
||||||
use rstest::{fixture, rstest};
|
use rstest::{fixture, rstest};
|
||||||
|
|
||||||
use super::TableState;
|
use super::TableState;
|
||||||
use crate::{
|
use crate::{Row, Table};
|
||||||
buffer::Buffer,
|
|
||||||
layout::{Constraint, Rect},
|
|
||||||
widgets::{Row, StatefulWidget, Table},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[fixture]
|
#[fixture]
|
||||||
fn table_buf() -> Buffer {
|
fn table_buf() -> Buffer {
|
|
@ -41,8 +41,8 @@
|
||||||
/// Note that if [`Table::widths`] is not called before rendering, the rendered columns will have
|
/// Note that if [`Table::widths`] is not called before rendering, the rendered columns will have
|
||||||
/// equal width.
|
/// equal width.
|
||||||
///
|
///
|
||||||
/// [`Table`]: crate::widgets::Table
|
/// [`Table`]: crate::Table
|
||||||
/// [`Table::widths`]: crate::widgets::Table::widths
|
/// [`Table::widths`]: crate::Table::widths
|
||||||
/// [`Frame::render_stateful_widget`]: crate::Frame::render_stateful_widget
|
/// [`Frame::render_stateful_widget`]: crate::Frame::render_stateful_widget
|
||||||
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
@ -1,4 +1,6 @@
|
||||||
use crate::{prelude::*, style::Styled, widgets::Block};
|
use ratatui_core::{prelude::*, style::Styled, widgets::WidgetRef};
|
||||||
|
|
||||||
|
use crate::{block::BlockExt, Block};
|
||||||
|
|
||||||
const DEFAULT_HIGHLIGHT_STYLE: Style = Style::new().add_modifier(Modifier::REVERSED);
|
const DEFAULT_HIGHLIGHT_STYLE: Style = Style::new().add_modifier(Modifier::REVERSED);
|
||||||
|
|
386
ratatui/Cargo.toml
Normal file
386
ratatui/Cargo.toml
Normal file
|
@ -0,0 +1,386 @@
|
||||||
|
[package]
|
||||||
|
name = "ratatui"
|
||||||
|
version = "0.28.1" # crate version
|
||||||
|
authors = ["Florian Dehau <work@fdehau.com>", "The Ratatui Developers"]
|
||||||
|
description = "A library that's all about cooking up terminal user interfaces"
|
||||||
|
documentation = "https://docs.rs/ratatui/latest/ratatui/"
|
||||||
|
repository = "https://github.com/ratatui/ratatui"
|
||||||
|
homepage = "https://ratatui.rs"
|
||||||
|
keywords = ["tui", "terminal", "dashboard"]
|
||||||
|
categories = ["command-line-interface"]
|
||||||
|
readme = "README.md"
|
||||||
|
license = "MIT"
|
||||||
|
exclude = [
|
||||||
|
"assets/*",
|
||||||
|
".github",
|
||||||
|
"Makefile.toml",
|
||||||
|
"CONTRIBUTING.md",
|
||||||
|
"*.log",
|
||||||
|
"tags",
|
||||||
|
]
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.74.0"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
#! The crate provides a set of optional features that can be enabled in your `cargo.toml` file.
|
||||||
|
#!
|
||||||
|
## By default, we enable the crossterm backend as this is a reasonable choice for most applications
|
||||||
|
## as it is supported on Linux/Mac/Windows systems. We also enable the `underline-color` feature
|
||||||
|
## which allows you to set the underline color of text.
|
||||||
|
default = ["crossterm", "underline-color"]
|
||||||
|
#! Generally an application will only use one backend, so you should only enable one of the following features:
|
||||||
|
## enables the [`CrosstermBackend`](backend::CrosstermBackend) backend and adds a dependency on [`crossterm`].
|
||||||
|
crossterm = ["dep:ratatui-crossterm", "dep:crossterm"]
|
||||||
|
## enables the [`TermionBackend`](backend::TermionBackend) backend and adds a dependency on [`termion`].
|
||||||
|
# termion = ["dep:ratatui-termion", "dep:termion"]
|
||||||
|
# ## enables the [`TermwizBackend`](backend::TermwizBackend) backend and adds a dependency on [`termwiz`].
|
||||||
|
# termwiz = ["dep:ratatui-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", "bitflags/serde", "compact_str/serde"]
|
||||||
|
|
||||||
|
## enables the [`border!`] macro.
|
||||||
|
macros = []
|
||||||
|
|
||||||
|
## enables conversions from colors in the [`palette`] crate to [`Color`](crate::style::Color).
|
||||||
|
palette = ["dep:palette"]
|
||||||
|
|
||||||
|
## enables all widgets.
|
||||||
|
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 = ["ratatui-widgets/widget-calendar", "dep:time"]
|
||||||
|
|
||||||
|
#! The following optional features are only available for some backends:
|
||||||
|
|
||||||
|
## enables the backend code that sets the underline color.
|
||||||
|
## Underline color is only supported by the [`CrosstermBackend`](backend::CrosstermBackend) backend,
|
||||||
|
## and is not supported on Windows 7.
|
||||||
|
# underline-color = ["ratatui-crossterm/underline-color"]
|
||||||
|
underline-color = ["ratatui-core/underline-color"]
|
||||||
|
|
||||||
|
#! The following features are unstable and may change in the future:
|
||||||
|
|
||||||
|
## Enable all unstable features.
|
||||||
|
unstable = [
|
||||||
|
"unstable-rendered-line-info",
|
||||||
|
"unstable-widget-ref",
|
||||||
|
"unstable-backend-writer",
|
||||||
|
]
|
||||||
|
|
||||||
|
## 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 = []
|
||||||
|
|
||||||
|
## Enables the [`WidgetRef`](widgets::WidgetRef) and [`StatefulWidgetRef`](widgets::StatefulWidgetRef) traits which are experimental and may change in
|
||||||
|
## the future.
|
||||||
|
unstable-widget-ref = []
|
||||||
|
|
||||||
|
## Enables getting access to backends' writers.
|
||||||
|
unstable-backend-writer = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
ratatui-widgets = { workspace = true }
|
||||||
|
ratatui-core = { workspace = true }
|
||||||
|
ratatui-crossterm = { workspace = true, optional = true }
|
||||||
|
# ratatui-termwiz = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
bitflags = "2.3"
|
||||||
|
cassowary = "0.3"
|
||||||
|
crossterm = { workspace = true, optional = true }
|
||||||
|
compact_str = "0.8.0"
|
||||||
|
document-features = { version = "0.2.7", optional = true }
|
||||||
|
instability = "0.3.1"
|
||||||
|
itertools = "0.13"
|
||||||
|
lru = "0.12.0"
|
||||||
|
paste = "1.0.2"
|
||||||
|
palette = { version = "0.7.6", optional = true }
|
||||||
|
serde = { version = "1", optional = true, features = ["derive"] }
|
||||||
|
strum = { version = "0.26.3", features = ["derive"] }
|
||||||
|
unicode-segmentation = "1.10"
|
||||||
|
unicode-truncate = "1"
|
||||||
|
unicode-width = "=0.1.13"
|
||||||
|
time = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
# [target.'cfg(not(windows))'.dependencies]
|
||||||
|
# # termion is not supported on Windows
|
||||||
|
# ratatui-termion = { workspace = true, optional = true }
|
||||||
|
# termion = { workspace = true, optional = true }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
argh = "0.1.12"
|
||||||
|
color-eyre = "0.6.2"
|
||||||
|
criterion = { version = "0.5.1", features = ["html_reports"] }
|
||||||
|
fakeit = "1.1"
|
||||||
|
font8x8 = "0.3.1"
|
||||||
|
futures = "0.3.30"
|
||||||
|
indoc = "2"
|
||||||
|
octocrab = "0.40.0"
|
||||||
|
pretty_assertions = "1.4.0"
|
||||||
|
rand = "0.8.5"
|
||||||
|
rand_chacha = "0.3.1"
|
||||||
|
rstest = "0.22.0"
|
||||||
|
serde_json = "1.0.109"
|
||||||
|
tokio = { version = "1.39.2", features = [
|
||||||
|
"rt",
|
||||||
|
"macros",
|
||||||
|
"time",
|
||||||
|
"rt-multi-thread",
|
||||||
|
] }
|
||||||
|
tracing = "0.1.40"
|
||||||
|
tracing-appender = "0.2.3"
|
||||||
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
|
|
||||||
|
[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"
|
||||||
|
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
all-features = true
|
||||||
|
# see https://doc.rust-lang.org/nightly/rustdoc/scraped-examples.html
|
||||||
|
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples"]
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
# Improve benchmark consistency
|
||||||
|
[profile.bench]
|
||||||
|
codegen-units = 1
|
||||||
|
lto = true
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
bench = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "main"
|
||||||
|
harness = false
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "async"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "barchart"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "barchart-grouped"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "block"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "calendar"
|
||||||
|
required-features = ["crossterm", "widget-calendar"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "canvas"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "chart"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "colors"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
# this example is a bit verbose, so we don't want to include it in the docs
|
||||||
|
doc-scrape-examples = false
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "colors_rgb"
|
||||||
|
required-features = ["crossterm", "palette"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "constraint-explorer"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "constraints"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = false
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "custom_widget"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "demo"
|
||||||
|
# this runs for all of the terminal backends, so it can't be built using --all-features or scraped
|
||||||
|
doc-scrape-examples = false
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "demo2"
|
||||||
|
required-features = ["crossterm", "palette", "widget-calendar"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "docsrs"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = false
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "flex"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "gauge"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "hello_world"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "inline"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "layout"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "line_gauge"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "hyperlink"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "list"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "minimal"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
# prefer to show the more featureful examples in the docs
|
||||||
|
doc-scrape-examples = false
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "modifiers"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
# this example is a bit verbose, so we don't want to include it in the docs
|
||||||
|
doc-scrape-examples = false
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "panic"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "paragraph"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "popup"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "ratatui-logo"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "scrollbar"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "sparkline"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "table"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "tabs"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "tracing"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "user_input"
|
||||||
|
required-features = ["crossterm"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "widget_impl"
|
||||||
|
required-features = ["crossterm", "unstable-widget-ref"]
|
||||||
|
doc-scrape-examples = true
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "state_serde"
|
||||||
|
required-features = ["serde"]
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue