mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-10 07:04:17 +00:00
fix(backend): add feature flag for underline-color (#570)
Windows 7 doesn't support the underline color attribute, so we need to make it optional. This commit adds a feature flag for the underline color attribute - it is enabled by default, but can be disabled by passing `--no-default-features` to cargo. We could specically check for Windows 7 and disable the feature flag automatically, but I think it's better for this check to be done by the crossterm crate, since it's the one that actually knows about the underlying terminal. To disable the feature flag in an application that supports Windows 7, add the following to your Cargo.toml: ```toml ratatui = { version = "0.24.0", default-features = false, features = ["crossterm"] } ``` Fixes https://github.com/ratatui-org/ratatui/issues/555
This commit is contained in:
parent
b61f65bc20
commit
8d507c43fa
6 changed files with 66 additions and 39 deletions
26
Cargo.toml
26
Cargo.toml
|
@ -23,14 +23,8 @@ rust-version = "1.67.0"
|
|||
[badges]
|
||||
|
||||
[dependencies]
|
||||
#! The crate provides a set of optional features that can be enabled in your `cargo.toml` file.
|
||||
#!
|
||||
#! Generally an application will only use one backend, so you should only enable one of the following features:
|
||||
## enables the [`CrosstermBackend`] backend and adds a dependency on the [Crossterm crate].
|
||||
crossterm = { version = "0.27", optional = true }
|
||||
## enables the [`TermionBackend`] backend and adds a dependency on the [Termion crate].
|
||||
termion = { version = "2.0", optional = true }
|
||||
## enables the [`TermwizBackend`] backend and adds a dependency on the [Termwiz crate].
|
||||
termwiz = { version = "0.20.0", optional = true }
|
||||
|
||||
serde = { version = "1", optional = true, features = ["derive"] }
|
||||
|
@ -60,7 +54,20 @@ palette = "0.7.3"
|
|||
pretty_assertions = "1.4.0"
|
||||
|
||||
[features]
|
||||
default = ["crossterm"]
|
||||
#! 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 and adds a dependency on the [Crossterm crate].
|
||||
crossterm = ["dep:crossterm"]
|
||||
## enables the [`TermionBackend`] backend and adds a dependency on the [Termion crate].
|
||||
termion = ["dep:termion"]
|
||||
## enables the [`TermwizBackend`] backend and adds a dependency on the [Termwiz crate].
|
||||
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.
|
||||
|
@ -77,6 +84,11 @@ all-widgets = ["widget-calendar"]
|
|||
## enables the [`calendar`] widget module and adds a dependency on the [Time crate].
|
||||
widget-calendar = ["dep:time"]
|
||||
|
||||
#! Underline color is only supported by the [`CrosstermBackend`] backend, and is not supported
|
||||
#! on Windows 7.
|
||||
## enables the backend code that sets the underline color.
|
||||
underline-color = ["dep:crossterm"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
# see https://doc.rust-lang.org/nightly/rustdoc/scraped-examples.html
|
||||
|
|
|
@ -9,9 +9,9 @@ ALL_FEATURES = "all-widgets,macros,serde"
|
|||
|
||||
# Windows does not support building termion, so this avoids the build failure by providing two
|
||||
# sets of flags, one for Windows and one for other platforms.
|
||||
# Windows: --features=all-widgets,macros,serde,crossterm,termwiz
|
||||
# Other: --all-features
|
||||
ALL_FEATURES_FLAG = { source = "${CARGO_MAKE_RUST_TARGET_OS}", default_value = "--all-features", mapping = { "windows" = "--features=all-widgets,macros,serde,crossterm,termwiz" } }
|
||||
# Windows: --features=all-widgets,macros,serde,crossterm,termwiz,underline-color
|
||||
# Other: --features=all-widgets,macros,serde,crossterm,termion,termwiz,underline-color
|
||||
ALL_FEATURES_FLAG = { source = "${CARGO_MAKE_RUST_TARGET_OS}", default_value = "--features=all-widgets,macros,serde,crossterm,termion,termwiz", mapping = { "windows" = "--features=all-widgets,macros,serde,crossterm,termwiz" } }
|
||||
|
||||
[tasks.default]
|
||||
alias = "ci"
|
||||
|
|
|
@ -4,12 +4,14 @@
|
|||
//! [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 CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor,
|
||||
SetForegroundColor, SetUnderlineColor,
|
||||
SetForegroundColor,
|
||||
},
|
||||
terminal::{self, Clear},
|
||||
};
|
||||
|
@ -124,6 +126,7 @@ where
|
|||
{
|
||||
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<(u16, u16)> = None;
|
||||
|
@ -151,6 +154,7 @@ where
|
|||
queue!(self.writer, SetBackgroundColor(color))?;
|
||||
bg = cell.bg;
|
||||
}
|
||||
#[cfg(feature = "underline-color")]
|
||||
if cell.underline_color != underline_color {
|
||||
let color = CColor::from(cell.underline_color);
|
||||
queue!(self.writer, SetUnderlineColor(color))?;
|
||||
|
@ -160,13 +164,21 @@ where
|
|||
queue!(self.writer, Print(&cell.symbol))?;
|
||||
}
|
||||
|
||||
queue!(
|
||||
#[cfg(feature = "underline-color")]
|
||||
return queue!(
|
||||
self.writer,
|
||||
SetForegroundColor(CColor::Reset),
|
||||
SetBackgroundColor(CColor::Reset),
|
||||
SetUnderlineColor(CColor::Reset),
|
||||
SetAttribute(CAttribute::Reset)
|
||||
)
|
||||
SetAttribute(CAttribute::Reset),
|
||||
);
|
||||
#[cfg(not(feature = "underline-color"))]
|
||||
return queue!(
|
||||
self.writer,
|
||||
SetForegroundColor(CColor::Reset),
|
||||
SetBackgroundColor(CColor::Reset),
|
||||
SetAttribute(CAttribute::Reset),
|
||||
);
|
||||
}
|
||||
|
||||
fn hide_cursor(&mut self) -> io::Result<()> {
|
||||
|
|
|
@ -19,7 +19,7 @@ pub struct Cell {
|
|||
pub symbol: String,
|
||||
pub fg: Color,
|
||||
pub bg: Color,
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
pub underline_color: Color,
|
||||
pub modifier: Modifier,
|
||||
pub skip: bool,
|
||||
|
@ -55,7 +55,7 @@ impl Cell {
|
|||
if let Some(c) = style.bg {
|
||||
self.bg = c;
|
||||
}
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
if let Some(c) = style.underline_color {
|
||||
self.underline_color = c;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ impl Cell {
|
|||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
pub fn style(&self) -> Style {
|
||||
Style::default()
|
||||
.fg(self.fg)
|
||||
|
@ -73,7 +73,7 @@ impl Cell {
|
|||
.add_modifier(self.modifier)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "crossterm"))]
|
||||
#[cfg(not(feature = "underline-color"))]
|
||||
pub fn style(&self) -> Style {
|
||||
Style::default()
|
||||
.fg(self.fg)
|
||||
|
@ -95,7 +95,7 @@ impl Cell {
|
|||
self.symbol.push(' ');
|
||||
self.fg = Color::Reset;
|
||||
self.bg = Color::Reset;
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
{
|
||||
self.underline_color = Color::Reset;
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ impl Default for Cell {
|
|||
symbol: " ".into(),
|
||||
fg: Color::Reset,
|
||||
bg: Color::Reset,
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: Color::Reset,
|
||||
modifier: Modifier::empty(),
|
||||
skip: false,
|
||||
|
@ -138,7 +138,7 @@ impl Default for Cell {
|
|||
/// symbol: String::from("r"),
|
||||
/// fg: Color::Red,
|
||||
/// bg: Color::White,
|
||||
/// #[cfg(feature = "crossterm")]
|
||||
/// #[cfg(feature = "underline-color")]
|
||||
/// underline_color: Color::Reset,
|
||||
/// modifier: Modifier::empty(),
|
||||
/// skip: false
|
||||
|
@ -560,7 +560,7 @@ impl Debug for Buffer {
|
|||
overwritten.push((x, &c.symbol));
|
||||
}
|
||||
skip = std::cmp::max(skip, c.symbol.width()).saturating_sub(1);
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
{
|
||||
let style = (c.fg, c.bg, c.underline_color, c.modifier);
|
||||
if last_style != Some(style) {
|
||||
|
@ -568,7 +568,7 @@ impl Debug for Buffer {
|
|||
styles.push((x, y, c.fg, c.bg, c.underline_color, c.modifier));
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "crossterm"))]
|
||||
#[cfg(not(feature = "underline-color"))]
|
||||
{
|
||||
let style = (c.fg, c.bg, c.modifier);
|
||||
if last_style != Some(style) {
|
||||
|
@ -586,12 +586,12 @@ impl Debug for Buffer {
|
|||
}
|
||||
f.write_str(" ],\n styles: [\n")?;
|
||||
for s in styles {
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
f.write_fmt(format_args!(
|
||||
" x: {}, y: {}, fg: {:?}, bg: {:?}, underline: {:?}, modifier: {:?},\n",
|
||||
s.0, s.1, s.2, s.3, s.4, s.5
|
||||
))?;
|
||||
#[cfg(not(feature = "crossterm"))]
|
||||
#[cfg(not(feature = "underline-color"))]
|
||||
f.write_fmt(format_args!(
|
||||
" x: {}, y: {}, fg: {:?}, bg: {:?}, modifier: {:?},\n",
|
||||
s.0, s.1, s.2, s.3, s.4
|
||||
|
@ -625,7 +625,7 @@ mod tests {
|
|||
.bg(Color::Yellow)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
assert_eq!(
|
||||
format!("{buf:?}"),
|
||||
indoc::indoc!(
|
||||
|
@ -643,7 +643,7 @@ mod tests {
|
|||
}"
|
||||
)
|
||||
);
|
||||
#[cfg(not(feature = "crossterm"))]
|
||||
#[cfg(not(feature = "underline-color"))]
|
||||
assert_eq!(
|
||||
format!("{buf:?}"),
|
||||
indoc::indoc!(
|
||||
|
|
23
src/style.rs
23
src/style.rs
|
@ -140,7 +140,7 @@ impl fmt::Debug for Modifier {
|
|||
/// let styles = [
|
||||
/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
|
||||
/// Style::default().bg(Color::Red).add_modifier(Modifier::UNDERLINED),
|
||||
/// #[cfg(feature = "crossterm")]
|
||||
/// #[cfg(feature = "underline-color")]
|
||||
/// Style::default().underline_color(Color::Green),
|
||||
/// Style::default().fg(Color::Yellow).remove_modifier(Modifier::ITALIC),
|
||||
/// ];
|
||||
|
@ -152,7 +152,7 @@ impl fmt::Debug for Modifier {
|
|||
/// Style {
|
||||
/// fg: Some(Color::Yellow),
|
||||
/// bg: Some(Color::Red),
|
||||
/// #[cfg(feature = "crossterm")]
|
||||
/// #[cfg(feature = "underline-color")]
|
||||
/// underline_color: Some(Color::Green),
|
||||
/// add_modifier: Modifier::BOLD | Modifier::UNDERLINED,
|
||||
/// sub_modifier: Modifier::empty(),
|
||||
|
@ -179,7 +179,7 @@ impl fmt::Debug for Modifier {
|
|||
/// Style {
|
||||
/// fg: Some(Color::Yellow),
|
||||
/// bg: Some(Color::Reset),
|
||||
/// #[cfg(feature = "crossterm")]
|
||||
/// #[cfg(feature = "underline-color")]
|
||||
/// underline_color: Some(Color::Reset),
|
||||
/// add_modifier: Modifier::empty(),
|
||||
/// sub_modifier: Modifier::empty(),
|
||||
|
@ -192,7 +192,7 @@ impl fmt::Debug for Modifier {
|
|||
pub struct Style {
|
||||
pub fg: Option<Color>,
|
||||
pub bg: Option<Color>,
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
pub underline_color: Option<Color>,
|
||||
pub add_modifier: Modifier,
|
||||
pub sub_modifier: Modifier,
|
||||
|
@ -220,7 +220,7 @@ impl Style {
|
|||
Style {
|
||||
fg: None,
|
||||
bg: None,
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: None,
|
||||
add_modifier: Modifier::empty(),
|
||||
sub_modifier: Modifier::empty(),
|
||||
|
@ -232,7 +232,7 @@ impl Style {
|
|||
Style {
|
||||
fg: Some(Color::Reset),
|
||||
bg: Some(Color::Reset),
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: Some(Color::Reset),
|
||||
add_modifier: Modifier::empty(),
|
||||
sub_modifier: Modifier::all(),
|
||||
|
@ -272,9 +272,12 @@ impl Style {
|
|||
/// Changes the underline color. The text must be underlined with a modifier for this to work.
|
||||
///
|
||||
/// This uses a non-standard ANSI escape sequence. It is supported by most terminal emulators,
|
||||
/// but is only implemented in the crossterm backend.
|
||||
/// but is only implemented in the crossterm backend and enabled by the `underline-color`
|
||||
/// feature flag.
|
||||
///
|
||||
/// See [Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters) code `58` and `59` for more information.
|
||||
/// See
|
||||
/// [Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters)
|
||||
/// code `58` and `59` for more information.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
|
@ -284,7 +287,7 @@ impl Style {
|
|||
/// let diff = Style::default().underline_color(Color::Red).add_modifier(Modifier::UNDERLINED);
|
||||
/// assert_eq!(style.patch(diff), Style::default().underline_color(Color::Red).add_modifier(Modifier::UNDERLINED));
|
||||
/// ```
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
pub const fn underline_color(mut self, color: Color) -> Style {
|
||||
self.underline_color = Some(color);
|
||||
self
|
||||
|
@ -347,7 +350,7 @@ impl Style {
|
|||
self.fg = other.fg.or(self.fg);
|
||||
self.bg = other.bg.or(self.bg);
|
||||
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
{
|
||||
self.underline_color = other.underline_color.or(self.underline_color);
|
||||
}
|
||||
|
|
|
@ -366,7 +366,7 @@ impl<'a> Widget for LineGauge<'a> {
|
|||
.set_style(Style {
|
||||
fg: self.gauge_style.fg,
|
||||
bg: None,
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: self.gauge_style.underline_color,
|
||||
add_modifier: self.gauge_style.add_modifier,
|
||||
sub_modifier: self.gauge_style.sub_modifier,
|
||||
|
@ -378,7 +378,7 @@ impl<'a> Widget for LineGauge<'a> {
|
|||
.set_style(Style {
|
||||
fg: self.gauge_style.bg,
|
||||
bg: None,
|
||||
#[cfg(feature = "crossterm")]
|
||||
#[cfg(feature = "underline-color")]
|
||||
underline_color: self.gauge_style.underline_color,
|
||||
add_modifier: self.gauge_style.add_modifier,
|
||||
sub_modifier: self.gauge_style.sub_modifier,
|
||||
|
|
Loading…
Reference in a new issue