use hjkl_buffer::{Viewport, Wrap};
use crate::types::{Cursor, FoldProvider, Query};
pub fn ensure_cursor_visible<B>(buf: &B, folds: &dyn FoldProvider, viewport: &mut Viewport)
where
B: Cursor + Query + ?Sized,
{
let cursor = Cursor::cursor(buf);
let cursor_row = cursor.line as usize;
let cursor_col = cursor.col as usize;
let v = *viewport;
let wrap_active = !matches!(v.wrap, Wrap::None) && v.text_width > 0;
if !wrap_active {
let pos = hjkl_buffer::Position::new(cursor_row, cursor_col);
viewport.ensure_visible(pos);
return;
}
if v.height == 0 {
return;
}
if cursor_row < v.top_row {
viewport.top_row = cursor_row;
viewport.top_col = 0;
return;
}
let height = v.height as usize;
loop {
let csr = cursor_screen_row_from(buf, folds, viewport, viewport.top_row);
match csr {
Some(row) if row < height => break,
_ => {}
}
let mut next = viewport.top_row + 1;
while next <= cursor_row && folds.is_row_hidden(next) {
next += 1;
}
if next > cursor_row {
viewport.top_row = cursor_row;
break;
}
viewport.top_row = next;
}
viewport.top_col = 0;
}
pub fn cursor_screen_row<B>(buf: &B, folds: &dyn FoldProvider, viewport: &Viewport) -> Option<usize>
where
B: Cursor + Query + ?Sized,
{
if matches!(viewport.wrap, Wrap::None) || viewport.text_width == 0 {
return None;
}
cursor_screen_row_from(buf, folds, viewport, viewport.top_row)
}
pub fn max_top_for_height<B>(
buf: &B,
folds: &dyn FoldProvider,
viewport: &Viewport,
height: usize,
) -> usize
where
B: Query + ?Sized,
{
if height == 0 {
return 0;
}
let row_count = Query::line_count(buf) as usize;
if row_count == 0 {
return 0;
}
let last = row_count - 1;
let mut total = 0usize;
let mut row = last;
let v = *viewport;
loop {
if !folds.is_row_hidden(row) {
total += if matches!(v.wrap, Wrap::None) || v.text_width == 0 {
1
} else {
let line = Query::line(buf, row as u32);
hjkl_buffer::wrap::wrap_segments(line, v.text_width, v.wrap).len()
};
}
if total >= height {
return row;
}
if row == 0 {
return 0;
}
row -= 1;
}
}
fn cursor_screen_row_from<B>(
buf: &B,
folds: &dyn FoldProvider,
viewport: &Viewport,
top: usize,
) -> Option<usize>
where
B: Cursor + Query + ?Sized,
{
let cursor = Cursor::cursor(buf);
let cursor_row = cursor.line as usize;
let cursor_col = cursor.col as usize;
if cursor_row < top {
return None;
}
let v = *viewport;
let mut screen = 0usize;
for r in top..=cursor_row {
if folds.is_row_hidden(r) {
continue;
}
let line = Query::line(buf, r as u32);
let segs = hjkl_buffer::wrap::wrap_segments(line, v.text_width, v.wrap);
if r == cursor_row {
let seg_idx = hjkl_buffer::wrap::segment_for_col(&segs, cursor_col);
return Some(screen + seg_idx);
}
screen += segs.len();
}
None
}