Fix viewer scrolling so current line stays visible

This commit is contained in:
SW 2026-06-17 22:09:20 +02:00
parent 9996616d9b
commit 525acb9eb4
2 changed files with 21 additions and 12 deletions

View file

@ -46,8 +46,13 @@ impl LogViewer {
}
}
pub fn visible_lines(&self) -> Vec<&String> {
self.buffer.iter().filter(|l| self.search.matches(l)).collect()
/// Returns visible lines together with their original buffer index.
pub fn visible_lines(&self) -> Vec<(usize, &String)> {
self.buffer
.iter()
.enumerate()
.filter(|(_, l)| self.search.matches(l))
.collect()
}
pub fn push_line(&mut self, line: String) {

View file

@ -109,19 +109,22 @@ fn draw_log_buffer(f: &mut Frame, viewer: &LogViewer, area: ratatui::layout::Rec
let title = format!(" {} — {} ", viewer.source, if viewer.live { "LIVE" } else { "PAUSED" });
let visible = viewer.visible_lines();
// Compute the viewport offset so the current line stays in view.
let current_visible_idx = visible
.iter()
.position(|(i, _)| *i == viewer.scroll)
.unwrap_or(visible.len().saturating_sub(1));
let scroll_offset = current_visible_idx
.saturating_sub(area.height as usize / 2)
.min(visible.len().saturating_sub(1));
let lines: Vec<Line> = visible
.iter()
.enumerate()
.map(|(i, line)| {
let global_idx = viewer
.buffer
.iter()
.position(|l| std::ptr::eq(l.as_ptr(), line.as_ptr()))
.unwrap_or(i);
let is_current = global_idx == viewer.scroll;
.map(|(global_idx, line)| {
let is_current = *global_idx == viewer.scroll;
let is_match = viewer
.search_cursor
.map(|c| c == global_idx)
.map(|c| c == *global_idx)
.unwrap_or(false);
let mut style = Style::default();
@ -139,7 +142,8 @@ fn draw_log_buffer(f: &mut Frame, viewer: &LogViewer, area: ratatui::layout::Rec
let paragraph = Paragraph::new(Text::from(lines))
.block(default_block(&title))
.wrap(Wrap { trim: false });
.wrap(Wrap { trim: false })
.scroll((scroll_offset as u16, 0));
f.render_widget(paragraph, area);
}