From 830f3fceb75968e518d79ca2b980239eeec9af09 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 24 Dec 2023 13:48:15 +0000 Subject: [PATCH] More, but still not finished I'm not at all sure that counting by chars is what I really want, hmmm. --- src/coloured_string.rs | 109 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 101 insertions(+), 8 deletions(-) diff --git a/src/coloured_string.rs b/src/coloured_string.rs index 6306d91..25bc8dc 100644 --- a/src/coloured_string.rs +++ b/src/coloured_string.rs @@ -1,3 +1,6 @@ +use unicode_width::UnicodeWidthStr; + +#[derive(Debug, Clone)] pub struct ColouredString { text: String, colour: String, @@ -5,17 +8,107 @@ pub struct ColouredString { impl ColouredString { pub fn plain(text: &str) -> Self { - ColouredString { text: text.to_string(), - colour: " ".repeat(text.len()) } + ColouredString { + text: text.to_string(), + colour: " ".repeat(text.chars().count()), + } } pub fn uniform(text: &str, colour: char) -> Self { - ColouredString { text: text.to_string(), - colour: colour.to_string().repeat(text.len()) } + ColouredString { + text: text.to_string(), + colour: colour.to_string().repeat(text.chars().count()), + } } pub fn general(text: &str, colour: &str) -> Self { - assert!(text.len() == colour.len(), - "Mismatched lengths in ColouredString::general"); - ColouredString { text: text.to_string(), - colour: colour.to_string() } + assert_eq!(text.chars().count(), colour.chars().count(), + "Mismatched lengths in ColouredString::general"); + ColouredString { + text: text.to_string(), + colour: colour.to_string(), + } + } + + pub fn repeat(self, count: usize) -> Self { + ColouredString { + text: self.text.repeat(count), + colour: self.colour.repeat(count), + } + } + + pub fn nchars(&self) -> usize { self.text.chars().count() } + pub fn width(&self) -> usize { UnicodeWidthStr::width(&self.text as &str) } + + pub fn text(&self) -> &str { &self.text } +} + +impl PartialEq for ColouredString { + fn eq(&self, rhs: &Self) -> bool { + self.text == rhs.text && self.colour == rhs.colour } } + +impl Eq for ColouredString {} + +impl std::ops::Add for ColouredString { + type Output = Self; + fn add(self, rhs: Self) -> Self { + ColouredString { + text: self.text + &rhs.text, + colour: self.colour + &rhs.colour, + } + } +} + +impl std::ops::Add<&str> for ColouredString { + type Output = Self; + fn add(self, rhs: &str) -> Self { + ColouredString { + text: self.text + rhs, + colour: self.colour + &(" ".repeat(rhs.chars().count())), + } + } +} + +impl std::ops::Add for &str { + type Output = ColouredString; + fn add(self, rhs: ColouredString) -> ColouredString { + ColouredString { + text: self.to_string() + &rhs.text, + colour: (" ".repeat(self.chars().count())) + &rhs.colour, + } + } +} + +#[test] +fn test_constructors() { + assert_eq!(ColouredString::plain("hello"), + ColouredString::general("hello", " ")); + assert_eq!(ColouredString::uniform("hello", 'a'), + ColouredString::general("hello", "aaaaa")); +} + +#[test] +fn test_repeat() { + assert_eq!(ColouredString::general("xyz", "pqr").repeat(3), + ColouredString::general("xyzxyzxyz", "pqrpqrpqr")); +} + +#[test] +fn test_concat() { + assert_eq!(ColouredString::general("xyz", "pqr") + + ColouredString::general("abcde", "ijklm"), + ColouredString::general("xyzabcde", "pqrijklm")); + assert_eq!(ColouredString::general("xyz", "pqr") + "abcde", + ColouredString::general("xyzabcde", "pqr ")); + assert_eq!("abcde" + ColouredString::general("xyz", "pqr"), + ColouredString::general("abcdexyz", " pqr")); +} + +#[test] +fn test_lengths() { + assert_eq!(ColouredString::general("xyz", "pqr").nchars(), 3); + assert_eq!(ColouredString::general("xyz", "pqr").width(), 3); + + assert_eq!(ColouredString::general("xy\u{302}z", "pqqr").nchars(), 4); + assert_eq!(ColouredString::general("xy\u{302}z", "pqqr").width(), 3); +} -- 2.30.2