use {
crate::*,
crate::crossterm::{style::Print, QueueableCommand},
std::borrow::Cow,
unicode_width::UnicodeWidthChar,
};
pub struct CropWriter<'w, W>
where
W: std::io::Write,
{
pub w: &'w mut W,
pub allowed: usize,
pub tab_replacement: &'static str,
}
impl<'w, W> CropWriter<'w, W>
where
W: std::io::Write,
{
pub fn new(w: &'w mut W, limit: usize) -> Self {
Self {
w,
allowed: limit,
tab_replacement: DEFAULT_TAB_REPLACEMENT,
}
}
pub const fn is_full(&self) -> bool {
self.allowed == 0
}
pub fn cropped_str<'a>(&self, s: &'a str) -> (Cow<'a, str>, usize) {
StrFit::make_cow(s, self.allowed)
}
pub fn queue_unstyled_str(&mut self, s: &str) -> Result<(), Error> {
if self.is_full() {
return Ok(());
}
let (string, len) = self.cropped_str(s);
self.allowed -= len;
self.w.queue(Print(string))?;
Ok(())
}
pub fn queue_str(&mut self, cs: &CompoundStyle, s: &str) -> Result<(), Error> {
if self.is_full() {
return Ok(());
}
let (string, len) = self.cropped_str(s);
self.allowed -= len;
cs.queue(self.w, string)
}
pub fn queue_char(&mut self, cs: &CompoundStyle, c: char) -> Result<(), Error> {
let width = UnicodeWidthChar::width(c).unwrap_or(0);
if width < self.allowed {
self.allowed -= width;
cs.queue(self.w, c)?;
}
Ok(())
}
pub fn queue_unstyled_char(&mut self, c: char) -> Result<(), Error> {
if c == '\t' {
return self.queue_unstyled_str(self.tab_replacement);
}
let width = UnicodeWidthChar::width(c).unwrap_or(0);
if width < self.allowed {
self.allowed -= width;
self.w.queue(Print(c))?;
}
Ok(())
}
pub fn queue_unstyled_g_string(&mut self, mut s: String) -> Result<(), Error> {
if self.is_full() {
return Ok(());
}
let mut len = 0;
for (idx, _) in s.char_indices() {
len += 1;
if len > self.allowed {
s.truncate(idx);
self.allowed = 0;
self.w.queue(Print(s))?;
return Ok(());
}
}
self.allowed -= len;
self.w.queue(Print(s))?;
Ok(())
}
pub fn queue_g_string(&mut self, cs: &CompoundStyle, mut s: String) -> Result<(), Error> {
if self.is_full() {
return Ok(());
}
let mut len = 0;
for (idx, _) in s.char_indices() {
len += 1;
if len > self.allowed {
s.truncate(idx);
self.allowed = 0;
return cs.queue(self.w, s);
}
}
self.allowed -= len;
cs.queue(self.w, s)
}
pub fn queue_fg(&mut self, cs: &CompoundStyle) -> Result<(), Error> {
cs.queue_fg(self.w)
}
pub fn queue_bg(&mut self, cs: &CompoundStyle) -> Result<(), Error> {
cs.queue_bg(self.w)
}
pub fn fill(&mut self, cs: &CompoundStyle, filling: &'static Filling) -> Result<(), Error> {
self.repeat(cs, filling, self.allowed)
}
pub fn fill_unstyled(&mut self, filling: &'static Filling) -> Result<(), Error> {
self.repeat_unstyled(filling, self.allowed)
}
pub fn fill_with_space(&mut self, cs: &CompoundStyle) -> Result<(), Error> {
self.repeat(cs, &SPACE_FILLING, self.allowed)
}
pub fn repeat(
&mut self,
cs: &CompoundStyle,
filling: &'static Filling,
mut len: usize,
) -> Result<(), Error> {
len = len.min(self.allowed);
self.allowed -= len;
filling.queue_styled(self.w, cs, len)
}
pub fn repeat_unstyled(&mut self, filling: &'static Filling, mut len: usize) -> Result<(), Error> {
len = len.min(self.allowed);
self.allowed -= len;
filling.queue_unstyled(self.w, len)
}
}