+use unicode_width::UnicodeWidthStr;
+
+#[derive(Debug, Clone)]
pub struct ColouredString {
text: String,
colour: String,
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);
+}