@@ -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,22 +370,11 @@ bitflags! {
332370 const BOLD = 0b0000_0000_0000_0001;
333371 const DIM = 0b0000_0000_0000_0010;
334372 const ITALIC = 0b0000_0000_0000_0100;
335− const UNDERLINED = 0b0000_0000_0000_1000;
336373 const SLOW_BLINK = 0b0000_0000_0001_0000;
337374 const RAPID_BLINK = 0b0000_0000_0010_0000;
338375 const REVERSED = 0b0000_0000_0100_0000;
339376 const HIDDEN = 0b0000_0000_1000_0000;
340377 const CROSSED_OUT = 0b0000_0001_0000_0000;
341− const UNDERCURLED = 0b0000_0010_0000_0000;
342− const UNDERDOTTED = 0b0000_0100_0000_0000;
343− const UNDERDASHED = 0b0000_1000_0000_0000;
344− const DOUBLE_UNDERLINED = 0b0001_0000_0000_0000;
345−
346− const ANY_UNDERLINE = Self::UNDERLINED.bits
347− | Self::UNDERCURLED.bits
348− | Self::UNDERDOTTED.bits
349− | Self::UNDERDASHED.bits
350− | Self::DOUBLE_UNDERLINED.bits;
351378 }
352379}
353380
@@ -359,16 +386,11 @@ impl FromStr for Modifier {
359386 "bold" => Ok(Self::BOLD),
360387 "dim" => Ok(Self::DIM),
361388 "italic" => Ok(Self::ITALIC),
362− "underlined" => Ok(Self::UNDERLINED),
363389 "slow_blink" => Ok(Self::SLOW_BLINK),
364390 "rapid_blink" => Ok(Self::RAPID_BLINK),
365391 "reversed" => Ok(Self::REVERSED),
366392 "hidden" => Ok(Self::HIDDEN),
367393 "crossed_out" => Ok(Self::CROSSED_OUT),
368− "undercurled" => Ok(Self::UNDERCURLED),
369− "underdotted" => Ok(Self::UNDERDOTTED),
370− "underdashed" => Ok(Self::UNDERDASHED),
371− "double_underlined" => Ok(Self::DOUBLE_UNDERLINED),
372394 _ => Err("Invalid modifier"),
373395 }
374396 }
@@ -389,7 +411,7 @@ impl FromStr for Modifier {
389411/// just S3.
390412///
391413/// ```rust
392−/// # use helix_view::graphics::{Rect, Color, Modifier, Style};
414+/// # use helix_view::graphics::{Rect, Color, UnderlineStyle, Modifier, Style};
393415/// # use helix_tui::buffer::Buffer;
394416/// let styles = [
395417/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
@@ -405,7 +427,8 @@ impl FromStr for Modifier {
405427/// fg: Some(Color::Yellow),
406428/// bg: Some(Color::Red),
407429/// add_modifier: Modifier::BOLD,
408−/// underline: Some(Color::Reset),
430+/// underline_color: Some(Color::Reset),
431+/// underline_style: Some(UnderlineStyle::Reset),
409432/// sub_modifier: Modifier::empty(),
410433/// },
411434/// buffer[(0, 0)].style(),
@@ -416,7 +439,7 @@ impl FromStr for Modifier {
416439/// reset all properties until that point use [`Style::reset`].
417440///
418441/// ```
419−/// # use helix_view::graphics::{Rect, Color, Modifier, Style};
442+/// # use helix_view::graphics::{Rect, Color, UnderlineStyle, Modifier, Style};
420443/// # use helix_tui::buffer::Buffer;
421444/// let styles = [
422445/// Style::default().fg(Color::Blue).add_modifier(Modifier::BOLD | Modifier::ITALIC),
@@ -430,7 +453,8 @@ impl FromStr for Modifier {
430453/// Style {
431454/// fg: Some(Color::Yellow),
432455/// bg: Some(Color::Reset),
433−/// underline: Some(Color::Reset),
456+/// underline_color: Some(Color::Reset),
457+/// underline_style: Some(UnderlineStyle::Reset),
434458/// add_modifier: Modifier::empty(),
435459/// sub_modifier: Modifier::empty(),
436460/// },
@@ -442,7 +466,8 @@ impl FromStr for Modifier {
442466pub struct Style {
443467 pub fg: Option<Color>,
444468 pub bg: Option<Color>,
445− pub underline: Option<Color>,
469+ pub underline_color: Option<Color>,
470+ pub underline_style: Option<UnderlineStyle>,
446471 pub add_modifier: Modifier,
447472 pub sub_modifier: Modifier,
448473}
@@ -452,7 +477,8 @@ impl Default for Style {
452477 Style {
453478 fg: None,
454479 bg: None,
455− underline: None,
480+ underline_color: None,
481+ underline_style: None,
456482 add_modifier: Modifier::empty(),
457483 sub_modifier: Modifier::empty(),
458484 }
@@ -465,7 +491,8 @@ impl Style {
465491 Style {
466492 fg: Some(Color::Reset),
467493 bg: Some(Color::Reset),
468− underline: Some(Color::Reset),
494+ underline_color: None,
495+ underline_style: None,
469496 add_modifier: Modifier::empty(),
470497 sub_modifier: Modifier::all(),
471498 }
@@ -507,12 +534,27 @@ impl Style {
507534 ///
508535 /// ```rust
509536 /// # use helix_view::graphics::{Color, Style};
510− /// let style = Style::default().underline(Color::Blue);
511− /// let diff = Style::default().underline(Color::Red);
512− /// assert_eq!(style.patch(diff), Style::default().underline(Color::Red));
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));
513555 /// ```
514− pub fn underline(mut self, color: Color) -> Style {
515− self.underline = Some(color);
556+ pub fn underline_style(mut self, style: UnderlineStyle) -> Style {
557+ self.underline_style = Some(style);
516558 self
517559 }
518560
@@ -572,7 +614,8 @@ impl Style {
572614 pub fn patch(mut self, other: Style) -> Style {
573615 self.fg = other.fg.or(self.fg);
574616 self.bg = other.bg.or(self.bg);
575− self.underline = other.underline.or(self.underline);
617+ self.underline_color = other.underline_color.or(self.underline_color);
618+ self.underline_style = other.underline_style.or(self.underline_style);
576619
577620 self.add_modifier.remove(other.sub_modifier);
578621 self.add_modifier.insert(other.add_modifier);