Skip to main content

lv_tui_code_highlight/
view.rs

1use lv_tui::component::{Component, EventCx, LayoutCx, MeasureCx};
2use lv_tui::event::Event;
3use lv_tui::geom::{Pos, Rect, Size};
4use lv_tui::layout::Constraint;
5use lv_tui::render::RenderCx;
6use lv_tui::style::Style;
7
8use crate::highlight::CodeHighlight;
9
10/// A lv-tui Component that renders syntax-highlighted code.
11pub struct CodeView {
12    hl: CodeHighlight,
13    scroll: u16,
14    rect: Rect,
15}
16
17impl CodeView {
18    pub fn new(code: &str, language: &str) -> Self {
19        Self { hl: CodeHighlight::new(code, language), scroll: 0, rect: Rect::default() }
20    }
21}
22
23impl Component for CodeView {
24    fn render(&self, cx: &mut RenderCx) {
25        let vp = self.rect;
26        let visible = vp.height.max(1) as usize;
27        let start = (self.scroll as usize).min(self.hl.line_count().saturating_sub(visible));
28        let end = (start + visible).min(self.hl.line_count());
29
30        for i in start..end {
31            let y = vp.y.saturating_add((i - start) as u16);
32            self.hl.render_line(i, cx.buffer, Pos { x: vp.x, y }, vp);
33        }
34    }
35
36    fn measure(&self, _c: Constraint, _cx: &mut MeasureCx) -> Size {
37        Size { width: 80, height: self.hl.line_count().max(1) as u16 }
38    }
39
40    fn event(&mut self, event: &Event, cx: &mut EventCx) {
41        if let Event::Key(key) = event {
42            let visible = self.rect.height.max(1) as u16;
43            let total = self.hl.line_count().max(1) as u16;
44            match &key.key {
45                lv_tui::event::Key::Up => { self.scroll = self.scroll.saturating_sub(1); cx.invalidate_paint(); }
46                lv_tui::event::Key::Down => { self.scroll = (self.scroll + 1).min(total.saturating_sub(visible)); cx.invalidate_paint(); }
47                lv_tui::event::Key::PageUp => { self.scroll = self.scroll.saturating_sub(visible); cx.invalidate_paint(); }
48                lv_tui::event::Key::PageDown => { self.scroll = (self.scroll + visible).min(total.saturating_sub(visible)); cx.invalidate_paint(); }
49                _ => {}
50            }
51        }
52    }
53
54    fn layout(&mut self, rect: Rect, _cx: &mut LayoutCx) { self.rect = rect; }
55    fn focusable(&self) -> bool { false }
56    fn style(&self) -> Style { Style::default() }
57}