Skip to main content

rgx/ui/
explanation.rs

1use ratatui::{
2    buffer::Buffer,
3    layout::Rect,
4    style::Style,
5    text::{Line, Span},
6    widgets::{Block, Borders, Paragraph, Widget, Wrap},
7};
8
9use crate::explain::ExplainNode;
10use crate::ui::theme;
11
12pub struct ExplanationPanel<'a> {
13    pub nodes: &'a [ExplainNode],
14    pub error: Option<&'a str>,
15}
16
17impl<'a> Widget for ExplanationPanel<'a> {
18    fn render(self, area: Rect, buf: &mut Buffer) {
19        let block = Block::default()
20            .borders(Borders::ALL)
21            .border_style(Style::default().fg(theme::OVERLAY))
22            .title(Span::styled(
23                " Explanation ",
24                Style::default().fg(theme::TEXT),
25            ));
26
27        if let Some(err) = self.error {
28            let lines = vec![Line::from(Span::styled(
29                err.to_string(),
30                Style::default().fg(theme::RED),
31            ))];
32            let paragraph = Paragraph::new(lines)
33                .block(block)
34                .style(Style::default().bg(theme::BASE));
35            paragraph.render(area, buf);
36            return;
37        }
38
39        if self.nodes.is_empty() {
40            let paragraph = Paragraph::new(Line::from(Span::styled(
41                "Enter a pattern to see its explanation",
42                Style::default().fg(theme::SUBTEXT),
43            )))
44            .block(block)
45            .style(Style::default().bg(theme::BASE));
46            paragraph.render(area, buf);
47            return;
48        }
49
50        let lines: Vec<Line> = self
51            .nodes
52            .iter()
53            .map(|node| {
54                let indent = "  ".repeat(node.depth);
55                let bullet = if node.depth > 0 { "|- " } else { "" };
56                Line::from(Span::styled(
57                    format!("{indent}{bullet}{}", node.description),
58                    Style::default().fg(if node.depth == 0 {
59                        theme::TEXT
60                    } else {
61                        theme::SUBTEXT
62                    }),
63                ))
64            })
65            .collect();
66
67        let paragraph = Paragraph::new(lines)
68            .block(block)
69            .style(Style::default().bg(theme::BASE))
70            .wrap(Wrap { trim: false });
71
72        paragraph.render(area, buf);
73    }
74}