rusticity_term/ui/
query_editor.rs1use ratatui::{
2 layout::Rect,
3 style::{Color, Style},
4 text::{Line, Span},
5 widgets::{Block, BorderType, Borders, Paragraph, Wrap},
6 Frame,
7};
8
9use super::styles;
10
11pub struct QueryEditorConfig<'a> {
12 pub query_text: &'a str,
13 pub cursor_line: usize,
14 pub cursor_col: usize,
15 pub is_active: bool,
16 pub title: &'a str,
17 pub area: Rect,
18}
19
20pub fn render_query_editor(frame: &mut Frame, config: QueryEditorConfig) {
21 let (border_style, border_type) = if config.is_active {
22 (styles::active_border(), BorderType::Double)
23 } else {
24 (Style::default(), BorderType::Plain)
25 };
26
27 let lines: Vec<Line> = config
28 .query_text
29 .lines()
30 .enumerate()
31 .map(|(line_idx, line_text)| {
32 if config.is_active && line_idx == config.cursor_line {
33 let before = &line_text[..config.cursor_col.min(line_text.len())];
34 let cursor_char = line_text
35 .chars()
36 .nth(config.cursor_col)
37 .map(|c| c.to_string())
38 .unwrap_or_else(|| " ".to_string());
39 let after =
40 &line_text[(config.cursor_col + cursor_char.len()).min(line_text.len())..];
41
42 Line::from(vec![
43 Span::raw(before),
44 Span::styled(cursor_char, styles::bg_white().fg(Color::Black)),
45 Span::raw(after),
46 ])
47 } else {
48 Line::from(line_text.to_string())
49 }
50 })
51 .collect();
52
53 let paragraph = Paragraph::new(lines)
54 .block(
55 Block::default()
56 .title(config.title)
57 .borders(Borders::ALL)
58 .border_type(BorderType::Rounded)
59 .border_style(border_style)
60 .border_type(border_type),
61 )
62 .wrap(Wrap { trim: false });
63
64 frame.render_widget(paragraph, config.area);
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn test_query_editor_config_creation() {
73 let config = QueryEditorConfig {
74 query_text: "SELECT * FROM logs",
75 cursor_line: 0,
76 cursor_col: 5,
77 is_active: true,
78 title: "Query",
79 area: Rect::new(0, 0, 80, 10),
80 };
81
82 assert_eq!(config.query_text, "SELECT * FROM logs");
83 assert_eq!(config.cursor_line, 0);
84 assert_eq!(config.cursor_col, 5);
85 assert!(config.is_active);
86 }
87
88 #[test]
89 fn test_query_editor_multiline() {
90 assert_eq!(
91 "fields @timestamp\n| sort @timestamp desc\n| limit 100"
92 .lines()
93 .count(),
94 3
95 );
96 }
97}