Skip to main content

intelli_shell/widgets/
completion.rs

1use ratatui::{
2    backend::FromCrossterm,
3    buffer::Buffer,
4    layout::{Rect, Size},
5    style::{Color, Style},
6    text::{Line, Span, Text},
7    widgets::Widget,
8};
9
10use crate::{config::Theme, model::VariableCompletion};
11
12const DEFAULT_STYLE: Style = Style::new();
13
14/// Widget to render a [`VariableCompletion`]
15#[derive(Clone)]
16pub struct VariableCompletionWidget<'a>(Text<'a>, Size);
17impl<'a> VariableCompletionWidget<'a> {
18    /// Builds a new [`VariableCompletionWidget`]
19    pub fn new(
20        completion: &'a VariableCompletion,
21        theme: &Theme,
22        is_highlighted: bool,
23        is_discarded: bool,
24        plain_style: bool,
25        full_content: bool,
26    ) -> Self {
27        let mut line_style = DEFAULT_STYLE;
28        if is_highlighted && let Some(bg_color) = theme.highlight {
29            line_style = line_style.bg(Color::from_crossterm(bg_color));
30        }
31        // Determine the right styles to use based on highlighted and discarded status
32        let (primary_style, secondary_style) = match (plain_style, is_discarded, is_highlighted) {
33            // Discarded
34            (_, true, false) => (theme.secondary, theme.secondary),
35            // Discarded & highlighted
36            (_, true, true) => (theme.highlight_secondary, theme.highlight_secondary),
37            // Plain style, regular
38            (true, false, false) => (theme.primary, theme.primary),
39            // Plain style, highlighted
40            (true, false, true) => (theme.highlight_primary, theme.highlight_primary),
41            // Regular
42            (false, false, false) => (theme.primary, theme.secondary),
43            // Highlighted
44            (false, false, true) => (theme.highlight_primary, theme.highlight_secondary),
45        };
46
47        // Setup the parts always present: variable and provider
48        let mut parts = vec![
49            Span::styled(&completion.variable, Style::from_crossterm(primary_style)),
50            Span::styled(": ", Style::from_crossterm(primary_style)),
51            Span::styled(&completion.suggestions_provider, Style::from_crossterm(secondary_style)),
52        ];
53
54        // If the full content has to be rendered
55        if full_content {
56            // Include the prefix
57            parts.insert(0, Span::styled("$ ", Style::from_crossterm(primary_style)));
58            // And the root command for non-global completions
59            if !completion.is_global() {
60                parts.insert(1, Span::styled("(", Style::from_crossterm(primary_style)));
61                parts.insert(
62                    2,
63                    Span::styled(&completion.root_cmd, Style::from_crossterm(primary_style)),
64                );
65                parts.insert(3, Span::styled(") ", Style::from_crossterm(primary_style)));
66            }
67        }
68
69        let text = Text::from(vec![Line::from(parts)]).style(line_style);
70        let width = text.width() as u16;
71        let height = text.height() as u16;
72        VariableCompletionWidget(text, Size::new(width, height))
73    }
74
75    /// Retrieves the size of this widget
76    pub fn size(&self) -> Size {
77        self.1
78    }
79}
80
81impl<'a> Widget for VariableCompletionWidget<'a> {
82    fn render(self, area: Rect, buf: &mut Buffer)
83    where
84        Self: Sized,
85    {
86        self.0.render(area, buf);
87    }
88}