@@ -315,6 +315,44 @@ impl From<Color> for crossterm::style::Color {
318+#[derive(Debug, Clone, Copy, PartialEq)]
319+pub enum UnderlineStyle {
328+impl FromStr for UnderlineStyle {
329+ type Err = &'static str;
331+ fn from_str(modifier: &str) -> Result<Self, Self::Err> {
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"),
343+impl From<UnderlineStyle> for crossterm::style::Attribute {
344+ fn from(style: UnderlineStyle) -> Self {
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,
318bitflags! {
356bitflags! {
319 /// Modifier changes the way a piece of text is displayed.
357 /// Modifier changes the way a piece of text is displayed.
@@ -332,7 +370,6 @@ bitflags! {
332 const BOLD = 0b0000_0000_0001;
370 const BOLD = 0b0000_0000_0001;
333 const DIM = 0b0000_0000_0010;
371 const DIM = 0b0000_0000_0010;
334 const ITALIC = 0b0000_0000_0100;
372 const ITALIC = 0b0000_0000_0100;
335− const UNDERLINED = 0b0000_0000_1000;
336 const SLOW_BLINK = 0b0000_0001_0000;
373 const SLOW_BLINK = 0b0000_0001_0000;
337 const RAPID_BLINK = 0b0000_0010_0000;
374 const RAPID_BLINK = 0b0000_0010_0000;
338 const REVERSED = 0b0000_0100_0000;
375 const REVERSED = 0b0000_0100_0000;
@@ -349,7 +386,6 @@ impl FromStr for Modifier {
349 "bold" => Ok(Self::BOLD),
386 "bold" => Ok(Self::BOLD),
350 "dim" => Ok(Self::DIM),
387 "dim" => Ok(Self::DIM),
351 "italic" => Ok(Self::ITALIC),
388 "italic" => Ok(Self::ITALIC),
352− "underlined" => Ok(Self::UNDERLINED),
353 "slow_blink" => Ok(Self::SLOW_BLINK),
389 "slow_blink" => Ok(Self::SLOW_BLINK),
354 "rapid_blink" => Ok(Self::RAPID_BLINK),
390 "rapid_blink" => Ok(Self::RAPID_BLINK),
355 "reversed" => Ok(Self::REVERSED),
391 "reversed" => Ok(Self::REVERSED),
@@ -375,7 +411,7 @@ impl FromStr for Modifier {
375/// just S3.
411/// just S3.
377/// ```rust
413/// ```rust
378−/// # use helix_view::graphics::{Rect, Color, Modifier, Style};
414+/// # use helix_view::graphics::{Rect, Color, UnderlineStyle, Modifier, Style};
379/// # use helix_tui::buffer::Buffer;
415/// # use helix_tui::buffer::Buffer;
380/// let styles = [
416/// let styles = [
381/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
417/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
@@ -391,6 +427,8 @@ impl FromStr for Modifier {
391/// fg: Some(Color::Yellow),
427/// fg: Some(Color::Yellow),
392/// bg: Some(Color::Red),
428/// bg: Some(Color::Red),
393/// add_modifier: Modifier::BOLD,
429/// add_modifier: Modifier::BOLD,
430+/// underline_color: Some(Color::Reset),
431+/// underline_style: Some(UnderlineStyle::Reset),
394/// sub_modifier: Modifier::empty(),
432/// sub_modifier: Modifier::empty(),
396/// buffer[(0, 0)].style(),
434/// buffer[(0, 0)].style(),
@@ -401,7 +439,7 @@ impl FromStr for Modifier {
401/// reset all properties until that point use [`Style::reset`].
439/// reset all properties until that point use [`Style::reset`].
404−/// # use helix_view::graphics::{Rect, Color, Modifier, Style};
442+/// # use helix_view::graphics::{Rect, Color, UnderlineStyle, Modifier, Style};
405/// # use helix_tui::buffer::Buffer;
443/// # use helix_tui::buffer::Buffer;
406/// let styles = [
444/// let styles = [
407/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
445/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
@@ -415,6 +453,8 @@ impl FromStr for Modifier {
415/// Style {
453/// Style {
416/// fg: Some(Color::Yellow),
454/// fg: Some(Color::Yellow),
417/// bg: Some(Color::Reset),
455/// bg: Some(Color::Reset),
456+/// underline_color: Some(Color::Reset),
457+/// underline_style: Some(UnderlineStyle::Reset),
418/// add_modifier: Modifier::empty(),
458/// add_modifier: Modifier::empty(),
419/// sub_modifier: Modifier::empty(),
459/// sub_modifier: Modifier::empty(),
@@ -426,6 +466,8 @@ impl FromStr for Modifier {
426pub struct Style {
466pub struct Style {
427 pub fg: Option<Color>,
467 pub fg: Option<Color>,
428 pub bg: Option<Color>,
468 pub bg: Option<Color>,
469+ pub underline_color: Option<Color>,
470+ pub underline_style: Option<UnderlineStyle>,
429 pub add_modifier: Modifier,
471 pub add_modifier: Modifier,
430 pub sub_modifier: Modifier,
472 pub sub_modifier: Modifier,
@@ -435,6 +477,8 @@ impl Default for Style {
436 fg: None,
478 fg: None,
437 bg: None,
479 bg: None,
480+ underline_color: None,
481+ underline_style: None,
438 add_modifier: Modifier::empty(),
482 add_modifier: Modifier::empty(),
439 sub_modifier: Modifier::empty(),
483 sub_modifier: Modifier::empty(),
@@ -447,6 +491,8 @@ impl Style {
448 fg: Some(Color::Reset),
492 fg: Some(Color::Reset),
449 bg: Some(Color::Reset),
493 bg: Some(Color::Reset),
494+ underline_color: None,
495+ underline_style: None,
450 add_modifier: Modifier::empty(),
496 add_modifier: Modifier::empty(),
451 sub_modifier: Modifier::all(),
497 sub_modifier: Modifier::all(),
@@ -482,6 +528,36 @@ impl Style {
531+ /// Changes the underline color.
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));
541+ pub fn underline_color(mut self, color: Color) -> Style {
542+ self.underline_color = Some(color);
546+ /// Changes the underline style.
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));
556+ pub fn underline_style(mut self, style: UnderlineStyle) -> Style {
557+ self.underline_style = Some(style);
485 /// Changes the text emphasis.
561 /// Changes the text emphasis.
487 /// When applied, it adds the given modifier to the `Style` modifiers.
563 /// When applied, it adds the given modifier to the `Style` modifiers.
@@ -538,6 +614,8 @@ impl Style {
538 pub fn patch(mut self, other: Style) -> Style {
614 pub fn patch(mut self, other: Style) -> Style {
539 self.fg = other.fg.or(self.fg);
615 self.fg = other.fg.or(self.fg);
540 self.bg = other.bg.or(self.bg);
616 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);
542 self.add_modifier.remove(other.sub_modifier);
620 self.add_modifier.remove(other.sub_modifier);
543 self.add_modifier.insert(other.add_modifier);
621 self.add_modifier.insert(other.add_modifier);