use nom::{ branch::alt, bytes::complete::{tag, take_till, take_till1}, combinator::eof, error::Error, multi::fold_many0, sequence::{pair, tuple}, Err, Parser, }; enum AnsiFrag<'l> { Lit(&'l str), Special(&'l str), } use AnsiFrag::Special; pub fn parse_ansi_markup(i: &str) -> Result>> { pair( fold_many0( alt(( take_till1(|c| c == '<').map(AnsiFrag::Lit), tuple((tag("<"), take_till(|c| c == '>'), tag(">"))) .map(|t| AnsiFrag::Special(t.1)), )), || "".to_owned(), |a, r| { a + match r { AnsiFrag::Lit(s) => &s, Special(s) if s == "reset" => "\x1b[0m", Special(s) if s == "bold" => "\x1b[1m", Special(s) if s == "under" => "\x1b[4m", Special(s) if s == "strike" => "\x1b[9m", Special(s) if s == "nounder" => "\x1b[24m", Special(s) if s == "black" => "\x1b[30m", Special(s) if s == "red" => "\x1b[31m", Special(s) if s == "green" => "\x1b[32m", Special(s) if s == "yellow" => "\x1b[33m", Special(s) if s == "blue" => "\x1b[34m", Special(s) if s == "magenta" => "\x1b[35m", Special(s) if s == "cyan" => "\x1b[36m", Special(s) if s == "white" => "\x1b[37m", Special(s) if s == "bgblack" => "\x1b[40m", Special(s) if s == "bgred" => "\x1b[41m", Special(s) if s == "bggreen" => "\x1b[42m", Special(s) if s == "bgyellow" => "\x1b[43m", Special(s) if s == "bgblue" => "\x1b[44m", Special(s) if s == "bgmagenta" => "\x1b[45m", Special(s) if s == "bgcyan" => "\x1b[46m", Special(s) if s == "bgwhite" => "\x1b[47m", Special(s) if s == "lt" => "<", Special(r) => panic!("Unknown ansi type {}", r), } }, ), eof, )(i) .map(|(_, (r, _))| r) } pub fn parse_ansi_markup_escape(i: &str) -> Result>> { parse_ansi_markup(i).map(|o| o.replace('\x1b', "\\e")) }