use std::{fmt::{Display, Formatter}};
use vte::{Parser, Perform};
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Noansi<T: AsRef<str>>(pub T);
struct AnsiStripper<'a, 'f, const BUFFER_SIZE: usize> {
formatter: &'a mut Formatter<'f>,
buffer: [u8; BUFFER_SIZE],
len: usize,
}
impl<'a, 'f, const BUFFER_SIZE: usize> AnsiStripper<'a, 'f, BUFFER_SIZE> {
#[must_use]
#[inline(always)]
const fn new(formatter: &'a mut Formatter<'f>) -> Self {
Self {
formatter,
buffer: [0u8; BUFFER_SIZE],
len: 0usize,
}
}
fn flush(&mut self) -> std::fmt::Result {
if self.len == 0 {
return Ok(());
}
let raw_ptr = self.buffer.as_ptr();
let len = self.len;
let slice = unsafe { std::slice::from_raw_parts(raw_ptr, len) };
let s = unsafe { str::from_utf8_unchecked(slice) };
self.len = 0;
self.formatter.write_str(s)
}
fn putchr(&mut self, chr: char) -> std::fmt::Result {
let len_utf8 = chr.len_utf8();
if (BUFFER_SIZE - self.len) < len_utf8 {
self.flush()?;
}
let buf = &mut self.buffer[self.len..];
chr.encode_utf8(buf);
self.len += len_utf8;
Ok(())
}
}
impl<'a, 'f, const BUFFER_SIZE: usize> Perform for AnsiStripper<'a, 'f, BUFFER_SIZE> {
fn print(&mut self, c: char) {
self.putchr(c).expect("Failed to put the char.")
}
}
impl<T: AsRef<str>> Display for Noansi<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut stripper: AnsiStripper<4096> = AnsiStripper::new(f);
_=Parser::new().advance_until_terminated(&mut stripper, self.0.as_ref().as_bytes());
stripper.flush()?;
Ok(())
}
}