diff options
Diffstat (limited to 'helix-view')
-rw-r--r-- | helix-view/src/graphics.rs | 101 | ||||
-rw-r--r-- | helix-view/src/gutter.rs | 4 | ||||
-rw-r--r-- | helix-view/src/theme.rs | 23 |
3 files changed, 95 insertions, 33 deletions
diff --git a/helix-view/src/graphics.rs b/helix-view/src/graphics.rs index 6c854fd0..01344748 100644 --- a/helix-view/src/graphics.rs +++ b/helix-view/src/graphics.rs @@ -315,6 +315,44 @@ impl From<Color> for crossterm::style::Color { } } +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum UnderlineStyle { + Reset, + Line, + Curl, + Dotted, + Dashed, + DoubleLine, +} + +impl FromStr for UnderlineStyle { + type Err = &'static str; + + fn from_str(modifier: &str) -> Result<Self, Self::Err> { + match modifier { + "line" => Ok(Self::Line), + "curl" => Ok(Self::Curl), + "dotted" => Ok(Self::Dotted), + "dashed" => Ok(Self::Dashed), + "double_line" => Ok(Self::DoubleLine), + _ => Err("Invalid underline style"), + } + } +} + +impl From<UnderlineStyle> for crossterm::style::Attribute { + fn from(style: UnderlineStyle) -> Self { + match style { + UnderlineStyle::Line => crossterm::style::Attribute::Underlined, + UnderlineStyle::Curl => crossterm::style::Attribute::Undercurled, + UnderlineStyle::Dotted => crossterm::style::Attribute::Underdotted, + UnderlineStyle::Dashed => crossterm::style::Attribute::Underdashed, + UnderlineStyle::DoubleLine => crossterm::style::Attribute::DoubleUnderlined, + UnderlineStyle::Reset => crossterm::style::Attribute::NoUnderline, + } + } +} + bitflags! { /// Modifier changes the way a piece of text is displayed. /// @@ -332,22 +370,11 @@ bitflags! { const BOLD = 0b0000_0000_0000_0001; const DIM = 0b0000_0000_0000_0010; const ITALIC = 0b0000_0000_0000_0100; - const UNDERLINED = 0b0000_0000_0000_1000; const SLOW_BLINK = 0b0000_0000_0001_0000; const RAPID_BLINK = 0b0000_0000_0010_0000; const REVERSED = 0b0000_0000_0100_0000; const HIDDEN = 0b0000_0000_1000_0000; const CROSSED_OUT = 0b0000_0001_0000_0000; - const UNDERCURLED = 0b0000_0010_0000_0000; - const UNDERDOTTED = 0b0000_0100_0000_0000; - const UNDERDASHED = 0b0000_1000_0000_0000; - const DOUBLE_UNDERLINED = 0b0001_0000_0000_0000; - - const ANY_UNDERLINE = Self::UNDERLINED.bits - | Self::UNDERCURLED.bits - | Self::UNDERDOTTED.bits - | Self::UNDERDASHED.bits - | Self::DOUBLE_UNDERLINED.bits; } } @@ -359,16 +386,11 @@ impl FromStr for Modifier { "bold" => Ok(Self::BOLD), "dim" => Ok(Self::DIM), "italic" => Ok(Self::ITALIC), - "underlined" => Ok(Self::UNDERLINED), "slow_blink" => Ok(Self::SLOW_BLINK), "rapid_blink" => Ok(Self::RAPID_BLINK), "reversed" => Ok(Self::REVERSED), "hidden" => Ok(Self::HIDDEN), "crossed_out" => Ok(Self::CROSSED_OUT), - "undercurled" => Ok(Self::UNDERCURLED), - "underdotted" => Ok(Self::UNDERDOTTED), - "underdashed" => Ok(Self::UNDERDASHED), - "double_underlined" => Ok(Self::DOUBLE_UNDERLINED), _ => Err("Invalid modifier"), } } @@ -389,7 +411,7 @@ impl FromStr for Modifier { /// just S3. /// /// ```rust -/// # use helix_view::graphics::{Rect, Color, Modifier, Style}; +/// # use helix_view::graphics::{Rect, Color, UnderlineStyle, Modifier, Style}; /// # use helix_tui::buffer::Buffer; /// let styles = [ /// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC), @@ -405,7 +427,8 @@ impl FromStr for Modifier { /// fg: Some(Color::Yellow), /// bg: Some(Color::Red), /// add_modifier: Modifier::BOLD, -/// underline: Some(Color::Reset), +/// underline_color: Some(Color::Reset), +/// underline_style: Some(UnderlineStyle::Reset), /// sub_modifier: Modifier::empty(), /// }, /// buffer[(0, 0)].style(), @@ -416,7 +439,7 @@ impl FromStr for Modifier { /// reset all properties until that point use [`Style::reset`]. /// /// ``` -/// # use helix_view::graphics::{Rect, Color, Modifier, Style}; +/// # use helix_view::graphics::{Rect, Color, UnderlineStyle, Modifier, Style}; /// # use helix_tui::buffer::Buffer; /// let styles = [ /// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC), @@ -430,7 +453,8 @@ impl FromStr for Modifier { /// Style { /// fg: Some(Color::Yellow), /// bg: Some(Color::Reset), -/// underline: Some(Color::Reset), +/// underline_color: Some(Color::Reset), +/// underline_style: Some(UnderlineStyle::Reset), /// add_modifier: Modifier::empty(), /// sub_modifier: Modifier::empty(), /// }, @@ -442,7 +466,8 @@ impl FromStr for Modifier { pub struct Style { pub fg: Option<Color>, pub bg: Option<Color>, - pub underline: Option<Color>, + pub underline_color: Option<Color>, + pub underline_style: Option<UnderlineStyle>, pub add_modifier: Modifier, pub sub_modifier: Modifier, } @@ -452,7 +477,8 @@ impl Default for Style { Style { fg: None, bg: None, - underline: None, + underline_color: None, + underline_style: None, add_modifier: Modifier::empty(), sub_modifier: Modifier::empty(), } @@ -465,7 +491,8 @@ impl Style { Style { fg: Some(Color::Reset), bg: Some(Color::Reset), - underline: Some(Color::Reset), + underline_color: None, + underline_style: None, add_modifier: Modifier::empty(), sub_modifier: Modifier::all(), } @@ -507,12 +534,27 @@ impl Style { /// /// ```rust /// # use helix_view::graphics::{Color, Style}; - /// let style = Style::default().underline(Color::Blue); - /// let diff = Style::default().underline(Color::Red); - /// assert_eq!(style.patch(diff), Style::default().underline(Color::Red)); + /// let style = Style::default().underline_color(Color::Blue); + /// let diff = Style::default().underline_color(Color::Red); + /// assert_eq!(style.patch(diff), Style::default().underline_color(Color::Red)); + /// ``` + pub fn underline_color(mut self, color: Color) -> Style { + self.underline_color = Some(color); + self + } + + /// Changes the underline style. + /// + /// ## Examples + /// + /// ```rust + /// # use helix_view::graphics::{UnderlineStyle, Style}; + /// let style = Style::default().underline_style(UnderlineStyle::Line); + /// let diff = Style::default().underline_style(UnderlineStyle::Curl); + /// assert_eq!(style.patch(diff), Style::default().underline_style(UnderlineStyle::Curl)); /// ``` - pub fn underline(mut self, color: Color) -> Style { - self.underline = Some(color); + pub fn underline_style(mut self, style: UnderlineStyle) -> Style { + self.underline_style = Some(style); self } @@ -572,7 +614,8 @@ impl Style { pub fn patch(mut self, other: Style) -> Style { self.fg = other.fg.or(self.fg); self.bg = other.bg.or(self.bg); - self.underline = other.underline.or(self.underline); + self.underline_color = other.underline_color.or(self.underline_color); + self.underline_style = other.underline_style.or(self.underline_style); self.add_modifier.remove(other.sub_modifier); self.add_modifier.insert(other.add_modifier); diff --git a/helix-view/src/gutter.rs b/helix-view/src/gutter.rs index ab0e2986..2c207d27 100644 --- a/helix-view/src/gutter.rs +++ b/helix-view/src/gutter.rs @@ -1,7 +1,7 @@ use std::fmt::Write; use crate::{ - graphics::{Color, Modifier, Style}, + graphics::{Color, Style, UnderlineStyle}, Document, Editor, Theme, View, }; @@ -147,7 +147,7 @@ pub fn breakpoints<'doc>( .find(|breakpoint| breakpoint.line == line)?; let mut style = if breakpoint.condition.is_some() && breakpoint.log_message.is_some() { - error.add_modifier(Modifier::UNDERLINED) + error.underline_style(UnderlineStyle::Line) } else if breakpoint.condition.is_some() { error } else if breakpoint.log_message.is_some() { diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 5ce1b2c5..90185937 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -10,6 +10,7 @@ use once_cell::sync::Lazy; use serde::{Deserialize, Deserializer}; use toml::Value; +use crate::graphics::UnderlineStyle; pub use crate::graphics::{Color, Modifier, Style}; pub static DEFAULT_THEME: Lazy<Theme> = Lazy::new(|| { @@ -263,20 +264,38 @@ impl ThemePalette { .ok_or(format!("Theme: invalid modifier: {}", value)) } + pub fn parse_underline_style(value: &Value) -> Result<UnderlineStyle, String> { + value + .as_str() + .and_then(|s| s.parse().ok()) + .ok_or(format!("Theme: invalid underline_style: {}", value)) + } + pub fn parse_style(&self, style: &mut Style, value: Value) -> Result<(), String> { if let Value::Table(entries) = value { for (name, value) in entries { match name.as_str() { "fg" => *style = style.fg(self.parse_color(value)?), "bg" => *style = style.bg(self.parse_color(value)?), - "underline" => *style = style.underline(self.parse_color(value)?), + "underline_color" => *style = style.underline_color(self.parse_color(value)?), + "underline_style" => { + warn!("found style"); + *style = style.underline_style(Self::parse_underline_style(&value)?) + } "modifiers" => { let modifiers = value .as_array() .ok_or("Theme: modifiers should be an array")?; for modifier in modifiers { - *style = style.add_modifier(Self::parse_modifier(modifier)?); + if modifier + .as_str() + .map_or(false, |modifier| modifier == "underlined") + { + *style = style.underline_style(UnderlineStyle::Line); + } else { + *style = style.add_modifier(Self::parse_modifier(modifier)?); + } } } _ => return Err(format!("Theme: invalid style attribute: {}", name)), |