intelli_shell/widgets/
dynamic.rs

1use std::{
2    fmt::{Display, Formatter},
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::{CommandPart, DynamicCommand},
17};
18
19/// The widget for a command containing variables
20#[cfg_attr(debug_assertions, derive(Debug))]
21#[derive(Clone)]
22pub struct DynamicCommandWidget {
23    /// The dynamic command
24    pub command: DynamicCommand,
25    // Internal fields
26    block: Option<Block<'static>>,
27    primary_style: Style,
28    secondary_style: Style,
29}
30
31impl DynamicCommandWidget {
32    /// Creates a new widget for the dynamic command
33    pub fn new(theme: &Theme, inline: bool, command: DynamicCommand) -> 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            command,
46            block,
47            primary_style: theme.primary.into(),
48            secondary_style: theme.secondary.into(),
49        }
50    }
51}
52
53impl Display for DynamicCommandWidget {
54    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
55        write!(f, "{}", self.command)
56    }
57}
58
59impl Widget for &DynamicCommandWidget {
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.command.parts.iter().map(|p| match p {
68            CommandPart::Text(t) | CommandPart::VariableValue(_, t) => Span::styled(t, self.secondary_style),
69            CommandPart::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.name), style)
77            }
78        }))
79        .render(area, buf);
80    }
81}
82
83impl Deref for DynamicCommandWidget {
84    type Target = DynamicCommand;
85
86    fn deref(&self) -> &Self::Target {
87        &self.command
88    }
89}
90
91impl DerefMut for DynamicCommandWidget {
92    fn deref_mut(&mut self) -> &mut Self::Target {
93        &mut self.command
94    }
95}