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 block: Option<Block<'static>>,
27 primary_style: Style,
28 secondary_style: Style,
29}
30
31impl CommandTemplateWidget {
32 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}