intelli_shell/widgets/
template.rs1use 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#[derive(Clone)]
21#[cfg_attr(test, derive(Debug))]
22pub struct CommandTemplateWidget {
23 pub template: CommandTemplate,
25 pub current_variable_index: usize,
27 block: Option<Block<'static>>,
29 primary_style: Style,
30 secondary_style: Style,
31}
32
33impl CommandTemplateWidget {
34 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}