chiark / gitweb /
Maybe the version with slices?
authorSimon Tatham <anakin@pobox.com>
Sun, 24 Dec 2023 16:46:59 +0000 (16:46 +0000)
committerSimon Tatham <anakin@pobox.com>
Sun, 24 Dec 2023 16:46:59 +0000 (16:46 +0000)
src/coloured_string.rs

index 446bdc6e883af2a3ee8aa55b1162ef37873a0d4a..9f4ae851d51e10e3b5035ba8ec951a0c974b7626 100644 (file)
@@ -7,6 +7,12 @@ pub struct ColouredString {
     colour: String,
 }
 
+#[derive(Debug, Clone)]
+pub struct ColouredStringSlice<'a> {
+    text: &'a str,
+    colour: &'a str,
+}
+
 impl ColouredString {
     pub fn plain(text: &str) -> Self {
         ColouredString {
@@ -40,6 +46,28 @@ impl ColouredString {
     pub fn width(&self) -> usize { UnicodeWidthStr::width(&self.text as &str) }
 
     pub fn text(&self) -> &str { &self.text }
+
+    pub fn slice(&self) -> ColouredStringSlice {
+        ColouredStringSlice {
+            text: &self.text,
+            colour: &self.colour,
+        }
+    }
+}
+
+impl<'a> ColouredStringSlice<'a> {
+    pub fn general(text: &'a str, colour: &'a str) -> Self {
+        assert_eq!(text.chars().count(), colour.chars().count(),
+                   "Mismatched lengths in ColouredStringSlice::general");
+        ColouredStringSlice {
+            text: text,
+            colour: colour,
+        }
+    }
+
+    pub fn nchars(&self) -> usize { self.text.chars().count() }
+    pub fn width(&self) -> usize { UnicodeWidthStr::width(&self.text as &str) }
+    pub fn text(&self) -> &'a str { &self.text }
 }
 
 impl PartialEq for ColouredString {
@@ -50,6 +78,14 @@ impl PartialEq for ColouredString {
 
 impl Eq for ColouredString {}
 
+impl<'a> PartialEq for ColouredStringSlice<'a> {
+    fn eq(&self, rhs: &ColouredStringSlice) -> bool {
+        self.text == rhs.text && self.colour == rhs.colour
+    }
+}
+
+impl<'a> Eq for ColouredStringSlice<'a> {}
+
 impl std::ops::Add<ColouredString> for ColouredString {
     type Output = Self;
     fn add(self, rhs: Self) -> Self {
@@ -81,29 +117,47 @@ impl std::ops::Add<ColouredString> for &str {
 }
 
 pub struct ColouredStringFragIterator<'a> {
-    cs: &'a ColouredString,
+    cs: ColouredStringSlice<'a>,
     textpos: usize,
     colourpos: usize,
 }
 
 pub struct ColouredStringSplitIterator<'a> {
-    cs: &'a ColouredString,
+    cs: ColouredStringSlice<'a>,
     width: usize,
     textpos: usize,
     colourpos: usize,
 }
 
+impl<'a> ColouredStringSlice<'a> {
+    pub fn frags(&self) -> ColouredStringFragIterator<'a> {
+        ColouredStringFragIterator {
+            cs: self.clone(),
+            textpos: 0,
+            colourpos: 0,
+        }
+    }
+    pub fn split(&'a self, width: usize) -> ColouredStringSplitIterator<'a> {
+        ColouredStringSplitIterator {
+            cs: self.clone(),
+            width: width,
+            textpos: 0,
+            colourpos: 0,
+        }
+    }
+}
+
 impl<'a> ColouredString {
     pub fn frags(&'a self) -> ColouredStringFragIterator<'a> {
         ColouredStringFragIterator {
-            cs: self,
+            cs: self.slice(),
             textpos: 0,
             colourpos: 0,
         }
     }
     pub fn split(&'a self, width: usize) -> ColouredStringSplitIterator<'a> {
         ColouredStringSplitIterator {
-            cs: self,
+            cs: self.slice(),
             width: width,
             textpos: 0,
             colourpos: 0,
@@ -150,7 +204,7 @@ fn char_width_infallible(c: char) -> usize {
 }
 
 impl<'a> Iterator for ColouredStringSplitIterator<'a> {
-    type Item = ColouredString;
+    type Item = ColouredStringSlice<'a>;
     fn next(&mut self) -> Option<Self::Item> {
         let textslice = &self.cs.text[self.textpos..];
         let mut textit = textslice.char_indices();
@@ -183,8 +237,10 @@ impl<'a> Iterator for ColouredStringSplitIterator<'a> {
                 };
                 self.textpos += textend;
                 self.colourpos += colourend;
-                Some(ColouredString::general(&textslice[..textend],
-                                             &colourslice[..colourend]))
+                Some(ColouredStringSlice {
+                        text: &textslice[..textend],
+                        colour: &colourslice[..colourend],
+                    })
             },
             _ => panic!("length mismatch in CSSI"),
         }
@@ -239,20 +295,20 @@ fn test_frags() {
 fn test_split() {
     let cs = ColouredString::general("abcdefgh", "mnopqrst");
     let mut lines = cs.split(3);
-    assert_eq!(lines.next(), Some(ColouredString::general("abc", "mno")));
-    assert_eq!(lines.next(), Some(ColouredString::general("def", "pqr")));
-    assert_eq!(lines.next(), Some(ColouredString::general("gh", "st")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("abc", "mno")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("def", "pqr")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("gh", "st")));
     assert_eq!(lines.next(), None);
     let mut lines = cs.split(4);
-    assert_eq!(lines.next(), Some(ColouredString::general("abcd", "mnop")));
-    assert_eq!(lines.next(), Some(ColouredString::general("efgh", "qrst")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("abcd", "mnop")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("efgh", "qrst")));
     assert_eq!(lines.next(), None);
 
-    let cs = ColouredString::general("ab\u{4567}defgh", "mnopqrst");
+    let cs = ColouredStringSlice::general("ab\u{4567}defgh", "mnopqrst");
     let mut lines = cs.split(3);
-    assert_eq!(lines.next(), Some(ColouredString::general("ab", "mn")));
-    assert_eq!(lines.next(), Some(ColouredString::general("\u{4567}d", "op")));
-    assert_eq!(lines.next(), Some(ColouredString::general("efg", "qrs")));
-    assert_eq!(lines.next(), Some(ColouredString::general("h", "t")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("ab", "mn")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("\u{4567}d", "op")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("efg", "qrs")));
+    assert_eq!(lines.next(), Some(ColouredStringSlice::general("h", "t")));
     assert_eq!(lines.next(), None);
 }