use std::io::Write;
pub struct AnsiStripper<W: Write> {
inner: W,
state: AnsiStateMachine,
}
enum AnsiStateMachine {
ScanningForESC,
ExpectingType,
WaitingForEnd,
}
impl<W: Write> AnsiStripper<W> {
pub fn new(writer: W) -> Self {
Self {
inner: writer,
state: AnsiStateMachine::ScanningForESC,
}
}
}
impl<W: Write> Write for AnsiStripper<W> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut cleaned_buffer = vec![];
for &c in buf {
match &mut self.state {
AnsiStateMachine::ScanningForESC => {
if c == 0x1b {
self.state = AnsiStateMachine::ExpectingType;
} else {
cleaned_buffer.push(c);
}
}
AnsiStateMachine::ExpectingType => {
if (0x40..=0x5f).contains(&c) {
self.state = AnsiStateMachine::WaitingForEnd;
} else if (0x60..=0x7e).contains(&c) {
tracing::warn!("The writer was asked to strip unsupported ANSI sequences!");
} else if (0x30..=0x3f).contains(&c) {
tracing::warn!("The writer was asked to strip unsupported ANSI sequences!");
} else if (0x20..=0x2f).contains(&c) {
tracing::warn!("The writer was asked to strip unsupported ANSI sequences!");
}
}
AnsiStateMachine::WaitingForEnd => {
if (0x40..=0x7e).contains(&c) {
self.state = AnsiStateMachine::ScanningForESC;
}
}
}
}
self.inner.write(&cleaned_buffer)
}
fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}