use std::io::{Result, Write};
pub struct TermOut {
buf: Vec<u8>,
flush_to: usize,
features: Features,
size: (i32, i32),
pub(crate) new_cleanup: Option<Vec<u8>>,
}
impl TermOut {
pub(crate) fn new(features: Features) -> Self {
Self {
buf: Vec::new(),
flush_to: 0,
features,
new_cleanup: None,
size: (0, 0),
}
}
#[inline]
pub fn features(&self) -> &Features {
&self.features
}
#[inline]
pub fn size(&self) -> (i32, i32) {
self.size
}
#[inline]
pub fn sy(&self) -> i32 {
self.size.0
}
#[inline]
pub fn sx(&self) -> i32 {
self.size.1
}
#[inline]
pub fn flush(&mut self) {
self.flush_to = self.buf.len();
}
#[inline]
pub fn out(&mut self, data: &str) -> &mut Self {
self.buf.extend_from_slice(data.as_bytes());
self
}
#[inline]
pub fn bytes(&mut self, data: &[u8]) -> &mut Self {
self.buf.extend_from_slice(data);
self
}
#[inline]
pub fn byt(&mut self, v1: u8) -> &mut Self {
self.buf.push(v1);
self
}
#[inline]
pub fn asc(&mut self, c: char) -> &mut Self {
self.buf.push(c as u8);
self
}
#[inline]
pub fn esc(&mut self, c: char) -> &mut Self {
self.buf.push(27);
self.buf.push(c as u8);
self
}
#[inline]
pub fn csi(&mut self) -> &mut Self {
self.esc('[')
}
pub fn num(&mut self, v: i32) -> &mut Self {
if v <= 0 {
self.asc('0');
} else if v <= 9 {
self.byt(v as u8 + b'0');
} else if v <= 99 {
self.byt((v / 10) as u8 + b'0').byt((v % 10) as u8 + b'0');
} else if v <= 999 {
self.byt((v / 100) as u8 + b'0')
.byt((v / 10 % 10) as u8 + b'0')
.byt((v % 10) as u8 + b'0');
} else {
self.asc('9').asc('9').asc('9');
}
self
}
#[inline]
pub fn at(&mut self, y: i32, x: i32) -> &mut Self {
let (sy, sx) = self.size;
self.csi()
.num(y.rem_euclid(sy) + 1)
.asc(';')
.num(x.rem_euclid(sx) + 1)
.asc('H')
}
#[inline]
pub fn attr(&mut self, codes: &str) -> &mut Self {
self.csi().out(codes).asc('m')
}
#[inline]
pub fn hfb(&mut self, hfb: u8) -> &mut Self {
const FG: [i32; 10] = [30, 34, 31, 35, 32, 36, 33, 37, 39, 39];
self.out("\x1B[0;");
if hfb >= 100 {
self.out("1;");
}
self.num(FG[(hfb / 10 % 10) as usize])
.asc(';')
.num(10 + FG[(hfb % 10) as usize])
.asc('m')
}
#[inline]
pub fn underline_cursor(&mut self) -> &mut Self {
self.out("\x1B[34h")
}
#[inline]
pub fn block_cursor(&mut self) -> &mut Self {
self.out("\x1B[34l")
}
#[inline]
pub fn show_cursor(&mut self) -> &mut Self {
self.out("\x1B[?25h\x1B[?0c")
}
#[inline]
pub fn hide_cursor(&mut self) -> &mut Self {
self.out("\x1B[?25l\x1B[?1c")
}
#[inline]
pub fn origin(&mut self) -> &mut Self {
self.out("\x1B[H")
}
#[inline]
pub fn erase_eol(&mut self) -> &mut Self {
self.out("\x1B[K")
}
#[inline]
pub fn clear(&mut self) -> &mut Self {
self.out("\x1B[2J")
}
#[inline]
pub fn spaces(&mut self, n: i32) -> &mut Self {
for _ in 0..n {
self.asc(' ');
}
self
}
#[inline]
pub fn attr_reset(&mut self) -> &mut Self {
self.out("\x1B[0m")
}
#[inline]
pub fn full_reset(&mut self) -> &mut Self {
self.out("\x1Bc")
}
#[inline]
pub fn utf8_mode(&mut self) -> &mut Self {
self.out("\x1B%G")
}
#[inline]
pub fn scroll_up(&mut self) -> &mut Self {
self.at(-1, 0).asc('\n')
}
pub fn save_cleanup(&mut self) {
self.new_cleanup = Some(self.buf.drain(..).collect());
}
pub(crate) fn data_to_flush(&self) -> &[u8] {
&self.buf[..self.flush_to]
}
pub(crate) fn drain_flush(&mut self) {
self.buf.drain(..self.flush_to);
self.flush_to = 0;
}
pub(crate) fn discard(&mut self) {
self.buf.drain(..);
self.flush_to = 0;
}
pub(crate) fn set_size(&mut self, sy: i32, sx: i32) {
self.size = (sy, sx);
}
}
impl Write for TermOut {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.buf.extend_from_slice(buf);
Ok(buf.len())
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
pub struct Features {
pub colour_256: bool,
}