From 77fac82e0e4b8f1d7bb155791eeb077b3312f82f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 24 Dec 2023 16:46:59 +0000 Subject: [PATCH] Maybe the version with slices? --- src/coloured_string.rs | 90 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/src/coloured_string.rs b/src/coloured_string.rs index 446bdc6..9f4ae85 100644 --- a/src/coloured_string.rs +++ b/src/coloured_string.rs @@ -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 for ColouredString { type Output = Self; fn add(self, rhs: Self) -> Self { @@ -81,29 +117,47 @@ impl std::ops::Add 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 { 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); } -- 2.30.2