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::engine;
10use crate::ui::theme;
11
12pub struct MatchDisplay<'a> {
13 pub matches: &'a [engine::Match],
14}
15
16impl<'a> Widget for MatchDisplay<'a> {
17 fn render(self, area: Rect, buf: &mut Buffer) {
18 let title = format!(" Matches ({}) ", self.matches.len());
19 let block = Block::default()
20 .borders(Borders::ALL)
21 .border_style(Style::default().fg(theme::OVERLAY))
22 .title(Span::styled(title, Style::default().fg(theme::TEXT)));
23
24 if self.matches.is_empty() {
25 let paragraph = Paragraph::new(Line::from(Span::styled(
26 "No matches",
27 Style::default().fg(theme::SUBTEXT),
28 )))
29 .block(block)
30 .style(Style::default().bg(theme::BASE));
31 paragraph.render(area, buf);
32 return;
33 }
34
35 let mut lines = Vec::new();
36 for (i, m) in self.matches.iter().enumerate() {
37 lines.push(Line::from(vec![
38 Span::styled(
39 format!("Match {} ", i + 1),
40 Style::default().fg(theme::BLUE),
41 ),
42 Span::styled(
43 format!("[{}-{}]: ", m.start, m.end),
44 Style::default().fg(theme::SUBTEXT),
45 ),
46 Span::styled(
47 format!("\"{}\"", &m.text),
48 Style::default().fg(theme::GREEN),
49 ),
50 ]));
51
52 for cap in &m.captures {
53 let color = theme::capture_color(cap.index.saturating_sub(1));
54 let name_str = cap
55 .name
56 .as_ref()
57 .map(|n| format!(" '{n}'"))
58 .unwrap_or_default();
59 lines.push(Line::from(vec![
60 Span::styled(" ", Style::default()),
61 Span::styled(
62 format!("Group #{}{name_str} ", cap.index),
63 Style::default().fg(color),
64 ),
65 Span::styled(
66 format!("[{}-{}]: ", cap.start, cap.end),
67 Style::default().fg(theme::SUBTEXT),
68 ),
69 Span::styled(format!("\"{}\"", &cap.text), Style::default().fg(color)),
70 ]));
71 }
72 }
73
74 let paragraph = Paragraph::new(lines)
75 .block(block)
76 .style(Style::default().bg(theme::BASE))
77 .wrap(Wrap { trim: false });
78
79 paragraph.render(area, buf);
80 }
81}