use lv_tui::component::{Component, EventCx, LayoutCx, MeasureCx};
use lv_tui::event::Event;
use lv_tui::geom::{Pos, Rect, Size};
use lv_tui::layout::Constraint;
use lv_tui::render::RenderCx;
use lv_tui::style::Style;
use crate::highlight::CodeHighlight;
pub struct CodeView {
hl: CodeHighlight,
scroll: u16,
rect: Rect,
}
impl CodeView {
pub fn new(code: &str, language: &str) -> Self {
Self { hl: CodeHighlight::new(code, language), scroll: 0, rect: Rect::default() }
}
}
impl Component for CodeView {
fn render(&self, cx: &mut RenderCx) {
let vp = self.rect;
let visible = vp.height.max(1) as usize;
let start = (self.scroll as usize).min(self.hl.line_count().saturating_sub(visible));
let end = (start + visible).min(self.hl.line_count());
for i in start..end {
let y = vp.y.saturating_add((i - start) as u16);
self.hl.render_line(i, cx.buffer, Pos { x: vp.x, y }, vp);
}
}
fn measure(&self, _c: Constraint, _cx: &mut MeasureCx) -> Size {
Size { width: 80, height: self.hl.line_count().max(1) as u16 }
}
fn event(&mut self, event: &Event, cx: &mut EventCx) {
if let Event::Key(key) = event {
let visible = self.rect.height.max(1) as u16;
let total = self.hl.line_count().max(1) as u16;
match &key.key {
lv_tui::event::Key::Up => { self.scroll = self.scroll.saturating_sub(1); cx.invalidate_paint(); }
lv_tui::event::Key::Down => { self.scroll = (self.scroll + 1).min(total.saturating_sub(visible)); cx.invalidate_paint(); }
lv_tui::event::Key::PageUp => { self.scroll = self.scroll.saturating_sub(visible); cx.invalidate_paint(); }
lv_tui::event::Key::PageDown => { self.scroll = (self.scroll + visible).min(total.saturating_sub(visible)); cx.invalidate_paint(); }
_ => {}
}
}
}
fn layout(&mut self, rect: Rect, _cx: &mut LayoutCx) { self.rect = rect; }
fn focusable(&self) -> bool { false }
fn style(&self) -> Style { Style::default() }
}