diff --git a/Cargo.toml b/Cargo.toml index 88c408a..558a09d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" edition = "2018" [dependencies] -tui = { version = "0.14.0", default-features = false } +tui = { version = "0.14.0", default-features = false, features = ["crossterm"] } +unicode-width = "0.1.8" diff --git a/log b/log new file mode 100644 index 0000000..3206dd2 --- /dev/null +++ b/log @@ -0,0 +1 @@ +AAAAAAAA \ No newline at end of file diff --git a/src/ansi.rs b/src/ansi.rs index 275637c..12f0f68 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -158,7 +158,7 @@ impl AnsiGraphicsStack { last_sequence = sequence; } self.stack.clear(); - println!("style {:?}", style); + // println!("style {:?}", style); // println!("-----------------------------"); style } @@ -171,6 +171,7 @@ pub fn ansi_to_text<'t, B: AsRef<[u8]>>(bytes: B) -> Result, Error> { let mut ansi_stack: AnsiGraphicsStack = AnsiGraphicsStack::new(); let mut num_stack: Stack = Stack::new(); let mut graphics_start: bool = false; + let mut spans_buffer: Vec = Vec::new(); let mut line_buffer = String::new(); // let mut last_byte: &u8 = reader.next().expect("Zero size bytes buffer"); let mut last_byte: &u8 = &0_u8; @@ -178,10 +179,8 @@ pub fn ansi_to_text<'t, B: AsRef<[u8]>>(bytes: B) -> Result, Error> { match (last_byte, byte) { (&b'\x1b', &b'[') => { if style.is_some() { - buffer.push(Spans::from(Span::styled( - line_buffer.clone(), - style.unwrap(), - ))); + spans_buffer.push(Span::styled(line_buffer.clone(), style.unwrap())); + line_buffer.clear(); } graphics_start = true; } @@ -198,12 +197,17 @@ pub fn ansi_to_text<'t, B: AsRef<[u8]>>(bytes: B) -> Result, Error> { } } else if code != &b'\x1b' { line_buffer.push(*code as char) + } else if code == &b'\n' { + buffer.push(Spans::from(spans_buffer.clone())); + spans_buffer.clear(); } last_byte = code; } } } - println!("{:?}", buffer); + // println!("{:?}", buffer); + buffer.push(Spans::from(spans_buffer.clone())); + spans_buffer.clear(); Ok(buffer.into()) } diff --git a/src/main.rs b/src/main.rs index 8372195..0c548f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,13 +5,87 @@ mod error; mod stack; mod style; mod tests; -use std::io::Read; +use io::{Read, Stdout}; +use std::io; +use tui::{ + backend::{Backend, CrosstermBackend}, + buffer::Buffer, + buffer::Cell, + layout::Rect, + widgets::{Paragraph, Widget}, +}; +use unicode_width::UnicodeWidthStr; use ansi::ansi_to_text; pub fn main() { - // let mut file = std::fs::File::open("log").unwrap(); - let mut file = std::fs::File::open("archlinux.ascii").unwrap(); + let mut file = std::fs::File::open("log").unwrap(); + // let mut file = std::fs::File::open("archlinux.ascii").unwrap(); let mut buffer: Vec = Vec::new(); + let mut backend = CrosstermBackend::new(io::stdout()); + let mut tmp_buffer = Buffer::empty(Rect::new(0, 0, 500, 500)); + file.read_to_end(&mut buffer).unwrap(); - let _text = ansi_to_text(buffer); + let _text = ansi_to_text(buffer).unwrap(); + println!("{:?}", _text); + + Paragraph::new(_text).render(Rect::new(1, 1, 10, 10), &mut tmp_buffer); + write_buffer_to_console(&mut backend, &mut tmp_buffer).unwrap(); +} + +fn find_last_buffer_cell_index(buf: &Buffer) -> Option<(u16, u16)> { + let empty_cell = Cell::default(); + + if let Some((idx, _)) = buf + .content + .iter() + .enumerate() + .filter(|p| !(*(p.1)).eq(&empty_cell)) + .last() + { + return Some(buf.pos_of(idx)); + } + + None +} + +fn write_buffer_to_console( + backend: &mut CrosstermBackend, + tmp_buffer: &mut Buffer, +) -> Result<(), io::Error> { + let (_, last_y) = + find_last_buffer_cell_index(tmp_buffer).expect("Error while writing to terminal buffer."); + + print!("{}", "\n".repeat(last_y as usize + 1)); + + let mut cursor_y: u16 = 0; + + let term_size = backend.size().unwrap_or_default(); + // We need a checked subtraction here, because (cursor_y - last_y - 1) might underflow if the + // cursor_y is smaller than (last_y - 1). + let starting_pos = cursor_y.saturating_sub(last_y).saturating_sub(1); + let mut skip_n = 0; + + let iter = tmp_buffer + .content + .iter() + .enumerate() + .filter(|(_previous, cell)| { + let curr_width = cell.symbol.width(); + if curr_width == 0 { + return false; + } + + let old_skip = skip_n; + skip_n = curr_width.saturating_sub(1); + old_skip == 0 + }) + .map(|(idx, cell)| { + let (x, y) = tmp_buffer.pos_of(idx); + (x, y, cell) + }) + .filter(|(x, y, _)| *x < term_size.width && *y <= last_y) + .map(|(x, y, cell)| (x, y + starting_pos, cell)); + + backend.draw(iter)?; + Ok(()) }