use core::fmt::Write as _;
use smol_str::{SmolStr, SmolStrBuilder};
use crate::hex::push_hex;
use crate::{ColorId, DEFAULT_BG_ID, DEFAULT_FG_ID, SgrFlags};
#[derive(Default, Debug)]
pub struct Reply {
buf: SmolStrBuilder,
}
impl Reply {
pub const DEFAULT: Self = Self {
buf: SmolStrBuilder::new(),
};
#[inline]
pub const fn new() -> Self {
Self::DEFAULT
}
#[inline]
pub fn is_empty(&self) -> bool {
self.buf.finish().is_empty()
}
pub fn decrqss(mut self, valid: bool, value: &str) -> Self {
let _ = write!(
self.buf,
"\x1bP{}$r{value}\x1b\\",
if valid { "1" } else { "0" }
);
self
}
fn xtgettcap(mut self, ok: bool, key: &[u8], value: Option<&[u8]>) -> Self {
self.buf.push_str(if ok { "\x1bP1+r" } else { "\x1bP0+r" });
push_hex(&mut self.buf, key);
if let Some(value) = value {
self.buf.push('=');
push_hex(&mut self.buf, value);
}
self.buf.push_str("\x1b\\");
self
}
#[inline]
pub fn xtgettcap_reply(self, key: &[u8], value: &[u8]) -> Self {
self.xtgettcap(true, key, Some(value))
}
#[inline]
pub fn xtgettcap_reply_bool(self, key: &[u8]) -> Self {
self.xtgettcap(true, key, None)
}
#[inline]
pub fn xtgettcap_error(self, msg: &[u8]) -> Self {
self.xtgettcap(false, msg, None)
}
pub fn xtgettcap_num(mut self, key: &[u8], n: usize) -> Self {
self.buf.push_str("\x1bP1+r");
push_hex(&mut self.buf, key);
self.buf.push('=');
let mut digits = [0_u8; 20];
let mut i = digits.len();
let mut n = n;
loop {
i -= 1;
digits[i] = b'0' + (n % 10) as u8;
n /= 10;
if n == 0 {
break;
}
}
for &d in &digits[i..] {
self.buf.push('3');
self.buf.push(d as char);
}
self.buf.push_str("\x1b\\");
self
}
pub fn sgr(mut self, fg: ColorId, bg: ColorId, flags: SgrFlags, palette: &[u32]) -> Self {
let _ = write!(self.buf, "0");
if flags.contains(SgrFlags::BOLD) {
let _ = write!(self.buf, ";1");
}
if flags.contains(SgrFlags::ITALIC) {
let _ = write!(self.buf, ";3");
}
if flags.contains(SgrFlags::UNDERLINE) {
let _ = write!(self.buf, ";4");
}
if flags.contains(SgrFlags::INVERSE) {
let _ = write!(self.buf, ";7");
}
push_sgr_color(&mut self.buf, 3, fg, palette);
push_sgr_color(&mut self.buf, 4, bg, palette);
self
}
pub fn decrqm(mut self, param: i32, private: bool, state: u8) -> Self {
let _ = write!(
self.buf,
"\x1b[{}{param};{state}$y",
if private { "?" } else { "" }
);
self
}
#[inline]
pub fn finish(self) -> SmolStr {
SmolStr::from(self.buf)
}
}
fn push_sgr_color(s: &mut SmolStrBuilder, base: u8, id: ColorId, palette: &[u32]) {
match id {
DEFAULT_FG_ID | DEFAULT_BG_ID => {
let _ = write!(s, ";{base}9");
}
id if id.0 <= 255 => {
let _ = write!(s, ";{base}8;5;{id}");
}
_ => {
let rgb = palette.get(id.0 as usize).copied().unwrap_or(0);
let _ = write!(
s,
";{base}8;2;{};{};{}",
(rgb >> 16) & 0xff,
(rgb >> 8) & 0xff,
rgb & 0xff
);
}
}
}