v0.1.2-pre.004
This commit is contained in:
105
crates/ksp-logging-lib/src/writer.rs
Normal file
105
crates/ksp-logging-lib/src/writer.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
// file: crates/ksp-logging-lib/src/writer.rs
|
||||
// version: 1
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum StripAnsiState {
|
||||
Text,
|
||||
Escape,
|
||||
Csi,
|
||||
Osc,
|
||||
OscEscape,
|
||||
String,
|
||||
StringEscape,
|
||||
}
|
||||
|
||||
pub(crate) struct StripAnsiWriter<W> {
|
||||
inner: W,
|
||||
state: StripAnsiState,
|
||||
}
|
||||
|
||||
impl<W> StripAnsiWriter<W> {
|
||||
pub(crate) const fn new(inner: W) -> Self {
|
||||
return Self { inner, state: StripAnsiState::Text };
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn into_inner(self) -> W {
|
||||
return self.inner;
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> std::io::Write for StripAnsiWriter<W>
|
||||
where
|
||||
W: std::io::Write,
|
||||
{
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let mut stripped = std::vec::Vec::with_capacity(buf.len());
|
||||
for byte in buf {
|
||||
self.consume_byte(*byte, &mut stripped);
|
||||
}
|
||||
let write_result = std::io::Write::write_all(&mut self.inner, stripped.as_slice());
|
||||
return match write_result {
|
||||
std::result::Result::Ok(()) => std::result::Result::Ok(buf.len()),
|
||||
std::result::Result::Err(error) => std::result::Result::Err(error),
|
||||
};
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
return std::io::Write::flush(&mut self.inner);
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> StripAnsiWriter<W> {
|
||||
fn consume_byte(&mut self, byte: u8, output: &mut std::vec::Vec<u8>) {
|
||||
self.state = match self.state {
|
||||
StripAnsiState::Text => {
|
||||
if byte == 0x1B {
|
||||
StripAnsiState::Escape
|
||||
} else {
|
||||
output.push(byte);
|
||||
StripAnsiState::Text
|
||||
}
|
||||
},
|
||||
StripAnsiState::Escape => match byte {
|
||||
b'[' => StripAnsiState::Csi,
|
||||
b']' => StripAnsiState::Osc,
|
||||
b'P' | b'X' | b'^' | b'_' => StripAnsiState::String,
|
||||
0x1B => StripAnsiState::Escape,
|
||||
_ => StripAnsiState::Text,
|
||||
},
|
||||
StripAnsiState::Csi => {
|
||||
if (0x40..=0x7E).contains(&byte) {
|
||||
StripAnsiState::Text
|
||||
} else {
|
||||
StripAnsiState::Csi
|
||||
}
|
||||
},
|
||||
StripAnsiState::Osc => match byte {
|
||||
0x07 => StripAnsiState::Text,
|
||||
0x1B => StripAnsiState::OscEscape,
|
||||
_ => StripAnsiState::Osc,
|
||||
},
|
||||
StripAnsiState::OscEscape => match byte {
|
||||
b'\\' => StripAnsiState::Text,
|
||||
0x1B => StripAnsiState::OscEscape,
|
||||
_ => StripAnsiState::Osc,
|
||||
},
|
||||
StripAnsiState::String => {
|
||||
if byte == 0x1B {
|
||||
StripAnsiState::StringEscape
|
||||
} else {
|
||||
StripAnsiState::String
|
||||
}
|
||||
},
|
||||
StripAnsiState::StringEscape => match byte {
|
||||
b'\\' => StripAnsiState::Text,
|
||||
0x1B => StripAnsiState::StringEscape,
|
||||
_ => StripAnsiState::String,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/writer.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user