@@ -315,6 +315,44 @@ impl From<Color> for crossterm::style::Color {
315315 }
316316}
317317
318+#[derive(Debug, Clone, Copy, PartialEq)]
319+pub enum UnderlineStyle {
320+ Reset,
321+ Line,
322+ Curl,
323+ Dotted,
324+ Dashed,
325+ DoubleLine,
326+}
327+
328+impl FromStr for UnderlineStyle {
329+ type Err = &'static str;
330+
331+ fn from_str(modifier: &str) -> Result<Self, Self::Err> {
332+ match modifier {
333+ "line" => Ok(Self::Line),
334+ "curl" => Ok(Self::Curl),
335+ "dotted" => Ok(Self::Dotted),
336+ "dashed" => Ok(Self::Dashed),
337+ "double_line" => Ok(Self::DoubleLine),
338+ _ => Err("Invalid underline style"),
339+ }
340+ }
341+}
342+
343+impl From<UnderlineStyle> for crossterm::style::Attribute {
344+ fn from(style: UnderlineStyle) -> Self {
345+ match style {
346+ UnderlineStyle::Line => crossterm::style::Attribute::Underlined,
347+ UnderlineStyle::Curl => crossterm::style::Attribute::Undercurled,
348+ UnderlineStyle::Dotted => crossterm::style::Attribute::Underdotted,
349+ UnderlineStyle::Dashed => crossterm::style::Attribute::Underdashed,
350+ UnderlineStyle::DoubleLine => crossterm::style::Attribute::DoubleUnderlined,
351+ UnderlineStyle::Reset => crossterm::style::Attribute::NoUnderline,
352+ }
353+ }
354+}
355+
318356bitflags! {
319357 /// Modifier changes the way a piece of text is displayed.
320358 ///
@@ -332,7 +370,6 @@ bitflags! {
332370 const BOLD = 0b0000_0000_0001;
333371 const DIM = 0b0000_0000_0010;
334372 const ITALIC = 0b0000_0000_0100;
335− const UNDERLINED = 0b0000_0000_1000;
336373 const SLOW_BLINK = 0b0000_0001_0000;
337374 const RAPID_BLINK = 0b0000_0010_0000;
338375 const REVERSED = 0b0000_0100_0000;
@@ -349,7 +386,6 @@ impl FromStr for Modifier {
349386 "bold" => Ok(Self::BOLD),
350387 "dim" => Ok(Self::DIM),
351388 "italic" => Ok(Self::ITALIC),
352− "underlined" => Ok(Self::UNDERLINED),
353389 "slow_blink" => Ok(Self::SLOW_BLINK),
354390 "rapid_blink" => Ok(Self::RAPID_BLINK),
355391 "reversed" => Ok(Self::REVERSED),
@@ -375,7 +411,7 @@ impl FromStr for Modifier {
375411/// just S3.
376412///
377413/// ```rust
378−/// # use helix_view::graphics::{Rect, Color, Modifier, Style};
414+/// # use helix_view::graphics::{Rect, Color, UnderlineStyle, Modifier, Style};
379415/// # use helix_tui::buffer::Buffer;
380416/// let styles = [
381417/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
@@ -391,6 +427,8 @@ impl FromStr for Modifier {
391427/// fg: Some(Color::Yellow),
392428/// bg: Some(Color::Red),
393429/// add_modifier: Modifier::BOLD,
430+/// underline_color: Some(Color::Reset),
431+/// underline_style: Some(UnderlineStyle::Reset),
394432/// sub_modifier: Modifier::empty(),
395433/// },
396434/// buffer[(0, 0)].style(),
@@ -401,7 +439,7 @@ impl FromStr for Modifier {
401439/// reset all properties until that point use [`Style::reset`].
402440///
403441/// ```
404−/// # use helix_view::graphics::{Rect, Color, Modifier, Style};
442+/// # use helix_view::graphics::{Rect, Color, UnderlineStyle, Modifier, Style};
405443/// # use helix_tui::buffer::Buffer;
406444/// let styles = [
407445/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
@@ -415,6 +453,8 @@ impl FromStr for Modifier {
415453/// Style {
416454/// fg: Some(Color::Yellow),
417455/// bg: Some(Color::Reset),
456+/// underline_color: Some(Color::Reset),
457+/// underline_style: Some(UnderlineStyle::Reset),
418458/// add_modifier: Modifier::empty(),
419459/// sub_modifier: Modifier::empty(),
420460/// },
@@ -426,6 +466,8 @@ impl FromStr for Modifier {
426466pub struct Style {
427467 pub fg: Option<Color>,
428468 pub bg: Option<Color>,
469+ pub underline_color: Option<Color>,
470+ pub underline_style: Option<UnderlineStyle>,
429471 pub add_modifier: Modifier,
430472 pub sub_modifier: Modifier,
431473}
@@ -435,6 +477,8 @@ impl Default for Style {
435477 Style {
436478 fg: None,
437479 bg: None,
480+ underline_color: None,
481+ underline_style: None,
438482 add_modifier: Modifier::empty(),
439483 sub_modifier: Modifier::empty(),
440484 }
@@ -447,6 +491,8 @@ impl Style {
447491 Style {
448492 fg: Some(Color::Reset),
449493 bg: Some(Color::Reset),
494+ underline_color: None,
495+ underline_style: None,
450496 add_modifier: Modifier::empty(),
451497 sub_modifier: Modifier::all(),
452498 }
@@ -482,6 +528,36 @@ impl Style {
482528 self
483529 }
484530
531+ /// Changes the underline color.
532+ ///
533+ /// ## Examples
534+ ///
535+ /// ```rust
536+ /// # use helix_view::graphics::{Color, Style};
537+ /// let style = Style::default().underline_color(Color::Blue);
538+ /// let diff = Style::default().underline_color(Color::Red);
539+ /// assert_eq!(style.patch(diff), Style::default().underline_color(Color::Red));
540+ /// ```
541+ pub fn underline_color(mut self, color: Color) -> Style {
542+ self.underline_color = Some(color);
543+ self
544+ }
545+
546+ /// Changes the underline style.
547+ ///
548+ /// ## Examples
549+ ///
550+ /// ```rust
551+ /// # use helix_view::graphics::{UnderlineStyle, Style};
552+ /// let style = Style::default().underline_style(UnderlineStyle::Line);
553+ /// let diff = Style::default().underline_style(UnderlineStyle::Curl);
554+ /// assert_eq!(style.patch(diff), Style::default().underline_style(UnderlineStyle::Curl));
555+ /// ```
556+ pub fn underline_style(mut self, style: UnderlineStyle) -> Style {
557+ self.underline_style = Some(style);
558+ self
559+ }
560+
485561 /// Changes the text emphasis.
486562 ///
487563 /// When applied, it adds the given modifier to the `Style` modifiers.
@@ -538,6 +614,8 @@ impl Style {
538614 pub fn patch(mut self, other: Style) -> Style {
539615 self.fg = other.fg.or(self.fg);
540616 self.bg = other.bg.or(self.bg);
617+ self.underline_color = other.underline_color.or(self.underline_color);
618+ self.underline_style = other.underline_style.or(self.underline_style);
541619
542620 self.add_modifier.remove(other.sub_modifier);
543621 self.add_modifier.insert(other.add_modifier);