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