diff --git a/Cargo.toml b/Cargo.toml index 555cc2dc..71e288cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ indoc = "2.0" itertools = "0.11" paste = "1.0.2" serde = { version = "1", optional = true, features = ["derive"] } +strum = { version = "0.25", features = ["derive"] } termion = { version = "2.0", optional = true } termwiz = { version = "0.20.0", optional = true } time = { version = "0.3.11", optional = true, features = ["local-offset"] } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 97027914..b8665278 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -27,6 +27,8 @@ use std::io; +use strum::{Display, EnumString}; + use crate::{buffer::Cell, layout::Rect}; #[cfg(feature = "termion")] @@ -49,7 +51,7 @@ pub use self::test::TestBackend; /// Enum representing the different types of clearing operations that can be performed /// on the terminal screen. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum ClearType { All, AfterCursor, @@ -115,3 +117,41 @@ pub trait Backend { /// Flush any buffered content to the terminal screen. fn flush(&mut self) -> Result<(), io::Error>; } + +#[cfg(test)] +mod tests { + use strum::ParseError; + + use super::*; + + #[test] + fn clear_type_tostring() { + assert_eq!(ClearType::All.to_string(), "All"); + assert_eq!(ClearType::AfterCursor.to_string(), "AfterCursor"); + assert_eq!(ClearType::BeforeCursor.to_string(), "BeforeCursor"); + assert_eq!(ClearType::CurrentLine.to_string(), "CurrentLine"); + assert_eq!(ClearType::UntilNewLine.to_string(), "UntilNewLine"); + } + + #[test] + fn clear_type_from_str() { + assert_eq!("All".parse::(), Ok(ClearType::All)); + assert_eq!( + "AfterCursor".parse::(), + Ok(ClearType::AfterCursor) + ); + assert_eq!( + "BeforeCursor".parse::(), + Ok(ClearType::BeforeCursor) + ); + assert_eq!( + "CurrentLine".parse::(), + Ok(ClearType::CurrentLine) + ); + assert_eq!( + "UntilNewLine".parse::(), + Ok(ClearType::UntilNewLine) + ); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } +} diff --git a/src/layout.rs b/src/layout.rs index 46b13fc8..97005ef7 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -2,6 +2,7 @@ use std::{ cell::RefCell, cmp::{max, min}, collections::HashMap, + fmt, rc::Rc, }; @@ -11,8 +12,9 @@ use cassowary::{ WeightedRelation::{EQ, GE, LE}, }; use itertools::Itertools; +use strum::{Display, EnumString}; -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum Corner { #[default] TopLeft, @@ -21,7 +23,7 @@ pub enum Corner { BottomLeft, } -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum Direction { Horizontal, #[default] @@ -97,6 +99,18 @@ impl Default for Constraint { } } +impl fmt::Display for Constraint { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Constraint::Percentage(p) => write!(f, "Percentage({})", p), + Constraint::Ratio(n, d) => write!(f, "Ratio({}, {})", n, d), + Constraint::Length(l) => write!(f, "Length({})", l), + Constraint::Max(m) => write!(f, "Max({})", m), + Constraint::Min(m) => write!(f, "Min({})", m), + } + } +} + impl Constraint { pub fn apply(&self, length: u16) -> u16 { match *self { @@ -121,11 +135,26 @@ impl Constraint { #[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] pub struct Margin { - pub vertical: u16, pub horizontal: u16, + pub vertical: u16, } -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +impl Margin { + pub const fn new(horizontal: u16, vertical: u16) -> Margin { + Margin { + horizontal, + vertical, + } + } +} + +impl fmt::Display for Margin { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}x{}", self.horizontal, self.vertical) + } +} + +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum Alignment { #[default] Left, @@ -144,6 +173,12 @@ pub struct Rect { pub height: u16, } +impl fmt::Display for Rect { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}x{}+{}+{}", self.width, self.height, self.x, self.y) + } +} + impl Rect { /// Creates a new rect, with width and height limited to keep the area under max u16. /// If clipped, aspect ratio will be preserved. @@ -234,8 +269,8 @@ impl Rect { } } -#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] -pub enum SegmentSize { +#[derive(Debug, Default, Display, EnumString, Clone, Eq, PartialEq, Hash)] +pub(crate) enum SegmentSize { EvenDistribution, #[default] LastTakesRemainder, @@ -614,9 +649,181 @@ fn try_split(area: Rect, layout: &Layout) -> Result, AddConstraintErr #[cfg(test)] mod tests { + use strum::ParseError; + use super::{SegmentSize::*, *}; use crate::prelude::Constraint::*; + #[test] + fn corner_to_string() { + assert_eq!(Corner::BottomLeft.to_string(), "BottomLeft"); + assert_eq!(Corner::BottomRight.to_string(), "BottomRight"); + assert_eq!(Corner::TopLeft.to_string(), "TopLeft"); + assert_eq!(Corner::TopRight.to_string(), "TopRight"); + } + + #[test] + fn corner_from_str() { + assert_eq!("BottomLeft".parse::(), Ok(Corner::BottomLeft)); + assert_eq!("BottomRight".parse::(), Ok(Corner::BottomRight)); + assert_eq!("TopLeft".parse::(), Ok(Corner::TopLeft)); + assert_eq!("TopRight".parse::(), Ok(Corner::TopRight)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } + + #[test] + fn direction_to_string() { + assert_eq!(Direction::Horizontal.to_string(), "Horizontal"); + assert_eq!(Direction::Vertical.to_string(), "Vertical"); + } + + #[test] + fn direction_from_str() { + assert_eq!("Horizontal".parse::(), Ok(Direction::Horizontal)); + assert_eq!("Vertical".parse::(), Ok(Direction::Vertical)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } + + #[test] + fn constraint_to_string() { + assert_eq!(Constraint::Percentage(50).to_string(), "Percentage(50)"); + assert_eq!(Constraint::Ratio(1, 2).to_string(), "Ratio(1, 2)"); + assert_eq!(Constraint::Length(10).to_string(), "Length(10)"); + assert_eq!(Constraint::Max(10).to_string(), "Max(10)"); + assert_eq!(Constraint::Min(10).to_string(), "Min(10)"); + } + + #[test] + fn margin_to_string() { + assert_eq!(Margin::new(1, 2).to_string(), "1x2"); + } + + #[test] + fn margin_new() { + assert_eq!( + Margin::new(1, 2), + Margin { + horizontal: 1, + vertical: 2 + } + ); + } + + #[test] + fn alignment_to_string() { + assert_eq!(Alignment::Left.to_string(), "Left"); + assert_eq!(Alignment::Center.to_string(), "Center"); + assert_eq!(Alignment::Right.to_string(), "Right"); + } + + #[test] + fn alignment_from_str() { + assert_eq!("Left".parse::(), Ok(Alignment::Left)); + assert_eq!("Center".parse::(), Ok(Alignment::Center)); + assert_eq!("Right".parse::(), Ok(Alignment::Right)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } + + #[test] + fn rect_to_string() { + assert_eq!(Rect::new(1, 2, 3, 4).to_string(), "3x4+1+2"); + } + + #[test] + fn rect_new() { + assert_eq!( + Rect::new(1, 2, 3, 4), + Rect { + x: 1, + y: 2, + width: 3, + height: 4 + } + ); + } + + #[test] + fn rect_area() { + assert_eq!(Rect::new(1, 2, 3, 4).area(), 12); + } + + #[test] + fn rect_left() { + assert_eq!(Rect::new(1, 2, 3, 4).left(), 1); + } + + #[test] + fn rect_right() { + assert_eq!(Rect::new(1, 2, 3, 4).right(), 4); + } + + #[test] + fn rect_top() { + assert_eq!(Rect::new(1, 2, 3, 4).top(), 2); + } + + #[test] + fn rect_bottom() { + assert_eq!(Rect::new(1, 2, 3, 4).bottom(), 6); + } + + #[test] + fn rect_inner() { + assert_eq!( + Rect::new(1, 2, 3, 4).inner(&Margin::new(1, 2)), + Rect::new(2, 4, 1, 0) + ); + } + + #[test] + fn rect_union() { + assert_eq!( + Rect::new(1, 2, 3, 4).union(Rect::new(2, 3, 4, 5)), + Rect::new(1, 2, 5, 6) + ); + } + + #[test] + fn rect_intersection() { + assert_eq!( + Rect::new(1, 2, 3, 4).intersection(Rect::new(2, 3, 4, 5)), + Rect::new(2, 3, 2, 3) + ); + } + + #[test] + fn rect_intersects() { + assert!(Rect::new(1, 2, 3, 4).intersects(Rect::new(2, 3, 4, 5))); + assert!(!Rect::new(1, 2, 3, 4).intersects(Rect::new(5, 6, 7, 8))); + } + + #[test] + fn segment_size_to_string() { + assert_eq!( + SegmentSize::EvenDistribution.to_string(), + "EvenDistribution" + ); + assert_eq!( + SegmentSize::LastTakesRemainder.to_string(), + "LastTakesRemainder" + ); + assert_eq!(SegmentSize::None.to_string(), "None"); + } + + #[test] + fn segment_size_from_string() { + assert_eq!( + "EvenDistribution".parse::(), + Ok(EvenDistribution) + ); + assert_eq!( + "LastTakesRemainder".parse::(), + Ok(LastTakesRemainder) + ); + assert_eq!("None".parse::(), Ok(None)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } + fn get_x_width_with_segment_size( segment_size: SegmentSize, constraints: Vec, diff --git a/src/symbols.rs b/src/symbols.rs index 0f9728ef..33566c23 100644 --- a/src/symbols.rs +++ b/src/symbols.rs @@ -1,3 +1,5 @@ +use strum::{Display, EnumString}; + pub mod block { pub const FULL: &str = "█"; pub const SEVEN_EIGHTHS: &str = "▉"; @@ -240,7 +242,7 @@ pub mod braille { } /// Marker to use when plotting data points -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum Marker { /// One point per cell in shape of dot #[default] @@ -301,3 +303,27 @@ pub mod scrollbar { end: "→", }; } + +#[cfg(test)] +mod tests { + use strum::ParseError; + + use super::*; + + #[test] + fn marker_tostring() { + assert_eq!(Marker::Dot.to_string(), "Dot"); + assert_eq!(Marker::Block.to_string(), "Block"); + assert_eq!(Marker::Bar.to_string(), "Bar"); + assert_eq!(Marker::Braille.to_string(), "Braille"); + } + + #[test] + fn marker_from_str() { + assert_eq!("Dot".parse::(), Ok(Marker::Dot)); + assert_eq!("Block".parse::(), Ok(Marker::Block)); + assert_eq!("Bar".parse::(), Ok(Marker::Bar)); + assert_eq!("Braille".parse::(), Ok(Marker::Braille)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } +} diff --git a/src/terminal.rs b/src/terminal.rs index 18c3d570..14be202a 100644 --- a/src/terminal.rs +++ b/src/terminal.rs @@ -1,4 +1,4 @@ -use std::io; +use std::{fmt, io}; use crate::{ backend::{Backend, ClearType}, @@ -15,6 +15,16 @@ pub enum Viewport { Fixed(Rect), } +impl fmt::Display for Viewport { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Viewport::Fullscreen => write!(f, "Fullscreen"), + Viewport::Inline(height) => write!(f, "Inline({})", height), + Viewport::Fixed(area) => write!(f, "Fixed({})", area), + } + } +} + /// Options to pass to [`Terminal::with_options`] #[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] pub struct TerminalOptions { @@ -487,3 +497,18 @@ fn compute_inline_size( pos, )) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn viewport_to_string() { + assert_eq!(Viewport::Fullscreen.to_string(), "Fullscreen"); + assert_eq!(Viewport::Inline(5).to_string(), "Inline(5)"); + assert_eq!( + Viewport::Fixed(Rect::new(0, 0, 5, 5)).to_string(), + "Fixed(5x5+0+0)" + ); + } +} diff --git a/src/title.rs b/src/title.rs index f7f4736d..a73f0094 100644 --- a/src/title.rs +++ b/src/title.rs @@ -1,3 +1,5 @@ +use strum::{Display, EnumString}; + use crate::{layout::Alignment, text::Line}; #[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] @@ -10,7 +12,7 @@ pub struct Title<'a> { pub position: Option, } -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, PartialEq, Eq, Hash)] pub enum Position { #[default] Top, @@ -45,3 +47,23 @@ where Self::default().content(value.into()) } } + +#[cfg(test)] +mod tests { + use strum::ParseError; + + use super::*; + + #[test] + fn position_tostring() { + assert_eq!(Position::Top.to_string(), "Top"); + assert_eq!(Position::Bottom.to_string(), "Bottom"); + } + + #[test] + fn position_from_str() { + assert_eq!("Top".parse::(), Ok(Position::Top)); + assert_eq!("Bottom".parse::(), Ok(Position::Bottom)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } +} diff --git a/src/widgets/block.rs b/src/widgets/block.rs index 5589211b..45e03b9a 100644 --- a/src/widgets/block.rs +++ b/src/widgets/block.rs @@ -1,6 +1,8 @@ #[path = "../title.rs"] pub mod title; +use strum::{Display, EnumString}; + pub use self::title::{Position, Title}; use crate::{ buffer::Buffer, @@ -10,7 +12,7 @@ use crate::{ widgets::{Borders, Widget}, }; -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum BorderType { #[default] Plain, @@ -526,6 +528,8 @@ impl<'a> Styled for Block<'a> { #[cfg(test)] mod tests { + use strum::ParseError; + use super::*; use crate::{ assert_buffer_eq, @@ -985,4 +989,19 @@ mod tests { assert_buffer_eq!(buffer, expected_buffer); } } + + #[test] + fn border_type_to_string() { + assert_eq!(format!("{}", BorderType::Plain), "Plain"); + assert_eq!(format!("{}", BorderType::Rounded), "Rounded"); + assert_eq!(format!("{}", BorderType::Double), "Double"); + } + + #[test] + fn border_type_from_str() { + assert_eq!("Plain".parse(), Ok(BorderType::Plain)); + assert_eq!("Rounded".parse(), Ok(BorderType::Rounded)); + assert_eq!("Double".parse(), Ok(BorderType::Double)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } } diff --git a/src/widgets/canvas/map.rs b/src/widgets/canvas/map.rs index 37055c0a..37844717 100644 --- a/src/widgets/canvas/map.rs +++ b/src/widgets/canvas/map.rs @@ -1,3 +1,5 @@ +use strum::{Display, EnumString}; + use crate::{ style::Color, widgets::canvas::{ @@ -6,7 +8,7 @@ use crate::{ }, }; -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum MapResolution { #[default] Low, @@ -38,3 +40,26 @@ impl Shape for Map { } } } + +#[cfg(test)] +mod tests { + use strum::ParseError; + + use super::*; + + #[test] + fn map_resolution_to_string() { + assert_eq!(MapResolution::Low.to_string(), "Low"); + assert_eq!(MapResolution::High.to_string(), "High"); + } + + #[test] + fn map_resolution_from_str() { + assert_eq!("Low".parse(), Ok(MapResolution::Low)); + assert_eq!("High".parse(), Ok(MapResolution::High)); + assert_eq!( + "".parse::(), + Err(ParseError::VariantNotFound) + ); + } +} diff --git a/src/widgets/chart.rs b/src/widgets/chart.rs index 2dd19fdc..67f42147 100644 --- a/src/widgets/chart.rs +++ b/src/widgets/chart.rs @@ -1,5 +1,6 @@ use std::{borrow::Cow, cmp::max}; +use strum::{Display, EnumString}; use unicode_width::UnicodeWidthStr; use crate::{ @@ -76,7 +77,7 @@ impl<'a> Axis<'a> { } /// Used to determine which style of graphing to use -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum GraphType { /// Draw each point #[default] @@ -627,6 +628,8 @@ impl<'a> Styled for Chart<'a> { #[cfg(test)] mod tests { + use strum::ParseError; + use super::*; use crate::style::{Modifier, Stylize}; @@ -702,4 +705,17 @@ mod tests { .remove_modifier(Modifier::DIM) ) } + + #[test] + fn graph_type_to_string() { + assert_eq!(GraphType::Scatter.to_string(), "Scatter"); + assert_eq!(GraphType::Line.to_string(), "Line"); + } + + #[test] + fn graph_type_from_str() { + assert_eq!("Scatter".parse::(), Ok(GraphType::Scatter)); + assert_eq!("Line".parse::(), Ok(GraphType::Line)); + assert_eq!("".parse::(), Err(ParseError::VariantNotFound)); + } } diff --git a/src/widgets/scrollbar.rs b/src/widgets/scrollbar.rs index 356edcf4..fa63702c 100644 --- a/src/widgets/scrollbar.rs +++ b/src/widgets/scrollbar.rs @@ -1,3 +1,5 @@ +use strum::{Display, EnumString}; + use super::StatefulWidget; use crate::{ buffer::Buffer, @@ -7,7 +9,7 @@ use crate::{ }; /// An enum representing the direction of scrolling in a Scrollbar widget. -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum ScrollDirection { /// Forward scroll direction, usually corresponds to scrolling downwards or rightwards. #[default] @@ -101,7 +103,7 @@ impl ScrollbarState { } /// Scrollbar Orientation -#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Eq, PartialEq, Hash)] pub enum ScrollbarOrientation { #[default] VerticalRight, @@ -458,12 +460,80 @@ impl<'a> StatefulWidget for Scrollbar<'a> { #[cfg(test)] mod tests { + use strum::ParseError; + use super::*; use crate::{ assert_buffer_eq, symbols::scrollbar::{HORIZONTAL, VERTICAL}, }; + #[test] + fn scroll_direction_to_string() { + assert_eq!(ScrollDirection::Forward.to_string(), "Forward"); + assert_eq!(ScrollDirection::Backward.to_string(), "Backward"); + } + + #[test] + fn scroll_direction_from_str() { + assert_eq!( + "Forward".parse::(), + Ok(ScrollDirection::Forward) + ); + assert_eq!( + "Backward".parse::(), + Ok(ScrollDirection::Backward) + ); + assert_eq!( + "".parse::(), + Err(ParseError::VariantNotFound) + ); + } + + #[test] + fn scrollbar_orientation_to_string() { + assert_eq!( + ScrollbarOrientation::VerticalRight.to_string(), + "VerticalRight" + ); + assert_eq!( + ScrollbarOrientation::VerticalLeft.to_string(), + "VerticalLeft" + ); + assert_eq!( + ScrollbarOrientation::HorizontalBottom.to_string(), + "HorizontalBottom" + ); + assert_eq!( + ScrollbarOrientation::HorizontalTop.to_string(), + "HorizontalTop" + ); + } + + #[test] + fn scrollbar_orientation_from_str() { + assert_eq!( + "VerticalRight".parse::(), + Ok(ScrollbarOrientation::VerticalRight) + ); + assert_eq!( + "VerticalLeft".parse::(), + Ok(ScrollbarOrientation::VerticalLeft) + ); + assert_eq!( + "HorizontalBottom".parse::(), + Ok(ScrollbarOrientation::HorizontalBottom) + ); + assert_eq!( + "HorizontalTop".parse::(), + Ok(ScrollbarOrientation::HorizontalTop) + ); + assert_eq!( + "".parse::(), + Err(ParseError::VariantNotFound) + ); + } + #[test] fn test_no_render_when_area_zero() { let mut buffer = Buffer::empty(Rect::new(0, 0, 0, 0)); diff --git a/src/widgets/sparkline.rs b/src/widgets/sparkline.rs index 1e32cec4..7d85df17 100644 --- a/src/widgets/sparkline.rs +++ b/src/widgets/sparkline.rs @@ -1,5 +1,7 @@ use std::cmp::min; +use strum::{Display, EnumString}; + use crate::{ buffer::Buffer, layout::Rect, @@ -38,7 +40,7 @@ pub struct Sparkline<'a> { direction: RenderDirection, } -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Display, EnumString, Clone, Copy, Eq, PartialEq, Hash)] pub enum RenderDirection { #[default] LeftToRight, @@ -167,6 +169,8 @@ impl<'a> Widget for Sparkline<'a> { #[cfg(test)] mod tests { + use strum::ParseError; + use super::*; use crate::{ assert_buffer_eq, @@ -174,6 +178,28 @@ mod tests { style::{Color, Modifier, Stylize}, }; + #[test] + fn render_direction_to_string() { + assert_eq!(RenderDirection::LeftToRight.to_string(), "LeftToRight"); + assert_eq!(RenderDirection::RightToLeft.to_string(), "RightToLeft"); + } + + #[test] + fn render_direction_from_str() { + assert_eq!( + "LeftToRight".parse::(), + Ok(RenderDirection::LeftToRight) + ); + assert_eq!( + "RightToLeft".parse::(), + Ok(RenderDirection::RightToLeft) + ); + assert_eq!( + "".parse::(), + Err(ParseError::VariantNotFound) + ); + } + // Helper function to render a sparkline to a buffer with a given width // filled with x symbols to make it easier to assert on the result fn render(widget: Sparkline, width: u16) -> Buffer { diff --git a/src/widgets/table.rs b/src/widgets/table.rs index f1f14f3b..1810d0d1 100644 --- a/src/widgets/table.rs +++ b/src/widgets/table.rs @@ -1,3 +1,4 @@ +use strum::{Display, EnumString}; use unicode_width::UnicodeWidthStr; use crate::{ @@ -161,7 +162,7 @@ impl<'a> Styled for Row<'a> { } /// This option allows the user to configure the "highlight symbol" column width spacing -#[derive(Debug, PartialEq, Eq, Clone, Default, Hash)] +#[derive(Debug, Display, EnumString, PartialEq, Eq, Clone, Default, Hash)] pub enum HighlightSpacing { /// Always add spacing for the selection symbol column /// @@ -776,4 +777,34 @@ mod tests { .remove_modifier(Modifier::CROSSED_OUT) ) } + + #[test] + fn highlight_spacing_to_string() { + assert_eq!(HighlightSpacing::Always.to_string(), "Always".to_string()); + assert_eq!( + HighlightSpacing::WhenSelected.to_string(), + "WhenSelected".to_string() + ); + assert_eq!(HighlightSpacing::Never.to_string(), "Never".to_string()); + } + + #[test] + fn highlight_spacing_from_str() { + assert_eq!( + "Always".parse::(), + Ok(HighlightSpacing::Always) + ); + assert_eq!( + "WhenSelected".parse::(), + Ok(HighlightSpacing::WhenSelected) + ); + assert_eq!( + "Never".parse::(), + Ok(HighlightSpacing::Never) + ); + assert_eq!( + "".parse::(), + Err(strum::ParseError::VariantNotFound) + ); + } }