use unicode_width::UnicodeWidthStr;
+use unicode_width::UnicodeWidthChar;
#[derive(Debug, Clone)]
pub struct ColouredString {
colourpos: usize,
}
+pub struct ColouredStringSplitIterator<'a> {
+ cs: &'a ColouredString,
+ width: usize,
+ textpos: usize,
+ colourpos: usize,
+}
+
impl<'a> ColouredString {
pub fn frags(&'a self) -> ColouredStringFragIterator<'a> {
ColouredStringFragIterator {
colourpos: 0,
}
}
+ pub fn split(&'a self, width: usize) -> ColouredStringSplitIterator<'a> {
+ ColouredStringSplitIterator {
+ cs: self,
+ width: width,
+ textpos: 0,
+ colourpos: 0,
+ }
+ }
}
impl<'a> Iterator for ColouredStringFragIterator<'a> {
}
}
+fn char_width_infallible(c: char) -> usize {
+ match UnicodeWidthChar::width(c) {
+ Some(w) => w,
+ None => 0,
+ }
+}
+
+impl<'a> Iterator for ColouredStringSplitIterator<'a> {
+ type Item = ColouredString;
+ fn next(&mut self) -> Option<Self::Item> {
+ let textslice = &self.cs.text[self.textpos..];
+ let mut textit = textslice.char_indices();
+ let colourslice = &self.cs.colour[self.colourpos..];
+ let mut colourit = colourslice.char_indices();
+ match (textit.next(), colourit.next()) {
+ (None, None) => None,
+ (Some((_, tc)), Some(_)) => {
+ let mut tpos: usize = 0;
+ let mut cpos: usize = 0;
+ let mut width: usize = 0;
+ let mut last_tc = tc;
+ let (textend, colourend) = loop {
+ let wc = char_width_infallible(last_tc);
+ if width + wc > self.width {
+ break (tpos, cpos);
+ }
+ width += wc;
+ match (textit.next(), colourit.next()) {
+ (None, None) => {
+ break (textslice.len(), colourslice.len());
+ },
+ (Some((ti, tc)), Some((ci, _))) => {
+ tpos = ti;
+ cpos = ci;
+ last_tc = tc;
+ },
+ _ => panic!("length mismatch in CSSI"),
+ };
+ };
+ self.textpos += textend;
+ self.colourpos += colourend;
+ Some(ColouredString::general(&textslice[..textend],
+ &colourslice[..colourend]))
+ },
+ _ => panic!("length mismatch in CSSI"),
+ }
+ }
+}
+
#[test]
fn test_constructors() {
assert_eq!(ColouredString::plain("hello"),
assert_eq!(frags.next(), Some(("wèasël", 'v')));
assert_eq!(frags.next(), None);
}
+
+#[test]
+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(), 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(), None);
+
+ let cs = ColouredString::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(), None);
+}