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    // Internal fields
26    block: Option<Block<'static>>,
27    primary_style: Style,
28    secondary_style: Style,
29}
30
31impl CommandTemplateWidget {
32    /// Creates a new widget for the command template
33    pub fn new(theme: &Theme, inline: bool, template: CommandTemplate) -> Self {
34        let block = if !inline {
35            Some(
36                Block::default()
37                    .borders(Borders::ALL)
38                    .style(theme.primary)
39                    .title(" Command "),
40            )
41        } else {
42            None
43        };
44        Self {
45            template,
46            block,
47            primary_style: theme.primary.into(),
48            secondary_style: theme.secondary.into(),
49        }
50    }
51}
52
53impl fmt::Display for CommandTemplateWidget {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        write!(f, "{}", self.template)
56    }
57}
58
59impl Widget for &CommandTemplateWidget {
60    fn render(self, mut area: Rect, buf: &mut Buffer) {
61        if let Some(block) = &self.block {
62            block.render(area, buf);
63            area = block.inner(area);
64        }
65
66        let mut first_variable_found = false;
67        Line::from_iter(self.template.parts.iter().map(|p| match p {
68            TemplatePart::Text(t) | TemplatePart::VariableValue(_, t) => Span::styled(t, self.secondary_style),
69            TemplatePart::Variable(v) => {
70                let style = if !first_variable_found {
71                    first_variable_found = true;
72                    self.primary_style
73                } else {
74                    self.secondary_style
75                };
76                Span::styled(format!("{{{{{}}}}}", v.display), style)
77            }
78        }))
79        .render(area, buf);
80    }
81}
82
83impl Deref for CommandTemplateWidget {
84    type Target = CommandTemplate;
85
86    fn deref(&self) -> &Self::Target {
87        &self.template
88    }
89}
90
91impl DerefMut for CommandTemplateWidget {
92    fn deref_mut(&mut self) -> &mut Self::Target {
93        &mut self.template
94    }
95}