use {
base64::{engine::general_purpose::*, write::*},
std::io::*,
};
pub const COMMAND_START: &[u8] = b"\x1b_G";
pub const COMMAND_START_TMUX: &[u8] = b"\x1bPtmux;\x1b\x1b_G";
pub const POSITION_START_TMUX: &[u8] = b"\x1bPtmux;\x1b\x1b[";
pub const POSITION_END_COMMAND_START_TMUX: &[u8] = b"H\x1b\x1b_G";
pub const COMMAND_END: &[u8] = b"\x1b\\";
pub const COMMAND_END_TMUX: &[u8] = b"\x1b\x1b\\\x1b\\";
pub const COMMAND_END_AND_DEVICE_QUERY: &[u8] = b"\x1b\\\x1b[c";
pub const COMMAND_END_AND_DEVICE_QUERY_TMUX: &[u8] = b"\x1b\x1b\\\x1b\x1b[c\x1b\\";
pub trait KittyCommandWriter: Sized {
fn write_start(&mut self, in_tmux: bool, position: Option<(usize, usize)>) -> Result<()>;
fn write_end(&mut self, in_tmux: bool) -> Result<()>;
fn write_end_and_device_query(&mut self, in_tmux: bool) -> Result<()>;
fn write_base64(self, data: &[u8]) -> Result<Self>;
}
impl<WriteT> KittyCommandWriter for WriteT
where
WriteT: Write,
{
fn write_start(&mut self, in_tmux: bool, position: Option<(usize, usize)>) -> Result<()> {
if in_tmux && let Some((x, y)) = position {
self.write_all(POSITION_START_TMUX)?;
self.write_all((y + 1).to_string().as_bytes())?;
self.write_all(b";")?;
self.write_all((x + 1).to_string().as_bytes())?;
self.write_all(POSITION_END_COMMAND_START_TMUX)
} else {
self.write_all(if in_tmux { COMMAND_START_TMUX } else { COMMAND_START })
}
}
fn write_end(&mut self, in_tmux: bool) -> Result<()> {
self.write_all(if in_tmux { COMMAND_END_TMUX } else { COMMAND_END })?;
self.flush()
}
fn write_end_and_device_query(&mut self, in_tmux: bool) -> Result<()> {
self.write_all(if in_tmux { COMMAND_END_AND_DEVICE_QUERY_TMUX } else { COMMAND_END_AND_DEVICE_QUERY })?;
self.flush()
}
fn write_base64(self, data: &[u8]) -> Result<Self> {
let mut encoder = EncoderWriter::new(self, &STANDARD);
encoder.write_all(data)?;
encoder.finish()
}
}