diff --git a/Cargo.lock b/Cargo.lock index 8ee26d8..3c0a8a5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "ansi-parser" -version = "0.3.0" +version = "0.4.0" dependencies = [ "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/enums.rs b/src/enums.rs index 744abd3..427aedc 100644 --- a/src/enums.rs +++ b/src/enums.rs @@ -1,47 +1,6 @@ #[cfg(test)] mod tests; -use num_derive::FromPrimitive; -use num_derive::ToPrimitive; - -use num_traits::ToPrimitive; - -///A list of available text attributes. -#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)] -pub enum TextAttribute { - Off = 0, - Bold = 1, - Underscore = 4, - Blink = 5, - ReverseVideo = 7, - Concealed = 8 -} - -impl Display for TextAttribute { - fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(formatter, "{}", self.to_u8().unwrap_or(0)) - } -} - -///The basic ANSI colors. -#[derive(Debug, PartialEq, FromPrimitive, ToPrimitive)] -pub enum Color { - Black = 30, - Red = 31, - Green = 32, - Yellow = 33, - Blue = 34, - Magenta = 35, - Cyan = 36, - White = 37 -} - -impl Display for Color { - fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(formatter, "{}", self.to_u8().unwrap_or(0)) - } -} - ///The following are the implemented ANSI escape sequences. More to be added. #[derive(Debug, PartialEq)] pub enum AnsiSequence { @@ -54,13 +13,10 @@ pub enum AnsiSequence { CursorRestore, EraseDisplay, EraseLine, - SetGraphicsMode{ - ta: TextAttribute, - fg: Color, - bg: Color - }, + SetGraphicsMode(Vec), SetMode(u8), ResetMode(u8), +// HideCursor, } use std::fmt::Display; @@ -88,8 +44,15 @@ impl Display for AnsiSequence { => write!(formatter, "2J"), EraseLine => write!(formatter, "K"), - SetGraphicsMode{ta, fg, bg} - => write!(formatter, "{};{};{}m", ta, fg, bg), + SetGraphicsMode(vec) + => { + match vec.len() { + 1 => write!(formatter, "{}m", vec[0]), + 2 => write!(formatter, "{};{}m", vec[0], vec[1]), + 3 => write!(formatter, "{};{};{}m", vec[0], vec[1], vec[2]), + _ => unreachable!() + } + }, SetMode(mode) => write!(formatter, "={}h", mode), ResetMode(mode) diff --git a/src/parsers.rs b/src/parsers.rs index 797c727..7b6d5f1 100644 --- a/src/parsers.rs +++ b/src/parsers.rs @@ -1,55 +1,21 @@ #[cfg(test)] mod tests; -use crate::{AnsiSequence, Output, Color, TextAttribute}; +use crate::{AnsiSequence, Output}; -use num_traits::cast::FromPrimitive; use std::convert::TryInto; use nom::*; named!( - parse_int, + parse_int<&str, u32>, map_res!( - map_res!( - nom::digit, - std::str::from_utf8 - ), + nom::digit, |s: &str| s.parse::() ) ); named!( - parse_fg_color, - do_parse!( - val: parse_int >> - worked: expr_opt!(FromPrimitive::from_u32(val)) >> - (worked) - ) -); - -named!( - parse_bg_color, - do_parse!( - val: parse_int >> - val: expr_opt!(val.checked_sub(10)) >> - worked: expr_opt!(FromPrimitive::from_u32(val)) >> - (worked) - ) -); - -named!( - parse_text_attr, - map!( - map!( - parse_int, - FromPrimitive::from_u32 - ), - Option::unwrap - ) -); - -named!( - cursor_pos, + cursor_pos<&str, AnsiSequence>, do_parse!( x: parse_int >> tag!(";") >> @@ -63,7 +29,7 @@ named!( ); named!( - cursor_up, + cursor_up<&str, AnsiSequence>, do_parse!( am: parse_int >> tag!("A") >> @@ -72,7 +38,7 @@ named!( ); named!( - cursor_down, + cursor_down<&str, AnsiSequence>, do_parse!( am: parse_int >> tag!("B") >> @@ -81,7 +47,7 @@ named!( ); named!( - cursor_forward, + cursor_forward<&str, AnsiSequence>, do_parse!( am: parse_int >> tag!("C") >> @@ -90,7 +56,7 @@ named!( ); named!( - cursor_backward, + cursor_backward<&str, AnsiSequence>, do_parse!( am: parse_int >> tag!("D") >> @@ -99,7 +65,7 @@ named!( ); named!( - cursor_save, + cursor_save<&str, AnsiSequence>, do_parse!( tag!("s") >> (AnsiSequence::CursorSave) @@ -107,7 +73,7 @@ named!( ); named!( - cursor_restore, + cursor_restore<&str, AnsiSequence>, do_parse!( tag!("u") >> (AnsiSequence::CursorRestore) @@ -115,7 +81,7 @@ named!( ); named!( - erase_display, + erase_display<&str, AnsiSequence>, do_parse!( tag!("2J") >> (AnsiSequence::EraseDisplay) @@ -123,7 +89,7 @@ named!( ); named!( - erase_line, + erase_line<&str, AnsiSequence>, do_parse!( tag!("K") >> (AnsiSequence::EraseDisplay) @@ -131,24 +97,48 @@ named!( ); named!( - graphics_mode, + graphics_mode1<&str, AnsiSequence>, do_parse!( - ta: parse_text_attr >> - tag!(";") >> - fg: parse_fg_color >> - tag!(";") >> - bg: parse_bg_color >> - tag!("m") >> - (AnsiSequence::SetGraphicsMode{ - ta: ta, - fg: fg, - bg: bg - }) + val: parse_int >> + tag!("m") >> + (AnsiSequence::SetGraphicsMode(vec![val])) ) ); named!( - set_mode, + graphics_mode2<&str, AnsiSequence>, + do_parse!( + val1: parse_int >> + tag!(";") >> + val2: parse_int >> + tag!("m") >> + (AnsiSequence::SetGraphicsMode(vec![val1, val2])) + ) +); + +named!( + graphics_mode3<&str, AnsiSequence>, + do_parse!( + val1: parse_int >> + tag!(";") >> + val2: parse_int >> + tag!(";") >> + val3: parse_int >> + tag!("m") >> + (AnsiSequence::SetGraphicsMode(vec![val1, val2, val3])) + ) +); + +named!( + graphics_mode<&str, AnsiSequence>, + alt!( + graphics_mode1 + | graphics_mode2 + | graphics_mode3) +); + +named!( + set_mode<&str, AnsiSequence>, do_parse!( tag!("=") >> mode: parse_int >> @@ -159,7 +149,7 @@ named!( ); named!( - reset_mode, + reset_mode<&str, AnsiSequence>, do_parse!( tag!("=") >> mode: parse_int >> @@ -170,7 +160,7 @@ named!( ); named!( - combined, + combined<&str, AnsiSequence>, alt!( cursor_pos | cursor_up @@ -188,60 +178,59 @@ named!( ); named!( - parse_escape, + parse_escape<&str, Output>, do_parse!( - tag_s!("\x1b[") >> + tag_s!("\u{1b}[") >> seq: combined >> (Output::Escape(seq)) ) ); -named!( - parse_str, - do_parse!( - text: map_res!( - take_until!("\x1b["), - std::str::from_utf8 - ) >> - (Output::TextBlock(text)) - ) -); - -named!( - parse_output, - do_parse!( - out: alt!(parse_escape | parse_str) >> - (out) - ) -); - pub struct ParserIterator<'a> { - dat: &'a[u8], - done: bool + dat: &'a str, } impl<'a> Iterator for ParserIterator<'a> { type Item = Output<'a>; fn next(&mut self) -> Option { - if self.done { + if self.dat == "" { return None; } - let parse = parse_output(self.dat); - if parse.is_ok() { - let parse = parse.unwrap(); + let pos = self.dat.find('\u{1b}'); + if let Some(loc) = pos { + if loc == 0 { + let res = parse_escape(&self.dat[loc..]); - self.dat = parse.0; - Some(parse.1) - }else{ - if self.done { - None - }else{ - self.done = true; - Some(Output::TextBlock(std::str::from_utf8(self.dat) - .unwrap())) + if let Ok(ret) = res { + self.dat = &ret.0; + Some(ret.1) + }else{ + let pos = self.dat[loc..].find('\x1b'); + if let Some(loc) = pos { + let temp = &self.dat[..loc]; + self.dat = &self.dat[loc..]; + + Some(Output::TextBlock(temp)) + }else{ + let temp = self.dat; + self.dat = ""; + + Some(Output::TextBlock(temp)) + } + } + + }else { + let temp = &self.dat[..loc]; + self.dat = &self.dat[loc..]; + + Some(Output::TextBlock(&temp)) } + }else{ + let temp = self.dat; + self.dat = ""; + Some(Output::TextBlock(temp)) } } } @@ -249,8 +238,7 @@ impl<'a> Iterator for ParserIterator<'a> { impl<'a> ParserIterator<'a> { pub fn new(string: &'a str) -> ParserIterator<'a> { ParserIterator { - dat: string.as_bytes(), - done: false + dat: string, } } } diff --git a/src/parsers/tests.rs b/src/parsers/tests.rs index 8b656af..394c7f6 100644 --- a/src/parsers/tests.rs +++ b/src/parsers/tests.rs @@ -3,14 +3,20 @@ use super::*; #[test] fn test_graphics_mode() { let parse = "4;31;42m"; - let temp = graphics_mode(parse.as_bytes()); + let temp = graphics_mode(parse); assert!(temp.is_ok()); - assert_eq!(AnsiSequence::SetGraphicsMode{ - ta: TextAttribute::Underscore, - fg: Color::Red, - bg: Color::Green - }, + assert_eq!(AnsiSequence::SetGraphicsMode( + vec![4,31,42] + ), + temp.unwrap().1 + ); + + let parse = "4m"; + let temp = graphics_mode(parse); + + assert!(temp.is_ok()); + assert_eq!(AnsiSequence::SetGraphicsMode(vec![4]), temp.unwrap().1 ); } @@ -18,7 +24,7 @@ fn test_graphics_mode() { #[test] fn test_set_mode() { let parse = "=7h"; - let temp = set_mode(parse.as_bytes()); + let temp = set_mode(parse); assert_eq!(AnsiSequence::SetMode(7), temp.unwrap().1); } @@ -26,17 +32,17 @@ fn test_set_mode() { #[test] fn test_reset_mode() { let parse = "=13l"; - let temp = reset_mode(parse.as_bytes()); + let temp = reset_mode(parse); assert_eq!(AnsiSequence::ResetMode(13), temp.unwrap().1); } #[test] fn test_parser_iterator() { - let parse_str = "Hello, world? How are \x1b[=7lyou? I hope you're doing well."; + let parse_str = "\x1b[=25l\x1b[=7l\x1b[0m\x1b[36m\x1b[1m-`"; let strings: Vec = ParserIterator::new(parse_str) .collect(); - assert_eq!(strings.len(), 3); + assert_eq!(strings.len(), 6); }