intelli_shell/widgets/
dynamic.rs1use 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#[cfg_attr(debug_assertions, derive(Debug))]
21#[derive(Clone)]
22pub struct DynamicCommandWidget {
23 pub command: DynamicCommand,
25 block: Option<Block<'static>>,
27 primary_style: Style,
28 secondary_style: Style,
29}
30
31impl DynamicCommandWidget {
32 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}