chiark / gitweb /
More, but still not finished
authorSimon Tatham <anakin@pobox.com>
Sun, 24 Dec 2023 13:48:15 +0000 (13:48 +0000)
committerSimon Tatham <anakin@pobox.com>
Sun, 24 Dec 2023 15:11:07 +0000 (15:11 +0000)
I'm not at all sure that counting by chars is what I really want, hmmm.

src/coloured_string.rs

index 6306d91480cafad634ab7f91ce760015cc53db30..25bc8dc67448f93ce1f3ad45dda059c3e5d88a1e 100644 (file)
@@ -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<ColouredString> 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<ColouredString> 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);
+}