// TODO: read all of this from terminfo pub trait BufWrite { fn write_buf(&self, buf: &mut Vec); } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct ClearScreen; impl BufWrite for ClearScreen { fn write_buf(&self, buf: &mut Vec) { buf.extend_from_slice(b"\x1b[H\x1b[J"); } } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct ClearRowForward; impl BufWrite for ClearRowForward { fn write_buf(&self, buf: &mut Vec) { buf.extend_from_slice(b"\x1b[K"); } } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct CRLF; impl BufWrite for CRLF { fn write_buf(&self, buf: &mut Vec) { buf.extend_from_slice(b"\r\n"); } } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct MoveTo { row: u16, col: u16, } impl MoveTo { pub fn new(pos: crate::grid::Pos) -> Self { Self { row: pos.row, col: pos.col, } } } impl BufWrite for MoveTo { fn write_buf(&self, buf: &mut Vec) { if self.row == 0 && self.col == 0 { buf.extend_from_slice(b"\x1b[H"); } else { buf.extend_from_slice(b"\x1b["); itoa::write(&mut *buf, self.row + 1).unwrap(); buf.push(b';'); itoa::write(&mut *buf, self.col + 1).unwrap(); buf.push(b'H'); } } } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct ClearAttrs; impl BufWrite for ClearAttrs { fn write_buf(&self, buf: &mut Vec) { buf.extend_from_slice(b"\x1b[m") } } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct Attrs { fgcolor: Option, bgcolor: Option, bold: Option, italic: Option, underline: Option, inverse: Option, } impl Attrs { pub fn fgcolor(mut self, fgcolor: crate::attrs::Color) -> Self { self.fgcolor = Some(fgcolor); self } pub fn bgcolor(mut self, bgcolor: crate::attrs::Color) -> Self { self.bgcolor = Some(bgcolor); self } pub fn bold(mut self, bold: bool) -> Self { self.bold = Some(bold); self } pub fn italic(mut self, italic: bool) -> Self { self.italic = Some(italic); self } pub fn underline(mut self, underline: bool) -> Self { self.underline = Some(underline); self } pub fn inverse(mut self, inverse: bool) -> Self { self.inverse = Some(inverse); self } } impl BufWrite for Attrs { #[allow(unused_assignments)] fn write_buf(&self, buf: &mut Vec) { if self.fgcolor.is_none() && self.bgcolor.is_none() && self.bold.is_none() && self.italic.is_none() && self.underline.is_none() && self.inverse.is_none() { return; } buf.extend_from_slice(b"\x1b["); let mut first = true; macro_rules! write_param { ($i:expr) => { if first { first = false; } else { buf.push(b';'); } itoa::write(&mut *buf, $i).unwrap(); }; } if let Some(fgcolor) = self.fgcolor { match fgcolor { crate::attrs::Color::Default => { write_param!(39); } crate::attrs::Color::Idx(i) => { if i < 8 { write_param!(i + 30); } else if i < 16 { write_param!(i + 82); } else { write_param!(38); write_param!(5); write_param!(i); } } crate::attrs::Color::Rgb(r, g, b) => { write_param!(38); write_param!(2); write_param!(r); write_param!(g); write_param!(b); } } } if let Some(bgcolor) = self.bgcolor { match bgcolor { crate::attrs::Color::Default => { write_param!(49); } crate::attrs::Color::Idx(i) => { if i < 8 { write_param!(i + 40); } else if i < 16 { write_param!(i + 92); } else { write_param!(48); write_param!(5); write_param!(i); } } crate::attrs::Color::Rgb(r, g, b) => { write_param!(48); write_param!(2); write_param!(r); write_param!(g); write_param!(b); } } } if let Some(bold) = self.bold { if bold { write_param!(1); } else { write_param!(22); } } if let Some(italic) = self.italic { if italic { write_param!(3); } else { write_param!(23); } } if let Some(underline) = self.underline { if underline { write_param!(4); } else { write_param!(24); } } if let Some(inverse) = self.inverse { if inverse { write_param!(7); } else { write_param!(27); } } buf.push(b'm'); } } #[derive(Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct MoveRight { count: u16, } impl MoveRight { pub fn new(count: u16) -> Self { Self { count } } } impl Default for MoveRight { fn default() -> Self { Self { count: 1 } } } impl BufWrite for MoveRight { fn write_buf(&self, buf: &mut Vec) { match self.count { 0 => {} 1 => buf.extend_from_slice(b"\x1b[C"), n => { buf.extend_from_slice(b"\x1b["); itoa::write(&mut *buf, n).unwrap(); buf.push(b'C'); } } } } #[derive(Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct EraseChar { count: u16, } impl EraseChar { pub fn new(count: u16) -> Self { Self { count } } } impl Default for EraseChar { fn default() -> Self { Self { count: 1 } } } impl BufWrite for EraseChar { fn write_buf(&self, buf: &mut Vec) { match self.count { 0 => {} 1 => buf.extend_from_slice(b"\x1b[X"), n => { buf.extend_from_slice(b"\x1b["); itoa::write(&mut *buf, n).unwrap(); buf.push(b'X'); } } } } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct HideCursor { hide: bool, } impl HideCursor { pub fn new(hide: bool) -> Self { Self { hide } } } impl BufWrite for HideCursor { fn write_buf(&self, buf: &mut Vec) { if self.hide { buf.extend_from_slice(b"\x1b[?25l") } else { buf.extend_from_slice(b"\x1b[?25h") } } } #[derive(Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct MoveFromTo { from: crate::grid::Pos, to: crate::grid::Pos, } impl MoveFromTo { pub fn new(from: crate::grid::Pos, to: crate::grid::Pos) -> Self { Self { from, to } } } impl BufWrite for MoveFromTo { fn write_buf(&self, buf: &mut Vec) { if self.to.row == self.from.row + 1 && self.to.col == 0 { crate::term::CRLF::default().write_buf(buf); } else if self.from.row == self.to.row && self.from.col < self.to.col { crate::term::MoveRight::new(self.to.col - self.from.col) .write_buf(buf); } else if self.to != self.from { crate::term::MoveTo::new(self.to).write_buf(buf); } } } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct AudibleBell; impl BufWrite for AudibleBell { fn write_buf(&self, buf: &mut Vec) { buf.push(b'\x07'); } } #[derive(Default, Debug)] #[must_use = "this struct does nothing unless you call write_buf"] pub struct VisualBell; impl BufWrite for VisualBell { fn write_buf(&self, buf: &mut Vec) { buf.extend_from_slice(b"\x1bg"); } }