little-kitty 0.0.3

A low-level interface for the Kitty Graphics Protocol
Documentation
use {
    crossterm::{ExecutableCommand, cursor::*},
    std::io::*,
};

//
// PositionalWriter
//

/// Wraps a writer with the option of moving the cursor.
///
/// Restores the original cursor position when dropped.
pub struct PositionalWriter<InnerT>
where
    InnerT: Write,
{
    /// Inner writer.
    pub inner: InnerT,

    restore: bool,
}

impl<InnerT> PositionalWriter<InnerT>
where
    InnerT: Write,
{
    /// Constructor.
    pub fn new(inner: InnerT) -> Self {
        Self { inner, restore: false }
    }

    /// Constructor.
    #[allow(unused)]
    pub fn new_save(mut inner: InnerT) -> Result<Self> {
        inner.execute(SavePosition)?;
        Ok(Self { inner, restore: true })
    }

    /// Constructor.
    pub fn new_save_at(mut inner: InnerT, x: u16, y: u16) -> Result<Self> {
        inner.execute(SavePosition)?.execute(MoveTo(x, y))?;
        Ok(Self { inner, restore: true })
    }

    /// Constructor.
    pub fn new_save_at_maybe(inner: InnerT, position: Option<(usize, usize)>) -> Result<Self> {
        match position {
            Some((x, y)) => Self::new_save_at(inner, x as u16, y as u16),
            None => Ok(Self::new(inner)),
        }
    }

    /// Move to position.
    pub fn at(&mut self, x: u16, y: u16) -> Result<()> {
        self.restore = true;
        self.inner.execute(MoveTo(x, y)).map(|_| ())
    }
}

impl<InnerT> Write for PositionalWriter<InnerT>
where
    InnerT: Write,
{
    fn write(&mut self, buffer: &[u8]) -> Result<usize> {
        self.inner.write(buffer)
    }

    fn flush(&mut self) -> Result<()> {
        self.inner.flush()
    }
}

impl<InnerT> Drop for PositionalWriter<InnerT>
where
    InnerT: Write,
{
    fn drop(&mut self) {
        if self.restore {
            _ = self.inner.execute(RestorePosition);
        }
    }
}