intelli_shell/widgets/items/
variable.rs1use ratatui::{
2 buffer::Buffer,
3 layout::{Rect, Size},
4 style::Style,
5 text::Line,
6 widgets::Widget,
7};
8
9use crate::{
10 config::Theme,
11 model::{VariableSuggestion, VariableValue},
12 utils::format_env_var,
13 widgets::{CustomListItem, CustomTextArea},
14};
15
16const SECRET_VARIABLE_TITLE: &str = "(secret)";
17const NEW_VARIABLE_TITLE: &str = "(new)";
18const EDIT_VARIABLE_TITLE: &str = "(edit)";
19
20#[derive(PartialEq, Eq)]
22pub enum VariableSuggestionItemIdentifier {
23 New,
24 Previous(String),
25 Environment(String),
26 Existing(Option<i32>, String),
27 Completion(String),
28 Derived(String),
29}
30
31#[derive(Clone)]
33pub enum VariableSuggestionItem<'a> {
34 New {
35 sort_index: u8,
36 is_secret: bool,
37 textarea: CustomTextArea<'a>,
38 },
39 Previous {
40 sort_index: u8,
41 value: String,
42 score: f64,
43 },
44 Environment {
45 sort_index: u8,
46 content: String,
47 is_value: bool,
48 score: f64,
49 },
50 Existing {
51 sort_index: u8,
52 value: VariableValue,
53 score: f64,
54 completion_merged: bool,
55 editing: Option<CustomTextArea<'a>>,
56 },
57 Completion {
58 sort_index: u8,
59 value: String,
60 score: f64,
61 },
62 Derived {
63 sort_index: u8,
64 value: String,
65 },
66}
67
68impl<'a> VariableSuggestionItem<'a> {
69 pub fn identifier(&self) -> VariableSuggestionItemIdentifier {
71 match self {
72 VariableSuggestionItem::New { .. } => VariableSuggestionItemIdentifier::New,
73 VariableSuggestionItem::Previous { value, .. } => VariableSuggestionItemIdentifier::Previous(value.clone()),
74 VariableSuggestionItem::Environment { content, .. } => {
75 VariableSuggestionItemIdentifier::Environment(content.clone())
76 }
77 VariableSuggestionItem::Existing { value, .. } => {
78 VariableSuggestionItemIdentifier::Existing(value.id, value.value.clone())
79 }
80 VariableSuggestionItem::Completion { value, .. } => {
81 VariableSuggestionItemIdentifier::Completion(value.clone())
82 }
83 VariableSuggestionItem::Derived { value, .. } => VariableSuggestionItemIdentifier::Derived(value.clone()),
84 }
85 }
86
87 pub fn enter_edit_mode(&mut self) {
89 if let VariableSuggestionItem::Existing { value, editing, .. } = self
90 && editing.is_none()
91 {
92 *editing = Some(
93 CustomTextArea::new(Style::default(), true, false, value.value.clone())
94 .title(EDIT_VARIABLE_TITLE)
95 .focused(),
96 );
97 }
98 }
99
100 pub fn sort_index(&self) -> u8 {
101 match self {
102 VariableSuggestionItem::New { sort_index, .. }
103 | VariableSuggestionItem::Previous { sort_index, .. }
104 | VariableSuggestionItem::Environment { sort_index, .. }
105 | VariableSuggestionItem::Existing { sort_index, .. }
106 | VariableSuggestionItem::Completion { sort_index, .. }
107 | VariableSuggestionItem::Derived { sort_index, .. } => *sort_index,
108 }
109 }
110
111 pub fn score(&self) -> f64 {
112 match self {
113 VariableSuggestionItem::Previous { score, .. }
114 | VariableSuggestionItem::Environment { score, .. }
115 | VariableSuggestionItem::Existing { score, .. }
116 | VariableSuggestionItem::Completion { score, .. } => *score,
117 _ => 0.0,
118 }
119 }
120}
121
122impl<'a> From<(u8, VariableSuggestion, f64)> for VariableSuggestionItem<'a> {
123 fn from((sort_index, suggestion, score): (u8, VariableSuggestion, f64)) -> Self {
124 match suggestion {
125 VariableSuggestion::Secret => Self::New {
126 sort_index,
127 is_secret: true,
128 textarea: CustomTextArea::new(Style::default(), true, false, "")
129 .title(SECRET_VARIABLE_TITLE)
130 .focused(),
131 },
132 VariableSuggestion::New => Self::New {
133 sort_index,
134 is_secret: false,
135 textarea: CustomTextArea::new(Style::default(), true, false, "")
136 .title(NEW_VARIABLE_TITLE)
137 .focused(),
138 },
139 VariableSuggestion::Previous(value) => Self::Previous {
140 sort_index,
141 value,
142 score,
143 },
144 VariableSuggestion::Environment { env_var_name, value } => {
145 if let Some(value) = value {
146 Self::Environment {
147 sort_index,
148 content: value,
149 is_value: true,
150 score,
151 }
152 } else {
153 Self::Environment {
154 sort_index,
155 content: format_env_var(env_var_name),
156 is_value: false,
157 score,
158 }
159 }
160 }
161 VariableSuggestion::Existing(value) => Self::Existing {
162 sort_index,
163 value,
164 score,
165 completion_merged: false,
166 editing: None,
167 },
168 VariableSuggestion::Completion(value) => Self::Completion {
169 sort_index,
170 value,
171 score,
172 },
173 VariableSuggestion::Derived(value) => Self::Derived { sort_index, value },
174 }
175 }
176}
177
178impl<'i> CustomListItem for VariableSuggestionItem<'i> {
179 type Widget<'w>
180 = VariableSuggestionItemWidget<'w>
181 where
182 'i: 'w;
183
184 fn as_widget<'a>(
185 &'a self,
186 theme: &Theme,
187 inline: bool,
188 is_highlighted: bool,
189 is_discarded: bool,
190 ) -> (Self::Widget<'a>, Size) {
191 match self {
192 VariableSuggestionItem::New { textarea, .. }
193 | VariableSuggestionItem::Existing {
194 editing: Some(textarea),
195 ..
196 } => {
197 let style = match (is_highlighted, is_discarded) {
198 (true, true) => theme.highlight_secondary_full(),
199 (true, false) => theme.highlight_primary_full(),
200 (false, true) => theme.secondary,
201 (false, false) => theme.primary,
202 };
203
204 let mut ta_render = textarea.clone();
205 ta_render.set_focus(is_highlighted);
206 ta_render.set_style(style);
207 (
208 VariableSuggestionItemWidget(VariableSuggestionItemWidgetInner::TextArea(ta_render)),
209 Size::new(10, 1),
210 )
211 }
212 VariableSuggestionItem::Existing {
213 value: VariableValue { value: text, .. },
214 ..
215 }
216 | VariableSuggestionItem::Previous { value: text, .. }
217 | VariableSuggestionItem::Environment { content: text, .. }
218 | VariableSuggestionItem::Completion { value: text, .. }
219 | VariableSuggestionItem::Derived { value: text, .. } => {
220 let (line, size) = text.as_widget(theme, inline, is_highlighted, is_discarded);
221 (
222 VariableSuggestionItemWidget(VariableSuggestionItemWidgetInner::Literal(line)),
223 size,
224 )
225 }
226 }
227 }
228}
229
230pub struct VariableSuggestionItemWidget<'a>(VariableSuggestionItemWidgetInner<'a>);
232#[allow(clippy::large_enum_variant)]
233enum VariableSuggestionItemWidgetInner<'a> {
234 TextArea(CustomTextArea<'a>),
235 Literal(Line<'a>),
236}
237
238impl<'a> Widget for VariableSuggestionItemWidget<'a> {
239 fn render(self, area: Rect, buf: &mut Buffer)
240 where
241 Self: Sized,
242 {
243 match self.0 {
244 VariableSuggestionItemWidgetInner::TextArea(ta) => ta.render(area, buf),
245 VariableSuggestionItemWidgetInner::Literal(l) => l.render(area, buf),
246 }
247 }
248}