use ratatui::text::{Line, Span};
use super::super::theme::Palette;
pub(super) struct Attempt {
pub lines: Vec<Line<'static>>,
pub cursor_drawn: bool,
}
pub(super) fn to_cursor<B, F>(
cursor_row: usize,
start: usize,
mut body: B,
fallback: F,
) -> Vec<Line<'static>>
where
B: FnMut(usize) -> Attempt,
F: FnOnce() -> Vec<Line<'static>>,
{
let mut offset = start.min(cursor_row);
loop {
let attempt = body(offset);
if attempt.cursor_drawn {
return attempt.lines;
}
if offset >= cursor_row {
return fallback();
}
offset += 1;
}
}
enum Side {
Above,
Below,
}
fn marker(count: usize, side: Side, palette: Palette) -> Line<'static> {
let text = match side {
Side::Above => format!(" ... {count} above"),
Side::Below => format!(" ... {count} below"),
};
Line::from(Span::styled(text, palette.muted()))
}
pub(super) fn window_markers(
lines: &mut Vec<Line<'static>>,
hidden_below: usize,
offset: usize,
palette: Palette,
) {
if hidden_below > 0 {
lines.push(marker(hidden_below, Side::Below, palette));
}
if offset > 0 {
lines.insert(0, marker(offset, Side::Above, palette));
}
}
pub(super) fn cursor_markers(
lines: &mut Vec<Line<'static>>,
hidden_below: usize,
cursor_row: usize,
budget: usize,
palette: Palette,
) {
if cursor_row > 0 && lines.len() < budget {
lines.insert(0, marker(cursor_row, Side::Above, palette));
}
if hidden_below > 0 && lines.len() < budget {
lines.push(marker(hidden_below, Side::Below, palette));
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::lookout::view::fixtures::plain;
fn body(rows: usize) -> Vec<Line<'static>> {
(0..rows)
.map(|row| Line::from(format!("row {row}")))
.collect()
}
fn text(lines: &[Line<'static>]) -> Vec<String> {
lines
.iter()
.map(|line| {
line.spans
.iter()
.map(|span| span.content.as_ref())
.collect()
})
.collect()
}
#[test]
fn a_window_marks_the_rows_off_both_ends_around_the_rows_it_drew() {
let mut lines = body(2);
window_markers(&mut lines, 3, 4, plain());
assert_eq!(
text(&lines),
vec![" ... 4 above", "row 0", "row 1", " ... 3 below"]
);
}
#[test]
fn a_window_that_hid_nothing_marks_neither_end() {
let mut lines = body(2);
window_markers(&mut lines, 0, 0, plain());
assert_eq!(text(&lines), vec!["row 0", "row 1"]);
}
#[test]
fn the_cursor_body_spends_its_last_line_on_the_above_marker() {
let mut lines = body(1);
cursor_markers(&mut lines, 3, 2, 2, plain());
assert_eq!(text(&lines), vec![" ... 2 above", "row 0"]);
let mut lines = body(1);
cursor_markers(&mut lines, 3, 2, 3, plain());
assert_eq!(
text(&lines),
vec![" ... 2 above", "row 0", " ... 3 below"]
);
}
}