1use std::fmt;
2
3use crate::common::{
4 UtfWidth, CHMOD_LINES, CLOUD_NEWDIR_LINES, FILTER_LINES, NEWDIR_LINES, NEWFILE_LINES,
5 NVIM_ADDRESS_LINES, PASSWORD_LINES_DEVICE, PASSWORD_LINES_SUDO, REGEX_LINES, REMOTE_LINES,
6 RENAME_LINES, SHELL_LINES, SORT_LINES,
7};
8use crate::modes::InputCompleted;
9use crate::modes::MountAction;
10use crate::modes::{PasswordKind, PasswordUsage};
11
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum MarkAction {
17 Jump,
19 New,
21}
22
23#[derive(Clone, Copy, Debug, Eq, PartialEq)]
26pub enum NeedConfirmation {
27 Copy,
29 Delete,
31 Move,
33 EmptyTrash,
35 BulkAction,
37 DeleteCloud,
39}
40
41impl NeedConfirmation {
42 #[must_use]
45 pub fn confirmation_string(&self, destination: &str) -> String {
46 match *self {
47 Self::Copy => {
48 format!("Files will be copied to {destination}")
49 }
50 Self::Delete | Self::EmptyTrash => "Files will be deleted permanently".to_owned(),
51 Self::Move => {
52 format!("Files will be moved to {destination}")
53 }
54 Self::BulkAction => "Those files will be renamed or created :".to_owned(),
55 Self::DeleteCloud => "Remote Files will be deleted permanently".to_owned(),
56 }
57 }
58}
59
60impl CursorOffset for NeedConfirmation {
61 #[must_use]
65 fn cursor_offset(&self) -> u16 {
66 self.to_string().utf_width_u16() + 9
67 }
68}
69
70impl Leave for NeedConfirmation {
71 fn must_refresh(&self) -> bool {
72 true
73 }
74
75 fn must_reset_mode(&self) -> bool {
76 true
77 }
78}
79
80impl std::fmt::Display for NeedConfirmation {
81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82 match *self {
83 Self::Delete => write!(f, "Delete files :"),
84 Self::DeleteCloud => write!(f, "Delete files :"),
85 Self::Move => write!(f, "Move files here :"),
86 Self::Copy => write!(f, "Copy files here :"),
87 Self::EmptyTrash => write!(f, "Empty the trash ?"),
88 Self::BulkAction => write!(f, "Bulk :"),
89 }
90 }
91}
92
93#[derive(Clone, Copy, PartialEq, Eq)]
99pub enum InputSimple {
100 Rename,
102 Chmod,
104 Newfile,
106 Newdir,
108 RegexMatch,
110 Sort,
112 Filter,
114 SetNvimAddr,
116 Password(Option<MountAction>, PasswordUsage),
118 ShellCommand,
120 Remote,
122 CloudNewdir,
124}
125
126impl fmt::Display for InputSimple {
127 fn fmt(&self, f: &mut std::fmt::Formatter) -> fmt::Result {
128 match *self {
129 Self::Rename => write!(f, "Rename: "),
130 Self::Chmod => write!(f, "Chmod: "),
131 Self::Newfile => write!(f, "Newfile: "),
132 Self::Newdir => write!(f, "Newdir: "),
133 Self::RegexMatch => write!(f, "Regex: "),
134 Self::SetNvimAddr => write!(f, "Neovim: "),
135 Self::CloudNewdir => write!(f, "Newdir: "),
136 Self::ShellCommand => write!(f, "Shell: "),
137 Self::Sort => {
138 write!(f, "Sort: ")
139 }
140 Self::Filter => write!(f, "Filter: "),
141 Self::Password(_, PasswordUsage::CRYPTSETUP(password_kind)) => {
142 write!(f, "{password_kind}")
143 }
144 Self::Password(_, _) => write!(f, " sudo: "),
145 Self::Remote => write!(f, "Remote: "),
146 }
147 }
148}
149
150impl InputSimple {
151 const EDIT_BOX_OFFSET: u16 = 11;
152 const SORT_CURSOR_OFFSET: u16 = 8;
153 const PASSWORD_CURSOR_OFFSET: u16 = 9;
154
155 #[must_use]
158 pub const fn lines(&self) -> &'static [&'static str] {
159 match *self {
160 Self::Chmod => &CHMOD_LINES,
161 Self::Filter => &FILTER_LINES,
162 Self::Newdir => &NEWDIR_LINES,
163 Self::Newfile => &NEWFILE_LINES,
164 Self::Password(_, PasswordUsage::CRYPTSETUP(PasswordKind::SUDO)) => {
165 &PASSWORD_LINES_SUDO
166 }
167 Self::Password(_, PasswordUsage::CRYPTSETUP(PasswordKind::CRYPTSETUP)) => {
168 &PASSWORD_LINES_DEVICE
169 }
170 Self::Password(_, _) => &PASSWORD_LINES_SUDO,
171 Self::RegexMatch => ®EX_LINES,
172 Self::Rename => &RENAME_LINES,
173 Self::SetNvimAddr => &NVIM_ADDRESS_LINES,
174 Self::ShellCommand => &SHELL_LINES,
175 Self::Sort => &SORT_LINES,
176 Self::Remote => &REMOTE_LINES,
177 Self::CloudNewdir => &CLOUD_NEWDIR_LINES,
178 }
179 }
180}
181
182pub trait CursorOffset {
184 fn cursor_offset(&self) -> u16;
185}
186
187impl CursorOffset for InputSimple {
188 fn cursor_offset(&self) -> u16 {
189 match *self {
190 Self::Sort => Self::SORT_CURSOR_OFFSET,
191 Self::Password(_, _) => Self::PASSWORD_CURSOR_OFFSET,
192 _ => Self::EDIT_BOX_OFFSET,
193 }
194 }
195}
196
197impl Leave for InputSimple {
198 fn must_refresh(&self) -> bool {
199 !matches!(
200 self,
201 Self::ShellCommand | Self::Filter | Self::Password(_, _) | Self::Sort
202 )
203 }
204
205 fn must_reset_mode(&self) -> bool {
206 !matches!(self, Self::ShellCommand | Self::Password(_, _))
207 }
208}
209
210#[derive(Clone, Copy, Debug, Eq, PartialEq)]
214pub enum Navigate {
215 History,
217 Shortcut,
219 Trash,
221 Marks(MarkAction),
223 TempMarks(MarkAction),
225 Mount,
227 Compress,
229 TuiApplication,
231 CliApplication,
233 Context,
235 Cloud,
237 Picker,
239 Flagged,
241}
242
243impl fmt::Display for Navigate {
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 match *self {
246 Self::Marks(_) => write!(f, "Marks jump:"),
247 Self::TempMarks(_) => write!(f, "Temp marks jump:"),
248 Self::History => write!(f, "History :"),
249 Self::Shortcut => write!(f, "Shortcut :"),
250 Self::Trash => write!(f, "Trash :"),
251 Self::TuiApplication => {
252 write!(f, "Start a new shell running a command:")
253 }
254 Self::Compress => write!(f, "Compress :"),
255 Self::Mount => write!(f, "Mount :"),
256 Self::CliApplication => write!(f, "Display infos :"),
257 Self::Context => write!(f, "Context"),
258 Self::Cloud => write!(f, "Cloud"),
259 Self::Picker => write!(f, "Picker"),
260 Self::Flagged => write!(f, "Flagged"),
261 }
262 }
263}
264
265impl CursorOffset for Navigate {
266 #[inline]
267 #[must_use]
268 fn cursor_offset(&self) -> u16 {
269 0
270 }
271}
272
273impl Leave for Navigate {
274 fn must_refresh(&self) -> bool {
275 !matches!(self, Self::CliApplication | Self::Context)
276 }
277
278 fn must_reset_mode(&self) -> bool {
279 !matches!(self, Self::CliApplication | Self::Context)
280 }
281}
282
283impl Navigate {
284 pub fn simple_draw_menu(&self) -> bool {
286 matches!(
287 self,
288 Self::Compress
289 | Self::Shortcut
290 | Self::TuiApplication
291 | Self::CliApplication
292 | Self::Marks(_)
293 | Self::Mount
294 )
295 }
296}
297
298#[derive(Clone, Copy, Eq, PartialEq)]
301pub enum Menu {
302 InputCompleted(InputCompleted),
309 InputSimple(InputSimple),
314 Navigate(Navigate),
316 NeedConfirmation(NeedConfirmation),
319 Nothing,
321}
322
323impl fmt::Display for Menu {
324 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
325 match *self {
326 Self::InputCompleted(input_completed) => input_completed.fmt(f),
327 Self::InputSimple(input_simple) => input_simple.fmt(f),
328 Self::Navigate(navigate) => navigate.fmt(f),
329 Self::NeedConfirmation(need_confirmation) => need_confirmation.fmt(f),
330 Self::Nothing => write!(f, ""),
331 }
332 }
333}
334
335impl Menu {
336 pub fn show_cursor(&self) -> bool {
338 self.cursor_offset() != 0
339 }
340
341 pub fn binds_per_mode(&self) -> &'static str {
342 match self {
343 Self::InputCompleted(_) => "Tab: completion. shift+⬆️, shift+⬇️: previous entries, shift+⬅️: erase line. Enter: validate",
344 Self::InputSimple(InputSimple::Filter) => "Enter reset the filters",
345 Self::InputSimple(InputSimple::Sort ) => "Enter reset the sort",
346 Self::InputSimple(_) => "shift+⬆️, shift+⬇️: previous entries, shift+⬅️: erase line. Enter: validate",
347 Self::Navigate(Navigate::Marks(MarkAction::Jump)) => "Type the mark letter to jump there. up, down to navigate, ENTER to select an element",
348 Self::Navigate(Navigate::Marks(MarkAction::New)) => "Type the mark set a mark here. up, down to navigate, ENTER to select an element",
349 Self::Navigate(Navigate::TempMarks(MarkAction::New)) => "Type the mark set a mark here. up, down to navigate, ENTER to select an element",
350 Self::Navigate(Navigate::Cloud) => "l: leave drive, arrows: navigation, Enter: enter dir / download file, d: new dir, x: delete selected, u: upload local file",
351 Self::Navigate(Navigate::Flagged) => "Up, Down: navigate, Enter / j: jump to this file, x: remove from flagged, u: clear",
352 Self::Navigate(Navigate::Trash) => "Up, Down: navigate.",
353 Self::Navigate(Navigate::Mount) => "m: mount, u: umount, e: eject (removable), g/ENTER: go to",
354 Self::Navigate(_) => "up, down to navigate, Enter to select an element",
355 Self::NeedConfirmation(_) => "",
356 _ => "",
357 }
358 }
359
360 pub fn is_nothing(&self) -> bool {
362 matches!(self, Self::Nothing)
363 }
364
365 pub fn is_navigate(&self) -> bool {
366 matches!(self, Self::Navigate(_))
367 }
368
369 pub fn is_input(&self) -> bool {
370 matches!(self, Self::InputCompleted(_) | Self::InputSimple(_))
371 }
372}
373
374impl CursorOffset for Menu {
375 #[inline]
378 #[must_use]
379 fn cursor_offset(&self) -> u16 {
380 match self {
381 Self::InputCompleted(input_completed) => input_completed.cursor_offset(),
382 Self::InputSimple(input_simple) => input_simple.cursor_offset(),
383 Self::Navigate(navigate) => navigate.cursor_offset(),
384 Self::NeedConfirmation(confirmed_action) => confirmed_action.cursor_offset(),
385 Self::Nothing => 0,
386 }
387 }
388}
389
390impl Leave for Menu {
391 fn must_refresh(&self) -> bool {
392 match self {
393 Self::InputCompleted(input_completed) => input_completed.must_refresh(),
394 Self::InputSimple(input_simple) => input_simple.must_refresh(),
395 Self::Navigate(navigate) => navigate.must_refresh(),
396 Self::NeedConfirmation(need_confirmation) => need_confirmation.must_refresh(),
397 Self::Nothing => true,
398 }
399 }
400
401 fn must_reset_mode(&self) -> bool {
402 match self {
403 Self::InputCompleted(input_completed) => input_completed.must_reset_mode(),
404 Self::InputSimple(input_simple) => input_simple.must_reset_mode(),
405 Self::Navigate(navigate) => navigate.must_reset_mode(),
406 Self::NeedConfirmation(need_confirmation) => need_confirmation.must_reset_mode(),
407 Self::Nothing => true,
408 }
409 }
410}
411
412pub trait Leave {
416 fn must_refresh(&self) -> bool;
418 fn must_reset_mode(&self) -> bool;
420}
421
422#[derive(Default, PartialEq)]
426pub enum Display {
427 #[default]
428 Directory,
430 Tree,
432 Preview,
434 Fuzzy,
436}
437
438impl Display {
439 fn is(&self, other: Self) -> bool {
440 self == &other
441 }
442
443 pub fn is_tree(&self) -> bool {
444 self.is(Self::Tree)
445 }
446
447 pub fn is_preview(&self) -> bool {
448 self.is(Self::Preview)
449 }
450
451 pub fn is_fuzzy(&self) -> bool {
452 self.is(Self::Fuzzy)
453 }
454}