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}