#[derive(PartialEq, Eq)]
pub enum Ansi {
Txt,
Esc,
EscCSI,
EscUnsupported,
EscEnd,
}
impl Ansi {
fn step(&mut self, c: char) {
use Ansi::*;
*self = match self {
Txt | EscEnd if c == '\x1B' => Esc,
Txt | EscEnd if c < ' ' => EscEnd,
Txt | EscEnd => Txt,
Esc if c == '[' => EscCSI,
Esc if "78\x0A\x0C\x0D".contains(c) => EscEnd,
Esc => EscUnsupported,
EscCSI if ('@'..='~').contains(&c) => EscEnd,
EscCSI => EscCSI,
EscUnsupported => EscUnsupported,
}
}
pub fn strip(s: &str, max: usize) -> String {
let mut out = String::with_capacity(max + 3);
let mut state = Self::Txt;
for c in s.trim().chars() {
state.step(c);
if state == Self::Txt {
if !out.is_empty() || !c.is_whitespace() {
out.push(c);
}
if out.len() >= max {
out += "...";
break;
}
}
}
out
}
pub fn len(s: &[u8]) -> usize {
let mut len = 0;
let mut state = Self::Txt;
for c in s {
state.step(*c as char);
if state == Self::Txt {
len += 1;
}
}
len
}
}
pub struct AnsiStr {
pub val: &'static str,
pub len: usize,
}
impl From<&'static str> for AnsiStr {
fn from(val: &'static str) -> Self {
Self { val, len: Ansi::len(val.as_bytes()) }
}
}
impl crate::table::Disp for AnsiStr {
fn out(&self, buf: &mut Vec<u8>, _conf: &crate::Conf) -> usize {
buf.extend_from_slice(self.val.as_bytes());
self.len
}
}