//! niri's fill/clear/continue row. Repaints never consume a sample twice. use unicode_segmentation::UnicodeSegmentation; use unicode_width::UnicodeWidthStr; #[derive(Default)] pub struct CodeLine { source: String, width: usize, line: String, } impl CodeLine { pub fn advance(&mut self, code: &str, width: usize) -> &str { let continued = self.width == width && code.starts_with(&self.source); let start = if continued { self.source.len() } else { self.line.clear(); 0 }; for grapheme in code[start..].graphemes(true) { let safe: String = grapheme .chars() .map(|c| if c.is_control() { ' ' } else { c }) .collect(); if self.line.width() + safe.width() > width { self.line.clear(); } if safe.width() <= width { self.line.push_str(&safe); } } self.source.clear(); self.source.push_str(code); self.width = width; &self.line } } #[cfg(test)] mod tests { use super::*; #[test] fn fill_clear_continue_repaint_resize_and_correction() { let mut row = CodeLine::default(); assert_eq!(row.advance("abcdef", 5), "f"); assert_eq!(row.advance("abcdef", 5), "f"); assert_eq!(row.advance("abcdef\ng", 5), "f g"); assert_eq!(row.advance("abcdef\ng", 4), "ef g"); assert_eq!(row.advance("界界é", 4), "é"); assert_eq!(row.advance("x", 0), ""); } }