tracing_subscriber_multi/
ascii_stripper.rs1use std::io::Write;
2
3pub struct AnsiStripper<W: Write> {
8 inner: W,
9 state: AnsiStateMachine,
10}
11
12enum AnsiStateMachine {
13 ScanningForESC,
14 ExpectingType,
15 WaitingForEnd,
16}
17
18impl<W: Write> AnsiStripper<W> {
19 pub fn new(writer: W) -> Self {
21 Self {
22 inner: writer,
23 state: AnsiStateMachine::ScanningForESC,
24 }
25 }
26}
27
28impl<W: Write> Write for AnsiStripper<W> {
29 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
30 let mut cleaned_buffer = vec![];
31 for &c in buf {
32 match &mut self.state {
33 AnsiStateMachine::ScanningForESC => {
34 if c == 0x1b {
35 self.state = AnsiStateMachine::ExpectingType;
37 } else {
38 cleaned_buffer.push(c);
40 }
41 }
42 AnsiStateMachine::ExpectingType => {
43 if (0x40..=0x5f).contains(&c) {
44 self.state = AnsiStateMachine::WaitingForEnd;
46 } else if (0x60..=0x7e).contains(&c) {
47 tracing::warn!("The writer was asked to strip unsupported ANSI sequences!");
49 } else if (0x30..=0x3f).contains(&c) {
50 tracing::warn!("The writer was asked to strip unsupported ANSI sequences!");
52 } else if (0x20..=0x2f).contains(&c) {
53 tracing::warn!("The writer was asked to strip unsupported ANSI sequences!");
55 }
56 }
57 AnsiStateMachine::WaitingForEnd => {
58 if (0x40..=0x7e).contains(&c) {
59 self.state = AnsiStateMachine::ScanningForESC;
61 }
62 }
63 }
64 }
65
66 self.inner.write(&cleaned_buffer)
67 }
68
69 fn flush(&mut self) -> std::io::Result<()> {
70 self.inner.flush()
71 }
72}