diff --git a/Cargo.toml b/Cargo.toml index 558a09d..fc5c7a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "ansi-to-tui" -version = "0.1.0" +version = "0.1.1" edition = "2018" [dependencies] -tui = { version = "0.14.0", default-features = false, features = ["crossterm"] } -unicode-width = "0.1.8" +tui = { version = "0.14.0", default-features = false } diff --git a/README.md b/README.md new file mode 100644 index 0000000..1149fb8 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# ansi-to-tui + +Parse text with ansi color codes and turn them into [`tui::text::Text`](https://docs.rs/tui/0.14.0/tui/text/struct.Text.html). + +Supports TrueColor ( RGB ) ( `\x1b[38;2;;;m`) +Supports 8 - Bit Color ( 0..256 ) ( `\x1b[38;5;m` ) +Supports 4 - Bit Color Pallete ( `\x1b[30..37;40..47m` ) + +A naive implementation, relatively fast. +Only dependency is the tui crate. +Lots of room for improvement. diff --git a/ansi.py b/ansi.py deleted file mode 100755 index 5bd301f..0000000 --- a/ansi.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python - -# for code in range(107): -# print(f"\x1b[{code}mTHIS IS TEXT\x1b[0m") - -# for z in range(255): -# print( -# f"\x1b[{38};{5};{z};{1};{7};{3};{5};{4}mTEXT \\x1b[{38};{5};{z}m\\1xb[0m\x1b[0m") - -llist = [27, 49, 49, 49, 51, 49, 109, 49, 50, 51, 52, 27, 48, 109, ] - -for l in llist: - print(chr(l)) diff --git a/src/ansi.rs b/src/ansi.rs index 3201c30..d2ba16b 100644 --- a/src/ansi.rs +++ b/src/ansi.rs @@ -30,7 +30,7 @@ impl Stack { let r = self.pop().unwrap(); color = Color::Rgb(r, g, b); } else { - return Err(Error::TempError); + return Err(Error::UnknownColor); } self.clear(); Ok(color) @@ -75,7 +75,6 @@ impl AnsiGraphicsStack { let mut color_parse_mode: Option = None; let mut last_sequence: usize = 0; let mut color_layer: Option = None; - // println!("{:?}", self); for sequence in self.iter().cloned() { if color_parse { if sequence < 255 { @@ -121,7 +120,6 @@ impl AnsiGraphicsStack { color_parse = false; } } else { - // println!("stop color index"); color_parse = false; } last_sequence = sequence; @@ -142,12 +140,10 @@ impl AnsiGraphicsStack { AnsiCode::DefaultForegroundColor => style = style.fg(Color::Reset), AnsiCode::DefaultBackgroundColor => style = style.bg(Color::Reset), AnsiCode::ForegroundColorIndex => { - // println!("foreground color index"); color_parse = true; color_layer = Some(AnsiColorLayer::Foreground) } AnsiCode::BackgroundColorIndex => { - // println!("background color index"); color_parse = true; color_layer = Some(AnsiColorLayer::Background) } @@ -158,8 +154,6 @@ impl AnsiGraphicsStack { last_sequence = sequence; } self.stack.clear(); - // println!("style {:?}", style); - // println!("-----------------------------"); style } } @@ -207,18 +201,10 @@ pub fn ansi_to_text<'t, B: AsRef<[u8]>>(bytes: B) -> Result, Error> { } last_byte = byte; } - // println!("{:?}", buffer); if !spans_buffer.is_empty() { buffer.push(Spans::from(spans_buffer.clone())); spans_buffer.clear(); } - // for span in buffer.iter() { - // println!("HELLOA"); - // println!("{:?}", span); - // } - - // println!("bufferlen {}", buffer.len()); - // println!("{:?}", &buffer); Ok(buffer.into()) } diff --git a/src/color.rs b/src/color.rs index 330883d..eeceedd 100644 --- a/src/color.rs +++ b/src/color.rs @@ -45,22 +45,3 @@ impl From for Color { } } } -// pub fn ansi_to_color(ansi: u8) -> AnsiColor { -// match ansi { -// 30 | 40 => AnsiColor::Black, -// 31 | 41 => AnsiColor::Red, -// 32 | 42 => AnsiColor::Green, -// 33 | 43 => AnsiColor::Yellow, -// 34 | 44 => AnsiColor::Blue, -// 35 | 45 => AnsiColor::Gray, -// 90 | 100 => AnsiColor::DarkGray, -// 91 | 101 => AnsiColor::LightRed, -// 92 | 102 => AnsiColor::LightGreen, -// 93 | 103 => AnsiColor::LightYellow, -// 94 | 104 => AnsiColor::LightBlue, -// 95 | 105 => AnsiColor::LightMagenta, -// 96 | 106 => AnsiColor::LightCyan, -// 97 | 107 => AnsiColor::White, -// _ => AnsiColor::Black, -// } -// } diff --git a/src/error.rs b/src/error.rs index d62b315..19e1e0c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,5 +4,5 @@ pub enum Error { StackLocked, StackUnlocked, InvalidAnsi, - TempError, + UnknownColor, } diff --git a/src/lib.rs b/src/lib.rs index b47bb9e..d7a5a35 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ mod code; mod color; mod error; mod stack; -mod style; mod tests; pub use ansi::ansi_to_text; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 057d755..0000000 --- a/src/main.rs +++ /dev/null @@ -1,92 +0,0 @@ -#![allow(dead_code)] -mod ansi; -mod code; -mod color; -mod error; -mod stack; -mod style; -mod tests; -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("").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).unwrap(); - // println!("{:?}", _text); - - Paragraph::new(_text).render(Rect::new(1, 1, 50, 50), &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(()) -} diff --git a/src/style.rs b/src/style.rs deleted file mode 100644 index 8ee847f..0000000 --- a/src/style.rs +++ /dev/null @@ -1,40 +0,0 @@ -// use crate::ansi::AnsiGraphicsStack; -// use crate::code::AnsiCode; -// use crate::color::AnsiColor; -// use tui::style::Style; - -// pub struct AnsiStyle { -// foreground: Option, -// background: Option, -// effect: Vec, -// } - -// impl AnsiStyle { -// pub fn new() -> Self { -// Self { -// foreground: None, -// background: None, -// effect: Vec::::new(), -// } -// } -// } -// impl From for Style { -// fn from(ansi_style: AnsiStyle) -> Self { -// let style = Style::default(); -// todo!(); -// } -// } - -// impl From for AnsiStyle { -// fn from(stack: AnsiGraphicsStack) -> Self { -// AnsiStyle::new() -// // for style in stack.iter() { -// // match style { -// // 1..=11 | 20..=25 | 27..=29 | 38 | 39 => { -// // *style as AnsiCode; -// // } -// // _ => (), -// // } -// // } -// } -// } diff --git a/src/tests.rs b/src/tests.rs index 7f8c63f..d8e65c6 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,7 +1,13 @@ #[cfg(test)] #[test] fn test_color() { - use crate::ansi_to_color; + use crate::stack::Stack; use tui::style::Color; - assert_eq!(ansi_to_color(31_u8), Color::Red); + let mut stack: Stack = Stack::new(); + stack.push(30); + assert_eq!(stack.parse_color().unwrap(), Color::Indexed(30)); + stack.push(30); + stack.push(3); + stack.push(55); + assert_eq!(stack.parse_color().unwrap(), Color::Rgb(30, 3, 55)); }