intelli_shell/widgets/
template.rs

1use std::{
2    fmt,
3    ops::{Deref, DerefMut},
4};
5
6use ratatui::{
7    buffer::Buffer,
8    layout::Rect,
9    style::Style,
10    text::{Line, Span},
11    widgets::{Block, Borders, Widget},
12};
13
14use crate::{
15    config::Theme,
16    model::{CommandTemplate, TemplatePart},
17};
18
19/// The widget for a command containing variables
20#[derive(Clone)]
21#[cfg_attr(test, derive(Debug))]
22pub struct CommandTemplateWidget {
23    /// The command template
24    pub template: CommandTemplate,
25    /// The index of the current variable being edited (for highlighting)
26    pub current_variable_index: usize,
27    // Internal fields
28    block: Option<Block<'static>>,
29    primary_style: Style,
30    secondary_style: Style,
31}
32
33impl CommandTemplateWidget {
34    /// Creates a new widget for the command template
35    pub fn new(theme: &Theme, inline: bool, template: CommandTemplate) -> Self {
36        let block = if !inline {
37            Some(
38                Block::default()
39                    .borders(Borders::ALL)
40                    .style(theme.primary)
41                    .title(" Command "),
42            )
43        } else {
44            None
45        };
46        Self {
47            template,
48            current_variable_index: 0,
49            block,
50            primary_style: theme.primary.into(),
51            secondary_style: theme.secondary.into(),
52        }
53    }
54}
55
56impl fmt::Display for CommandTemplateWidget {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        write!(f, "{}", self.template)
59    }
60}
61
62impl Widget for &CommandTemplateWidget {
63    fn render(self, mut area: Rect, buf: &mut Buffer) {
64        if let Some(block) = &self.block {
65            block.render(area, buf);
66            area = block.inner(area);
67        }
68
69        let mut variable_index = 0;
70        Line::from_iter(self.template.parts.iter().map(|p| match p {
71            TemplatePart::Text(t) => Span::styled(t, self.secondary_style),
72            TemplatePart::Variable(v) => {
73                let is_current = variable_index == self.current_variable_index;
74                variable_index += 1;
75
76                let style = if is_current {
77                    self.primary_style
78                } else {
79                    self.secondary_style
80                };
81
82                Span::styled(format!("{{{{{}}}}}", v.display), style)
83            }
84            TemplatePart::VariableValue(_v, t) => {
85                let is_current = variable_index == self.current_variable_index;
86                variable_index += 1;
87
88                let style = if is_current {
89                    self.primary_style
90                } else {
91                    self.secondary_style
92                };
93
94                Span::styled(t, style)
95            }
96        }))
97        .render(area, buf);
98    }
99}
100
101impl Deref for CommandTemplateWidget {
102    type Target = CommandTemplate;
103
104    fn deref(&self) -> &Self::Target {
105        &self.template
106    }
107}
108
109impl DerefMut for CommandTemplateWidget {
110    fn deref_mut(&mut self) -> &mut Self::Target {
111        &mut self.template
112    }
113}