Merge branch 'daniel.buga/ansi-parser-escape' into master

This commit is contained in:
David Bittner
2020-10-05 14:42:10 -04:00
4 changed files with 118 additions and 28 deletions

2
Cargo.lock generated
View File

@@ -2,7 +2,7 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "ansi-parser" name = "ansi-parser"
version = "0.6.4" version = "0.6.5"
dependencies = [ dependencies = [
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@@ -4,6 +4,7 @@ mod tests;
///The following are the implemented ANSI escape sequences. More to be added. ///The following are the implemented ANSI escape sequences. More to be added.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum AnsiSequence { pub enum AnsiSequence {
Escape,
CursorPos(u32, u32), CursorPos(u32, u32),
CursorUp(u32), CursorUp(u32),
CursorDown(u32), CursorDown(u32),
@@ -61,6 +62,7 @@ impl Display for AnsiSequence {
use AnsiSequence::*; use AnsiSequence::*;
match self { match self {
Escape => write!(formatter, "\u{1b}"),
CursorPos(line, col) CursorPos(line, col)
=> write!(formatter, "[{};{}H", line, col), => write!(formatter, "[{};{}H", line, col),
CursorUp(amt) CursorUp(amt)

View File

@@ -26,27 +26,45 @@ named!(
) )
); );
// TODO kind of ugly, would prefer to pass in the default so we could use it for
// all escapes with defaults (not just those that default to 1).
named!(
parse_def_cursor_int<&str, u32>,
map!(
nom::digit0,
|s: &str| s.parse::<u32>().unwrap_or(1)
)
);
named!( named!(
cursor_pos<&str, AnsiSequence>, cursor_pos<&str, AnsiSequence>,
do_parse!( do_parse!(
tag!("[") >> tag!("[") >>
x: parse_int >> x: parse_def_cursor_int >>
tag!(";") >> opt!(tag!(";")) >>
y: parse_int >> y: parse_def_cursor_int >>
alt!( alt!(
tag!("H") | tag!("H") |
tag!("f") tag!("f")
) >> ) >>
(AnsiSequence::CursorPos(x, y)) (AnsiSequence::CursorPos(x, y))
) )
); );
named!(
escape<&str, AnsiSequence>,
do_parse!(
tag!("\u{1b}") >>
(AnsiSequence::Escape)
)
);
named!( named!(
cursor_up<&str, AnsiSequence>, cursor_up<&str, AnsiSequence>,
do_parse!( do_parse!(
tag!("[") >> tag!("[") >>
am: parse_int >> am: parse_def_cursor_int >>
tag!("A") >> tag!("A") >>
(AnsiSequence::CursorUp(am)) (AnsiSequence::CursorUp(am))
) )
); );
@@ -54,9 +72,9 @@ named!(
named!( named!(
cursor_down<&str, AnsiSequence>, cursor_down<&str, AnsiSequence>,
do_parse!( do_parse!(
tag!("[") >> tag!("[") >>
am: parse_int >> am: parse_def_cursor_int >>
tag!("B") >> tag!("B") >>
(AnsiSequence::CursorDown(am)) (AnsiSequence::CursorDown(am))
) )
); );
@@ -64,9 +82,9 @@ named!(
named!( named!(
cursor_forward<&str, AnsiSequence>, cursor_forward<&str, AnsiSequence>,
do_parse!( do_parse!(
tag!("[") >> tag!("[") >>
am: parse_int >> am: parse_def_cursor_int >>
tag!("C") >> tag!("C") >>
(AnsiSequence::CursorForward(am)) (AnsiSequence::CursorForward(am))
) )
); );
@@ -74,9 +92,9 @@ named!(
named!( named!(
cursor_backward<&str, AnsiSequence>, cursor_backward<&str, AnsiSequence>,
do_parse!( do_parse!(
tag!("[") >> tag!("[") >>
am: parse_int >> am: parse_def_cursor_int >>
tag!("D") >> tag!("D") >>
(AnsiSequence::CursorBackward(am)) (AnsiSequence::CursorBackward(am))
) )
); );
@@ -125,6 +143,26 @@ named!(
) )
); );
named!(
graphics_mode5<&str, AnsiSequence>,
do_parse!(
tag!("[") >>
val1: parse_int >>
tag!(";") >>
val2: parse_int >>
tag!(";") >>
val3: parse_int >>
tag!(";") >>
val4: parse_int >>
tag!(";") >>
val5: parse_int >>
tag!("m") >>
(AnsiSequence::SetGraphicsMode(vec![val1, val2, val3, val4, val5]))
)
);
named!( named!(
graphics_mode<&str, AnsiSequence>, graphics_mode<&str, AnsiSequence>,
alt!( alt!(
@@ -132,6 +170,7 @@ named!(
| graphics_mode2 | graphics_mode2
| graphics_mode3 | graphics_mode3
| graphics_mode4 | graphics_mode4
| graphics_mode5
) )
); );
@@ -213,11 +252,12 @@ tag_parser!(set_single_shift3, "O", AnsiSequence::SetSingleShift3);
named!( named!(
combined<&str, AnsiSequence>, combined<&str, AnsiSequence>,
alt!( alt!(
cursor_pos escape
| cursor_pos
| cursor_up | cursor_up
| cursor_down | cursor_down
| cursor_forward | cursor_forward
| cursor_backward | cursor_backward
| cursor_save | cursor_save
| cursor_restore | cursor_restore
| erase_display | erase_display
@@ -272,4 +312,3 @@ named!(
(Output::Escape(seq)) (Output::Escape(seq))
) )
); );

View File

@@ -21,13 +21,37 @@ macro_rules! test_parser {
} }
} }
test_parser!(cursor_pos, "\u{1b}[10;5H"); macro_rules! test_def_val_parser {
test_parser!(cursor_up, "\u{1b}[5A"); ($name:ident, $string:expr) => {
test_parser!(cursor_down, "\u{1b}[5B"); #[test]
test_parser!(cursor_forward, "\u{1b}[5C"); fn $name() {
test_parser!(cursor_backward,"\u{1b}[5D"); let mut buff = String::new();
test_parser!(cursor_save, "\u{1b}[s"); let ret = parse_escape($string);
test_parser!(cursor_restore, "\u{1b}[u");
assert!(ret.is_ok());
let ret = ret.unwrap().1;
write!(&mut buff, "{}", ret)
.unwrap();
let ret2 = parse_escape(&buff);
assert!(ret2.is_ok());
let ret2 = ret2.unwrap().1;
assert_eq!(ret, ret2);
}
}
}
test_def_val_parser!(cursor_pos_default, "\u{1b}[H");
test_def_val_parser!(cursor_pos, "\u{1b}[10;5H");
test_def_val_parser!(cursor_up_default, "\u{1b}[A");
test_def_val_parser!(cursor_up, "\u{1b}[5A");
test_def_val_parser!(cursor_down, "\u{1b}[5B");
test_def_val_parser!(cursor_forward, "\u{1b}[5C");
test_def_val_parser!(cursor_backward, "\u{1b}[5D");
test_parser!(cursor_save, "\u{1b}[s");
test_parser!(cursor_restore, "\u{1b}[u");
test_parser!(erase_display, "\u{1b}[2J"); test_parser!(erase_display, "\u{1b}[2J");
test_parser!(erase_line, "\u{1b}[K"); test_parser!(erase_line, "\u{1b}[K");
@@ -96,3 +120,28 @@ fn test_parser_iterator_failure() {
assert_eq!(strings.len(), 6); assert_eq!(strings.len(), 6);
} }
#[test]
fn test_default_value() {
let strings: Vec<_> = "\x1b[H\x1b[123456H\x1b[;123456H\x1b[7asd;1234H\x1b[a;sd7H"
.ansi_parse()
.collect();
assert_eq!(strings.len(), 5);
assert_eq!(strings[0], Output::Escape(AnsiSequence::CursorPos(1,1)));
assert_eq!(strings[1], Output::Escape(AnsiSequence::CursorPos(123456,1)));
assert_eq!(strings[2], Output::Escape(AnsiSequence::CursorPos(1,123456)));
assert_eq!(strings[3], Output::TextBlock("\x1b[7asd;1234H"));
assert_eq!(strings[4], Output::TextBlock("\x1b[a;sd7H"));
}
#[test]
fn test_escape() {
let parts: Vec<_> = "\x1b\x1b[33mFoobar".ansi_parse().collect();
assert_eq!(
parts,
vec![
Output::Escape(AnsiSequence::Escape),
Output::TextBlock("[33mFoobar")
]
);
}