pub(crate) mod ev_handler;
pub(crate) mod term;
use crossterm::{
cursor::MoveTo,
style::Attribute,
terminal::{Clear, ClearType},
};
use std::{convert::TryFrom, io::Write};
use crate::{MinusError, PagerState};
pub(crate) fn draw(out: &mut impl Write, pager: &mut PagerState) -> Result<(), MinusError> {
write!(out, "{}{}", Clear(ClearType::All), MoveTo(0, 0))?;
write_lines(out, pager)?;
let prompt = pager
.message
.0
.as_ref()
.map_or_else(|| pager.prompt.clone(), std::clone::Clone::clone);
{
write!(
out,
"{mv}\r{rev}{prompt}{reset}",
mv = MoveTo(0, u16::try_from(pager.rows).unwrap()),
rev = Attribute::Reverse,
prompt = prompt.first().unwrap(),
reset = Attribute::Reset,
)?;
}
out.flush().map_err(MinusError::Draw)
}
pub(crate) fn write_lines(out: &mut impl Write, pager: &mut PagerState) -> Result<(), MinusError> {
let line_count = pager.num_lines();
let rows = pager.rows.saturating_sub(1);
let lower_mark = pager.upper_mark.saturating_add(rows.min(line_count));
if lower_mark > line_count {
pager.upper_mark = if line_count < pager.rows {
0
} else {
line_count.saturating_sub(rows)
};
}
let displayed_lines = pager
.get_flattened_lines_with_bounds(pager.upper_mark, lower_mark)
.join("\n\r");
writeln!(out, "\r{}", displayed_lines)?;
Ok(())
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum LineNumbers {
AlwaysOn,
Enabled,
Disabled,
AlwaysOff,
}
impl LineNumbers {
#[allow(dead_code)]
fn is_invertible(self) -> bool {
matches!(self, Self::Enabled | Self::Disabled)
}
}
impl std::ops::Not for LineNumbers {
type Output = Self;
fn not(self) -> Self::Output {
use LineNumbers::{Disabled, Enabled};
match self {
Enabled => Disabled,
Disabled => Enabled,
ln => ln,
}
}
}
#[cfg(test)]
mod tests;