1mod columnar_menu;
2mod list_menu;
3pub mod menu_functions;
4
5use crate::core_editor::Editor;
6use crate::History;
7use crate::{completion::history::HistoryCompleter, painting::Painter, Completer, Suggestion};
8pub use columnar_menu::ColumnarMenu;
9pub use list_menu::ListMenu;
10use nu_ansi_term::{Color, Style};
11
12pub struct MenuTextStyle {
14 pub selected_text_style: Style,
16 pub text_style: Style,
18 pub description_style: Style,
20}
21
22impl Default for MenuTextStyle {
23 fn default() -> Self {
24 Self {
25 selected_text_style: Color::Green.bold().reverse(),
26 text_style: Color::DarkGray.normal(),
27 description_style: Color::Yellow.normal(),
28 }
29 }
30}
31
32#[derive(Clone)]
34pub enum MenuEvent {
35 Activate(bool),
38 Deactivate,
40 Edit(bool),
43 NextElement,
45 PreviousElement,
47 MoveUp,
49 MoveDown,
51 MoveLeft,
53 MoveRight,
55 NextPage,
57 PreviousPage,
59}
60
61pub trait Menu: Send {
63 fn name(&self) -> &str;
65
66 fn indicator(&self) -> &str;
68
69 fn is_active(&self) -> bool;
71
72 fn menu_event(&mut self, event: MenuEvent);
74
75 fn can_quick_complete(&self) -> bool;
78
79 fn can_partially_complete(
82 &mut self,
83 values_updated: bool,
84 editor: &mut Editor,
85 completer: &mut dyn Completer,
86 ) -> bool;
87
88 fn update_values(&mut self, editor: &mut Editor, completer: &mut dyn Completer);
94
95 fn update_working_details(
101 &mut self,
102 editor: &mut Editor,
103 completer: &mut dyn Completer,
104 painter: &Painter,
105 );
106
107 fn replace_in_buffer(&self, editor: &mut Editor);
109
110 fn menu_required_lines(&self, terminal_columns: u16) -> u16;
113
114 fn menu_string(&self, available_lines: u16, use_ansi_coloring: bool) -> String;
116
117 fn min_rows(&self) -> u16;
119
120 fn get_values(&self) -> &[Suggestion];
122}
123
124pub enum ReedlineMenu {
126 EngineCompleter(Box<dyn Menu>),
128 HistoryMenu(Box<dyn Menu>),
130 WithCompleter {
132 menu: Box<dyn Menu>,
134 completer: Box<dyn Completer>,
136 },
137}
138
139impl ReedlineMenu {
140 fn as_ref(&self) -> &dyn Menu {
141 match self {
142 Self::EngineCompleter(menu)
143 | Self::HistoryMenu(menu)
144 | Self::WithCompleter { menu, .. } => menu.as_ref(),
145 }
146 }
147
148 fn as_mut(&mut self) -> &mut dyn Menu {
149 match self {
150 Self::EngineCompleter(menu)
151 | Self::HistoryMenu(menu)
152 | Self::WithCompleter { menu, .. } => menu.as_mut(),
153 }
154 }
155
156 pub(crate) fn can_partially_complete(
157 &mut self,
158 values_updated: bool,
159 editor: &mut Editor,
160 completer: &mut dyn Completer,
161 history: &dyn History,
162 ) -> bool {
163 match self {
164 Self::EngineCompleter(menu) => {
165 menu.can_partially_complete(values_updated, editor, completer)
166 }
167 Self::HistoryMenu(menu) => {
168 let mut history_completer = HistoryCompleter::new(history);
169 menu.can_partially_complete(values_updated, editor, &mut history_completer)
170 }
171 Self::WithCompleter {
172 menu,
173 completer: own_completer,
174 } => menu.can_partially_complete(values_updated, editor, own_completer.as_mut()),
175 }
176 }
177
178 pub(crate) fn update_values(
179 &mut self,
180 editor: &mut Editor,
181 completer: &mut dyn Completer,
182 history: &dyn History,
183 ) {
184 match self {
185 Self::EngineCompleter(menu) => menu.update_values(editor, completer),
186 Self::HistoryMenu(menu) => {
187 let mut history_completer = HistoryCompleter::new(history);
188 menu.update_values(editor, &mut history_completer);
189 }
190 Self::WithCompleter {
191 menu,
192 completer: own_completer,
193 } => {
194 menu.update_values(editor, own_completer.as_mut());
195 }
196 }
197 }
198
199 pub(crate) fn update_working_details(
200 &mut self,
201 editor: &mut Editor,
202 completer: &mut dyn Completer,
203 history: &dyn History,
204 painter: &Painter,
205 ) {
206 match self {
207 Self::EngineCompleter(menu) => {
208 menu.update_working_details(editor, completer, painter);
209 }
210 Self::HistoryMenu(menu) => {
211 let mut history_completer = HistoryCompleter::new(history);
212 menu.update_working_details(editor, &mut history_completer, painter);
213 }
214 Self::WithCompleter {
215 menu,
216 completer: own_completer,
217 } => {
218 menu.update_working_details(editor, own_completer.as_mut(), painter);
219 }
220 }
221 }
222}
223
224impl Menu for ReedlineMenu {
225 fn name(&self) -> &str {
226 self.as_ref().name()
227 }
228
229 fn indicator(&self) -> &str {
230 self.as_ref().indicator()
231 }
232
233 fn is_active(&self) -> bool {
234 self.as_ref().is_active()
235 }
236
237 fn menu_event(&mut self, event: MenuEvent) {
238 self.as_mut().menu_event(event);
239 }
240
241 fn can_quick_complete(&self) -> bool {
242 self.as_ref().can_quick_complete()
243 }
244
245 fn can_partially_complete(
246 &mut self,
247 values_updated: bool,
248 editor: &mut Editor,
249 completer: &mut dyn Completer,
250 ) -> bool {
251 match self {
252 Self::EngineCompleter(menu) | Self::HistoryMenu(menu) => {
253 menu.can_partially_complete(values_updated, editor, completer)
254 }
255 Self::WithCompleter {
256 menu,
257 completer: own_completer,
258 } => menu.can_partially_complete(values_updated, editor, own_completer.as_mut()),
259 }
260 }
261
262 fn update_values(&mut self, editor: &mut Editor, completer: &mut dyn Completer) {
263 match self {
264 Self::EngineCompleter(menu) | Self::HistoryMenu(menu) => {
265 menu.update_values(editor, completer);
266 }
267 Self::WithCompleter {
268 menu,
269 completer: own_completer,
270 } => {
271 menu.update_values(editor, own_completer.as_mut());
272 }
273 }
274 }
275
276 fn update_working_details(
277 &mut self,
278 editor: &mut Editor,
279 completer: &mut dyn Completer,
280 painter: &Painter,
281 ) {
282 match self {
283 Self::EngineCompleter(menu) | Self::HistoryMenu(menu) => {
284 menu.update_working_details(editor, completer, painter);
285 }
286 Self::WithCompleter {
287 menu,
288 completer: own_completer,
289 } => {
290 menu.update_working_details(editor, own_completer.as_mut(), painter);
291 }
292 }
293 }
294
295 fn replace_in_buffer(&self, editor: &mut Editor) {
296 self.as_ref().replace_in_buffer(editor);
297 }
298
299 fn menu_required_lines(&self, terminal_columns: u16) -> u16 {
300 self.as_ref().menu_required_lines(terminal_columns)
301 }
302
303 fn menu_string(&self, available_lines: u16, use_ansi_coloring: bool) -> String {
304 self.as_ref()
305 .menu_string(available_lines, use_ansi_coloring)
306 }
307
308 fn min_rows(&self) -> u16 {
309 self.as_ref().min_rows()
310 }
311
312 fn get_values(&self) -> &[Suggestion] {
313 self.as_ref().get_values()
314 }
315}