diff --git a/Cargo.toml b/Cargo.toml index 29891bee..ef0dc81b 100644 --- a/Cargo.toml +++ b/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 diff --git a/Makefile.toml b/Makefile.toml index 7fc6677b..26194e27 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -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" diff --git a/src/backend/crossterm.rs b/src/backend/crossterm.rs index 958fcdc8..77372229 100644 --- a/src/backend/crossterm.rs +++ b/src/backend/crossterm.rs @@ -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<()> { diff --git a/src/buffer.rs b/src/buffer.rs index fa86fba0..b87881b5 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -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!( diff --git a/src/style.rs b/src/style.rs index 812ea4b6..09b4fc80 100644 --- a/src/style.rs +++ b/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, pub bg: Option, - #[cfg(feature = "crossterm")] + #[cfg(feature = "underline-color")] pub underline_color: Option, 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); } diff --git a/src/widgets/gauge.rs b/src/widgets/gauge.rs index 4c4baa29..3926c7ac 100644 --- a/src/widgets/gauge.rs +++ b/src/widgets/gauge.rs @@ -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,