Skip to main content

rgx/ui/
regex_input.rs

1use ratatui::{
2    buffer::Buffer,
3    layout::Rect,
4    style::{Modifier, Style},
5    text::{Line, Span},
6    widgets::{Block, Borders, Paragraph, Widget},
7};
8
9use crate::input::editor::Editor;
10use crate::ui::{syntax_highlight, theme};
11
12pub struct RegexInput<'a> {
13    pub editor: &'a Editor,
14    pub focused: bool,
15    pub error: Option<&'a str>,
16}
17
18impl<'a> Widget for RegexInput<'a> {
19    fn render(self, area: Rect, buf: &mut Buffer) {
20        let border_style = if self.focused {
21            Style::default().fg(theme::BLUE)
22        } else {
23            Style::default().fg(theme::OVERLAY)
24        };
25
26        let title = if let Some(err) = self.error {
27            let truncated: String = err
28                .chars()
29                .take((area.width as usize).saturating_sub(10))
30                .collect();
31            format!(" Pattern (Error: {truncated}) ")
32        } else {
33            " Pattern ".to_string()
34        };
35
36        let title_style = if self.error.is_some() {
37            Style::default().fg(theme::RED)
38        } else {
39            Style::default().fg(theme::TEXT)
40        };
41
42        let block = Block::default()
43            .borders(Borders::ALL)
44            .border_style(border_style)
45            .title(Span::styled(title, title_style));
46
47        let content = self.editor.content();
48        let tokens = syntax_highlight::highlight(content);
49        let spans = if tokens.is_empty() {
50            vec![Span::styled(
51                content.to_string(),
52                Style::default().fg(theme::TEXT),
53            )]
54        } else {
55            syntax_highlight::build_highlighted_spans(content, &tokens)
56        };
57        let line = Line::from(spans);
58
59        let paragraph = Paragraph::new(line)
60            .block(block)
61            .style(Style::default().bg(theme::BASE));
62
63        paragraph.render(area, buf);
64
65        // Render cursor
66        if self.focused {
67            let cursor_x = area.x + 1 + self.editor.visual_cursor() as u16;
68            let cursor_y = area.y + 1;
69            if cursor_x < area.x + area.width.saturating_sub(1)
70                && cursor_y < area.y + area.height.saturating_sub(1)
71            {
72                if let Some(cell) = buf.cell_mut((cursor_x, cursor_y)) {
73                    cell.set_style(
74                        Style::default()
75                            .fg(theme::BASE)
76                            .bg(theme::TEXT)
77                            .add_modifier(Modifier::BOLD),
78                    );
79                }
80            }
81        }
82    }
83}