use std::{collections::VecDeque, io, usize};
mod termwrap;
use termwrap::{ConsoleTermWrap, TermWrap};
pub struct TermSnip<'a> {
term: Box<dyn TermWrap + 'a>,
limit: usize,
lines: VecDeque<String>,
}
impl<'a> TermSnip<'a> {
pub fn new(limit: usize) -> TermSnip<'a> {
TermSnip {
term: Box::new(ConsoleTermWrap::new()),
limit,
lines: VecDeque::new(),
}
}
pub fn write_line(&mut self, text: &str) -> io::Result<()> {
let line_len: usize = self.term.size().1.into();
if text.chars().count() < line_len {
self.term_write_line(text)?;
return Ok(());
}
let mut last_text = text;
while last_text.chars().count() >= line_len {
let (first, last) = last_text.split_at(line_len);
last_text = last;
self.term_write_line(first)?;
}
self.term_write_line(last_text)?;
Ok(())
}
fn term_write_line(&mut self, text: &str) -> io::Result<()> {
self.lines.push_back(text.to_string());
if self.lines.len() > self.limit {
self.lines.pop_front();
self.clear_lines()?;
for line in &self.lines {
self.term.write_line(line)?;
}
} else {
self.term.write_line(text)?;
}
Ok(())
}
pub fn clear_lines(&mut self) -> io::Result<()> {
self.term.clear_last_lines(self.lines.len())?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use mockall::predicate::eq;
#[test]
fn test_simple_one_line() {
let mut termwrap_mock = termwrap::MockTermWrap::new();
termwrap_mock.expect_size().returning(|| (20, 20));
termwrap_mock
.expect_write_line()
.with(eq("test"))
.times(1)
.returning(|_x| Ok(()));
let mut term_snip = TermSnip {
term: Box::new(termwrap_mock),
limit: 5,
lines: VecDeque::new(),
};
term_snip.write_line("test").unwrap();
}
#[test]
fn test_six_lines_with_limit_5() {
let mut termwrap_mock = termwrap::MockTermWrap::new();
termwrap_mock.expect_size().returning(|| (20, 20));
termwrap_mock
.expect_write_line()
.times(10)
.returning(|_x| Ok(()));
termwrap_mock
.expect_clear_last_lines()
.with(eq(5))
.times(1)
.returning(|_x| Ok(()));
let mut term_snip = TermSnip {
term: Box::new(termwrap_mock),
limit: 5,
lines: VecDeque::new(),
};
for _n in 0..6 {
term_snip.write_line("test").unwrap();
}
}
#[test]
fn test_long_line_split() {
let mut termwrap_mock = termwrap::MockTermWrap::new();
termwrap_mock.expect_size().returning(|| (20, 6));
termwrap_mock
.expect_write_line()
.times(3)
.returning(|_x| Ok(()));
let mut term_snip = TermSnip {
term: Box::new(termwrap_mock),
limit: 5,
lines: VecDeque::new(),
};
let testline = "Lorem ipsum dolor";
term_snip.write_line(testline).unwrap();
}
}