lv-tui-code-highlight 0.3.0

Syntax highlighting for the lv-tui framework
Documentation
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;

/// A lv-tui Component that renders syntax-highlighted code.
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() }
}