diff options
Diffstat (limited to 'src/term_manager.rs')
-rw-r--r-- | src/term_manager.rs | 143 |
1 files changed, 116 insertions, 27 deletions
diff --git a/src/term_manager.rs b/src/term_manager.rs index 5fb88ed..89bb937 100644 --- a/src/term_manager.rs +++ b/src/term_manager.rs @@ -8,13 +8,15 @@ use tuikit::event::Event; use tuikit::prelude::*; use tuikit::term::Term; +use crate::completion::InputCompleted; use crate::compress::CompressionMethod; use crate::config::Colors; use crate::constant_strings_paths::{ - FILTER_PRESENTATION, HELP_FIRST_SENTENCE, HELP_SECOND_SENTENCE, + FILTER_PRESENTATION, HELP_FIRST_SENTENCE, HELP_SECOND_SENTENCE, LOG_FIRST_SENTENCE, + LOG_SECOND_SENTENCE, }; use crate::content_window::ContentWindow; -use crate::fileinfo::{fileinfo_attr, FileInfo}; +use crate::fileinfo::{fileinfo_attr, shorten_path, FileInfo}; use crate::fm_error::{FmError, FmResult}; use crate::mode::{InputSimple, MarkAction, Mode, Navigate, NeedConfirmation}; use crate::preview::{Preview, TextKind, Window}; @@ -23,6 +25,13 @@ use crate::status::Status; use crate::tab::Tab; use crate::trash::TrashInfo; +macro_rules! enumerated_colored_iter { + ($t:ident) => { + std::iter::zip($t.content().iter().enumerate(), MENU_COLORS.iter().cycle()) + .map(|((a, b), c)| (a, b, c)) + }; +} + /// At least 120 chars width to display 2 tabs. pub const MIN_WIDTH_FOR_DUAL_PANE: usize = 120; @@ -35,6 +44,19 @@ const FIRST_LINE_COLORS: [Attr; 6] = [ color_to_attr(Color::Rgb(230, 189, 87)), ]; +const MENU_COLORS: [Attr; 10] = [ + color_to_attr(Color::Rgb(236, 250, 250)), + color_to_attr(Color::Rgb(221, 242, 209)), + color_to_attr(Color::Rgb(205, 235, 197)), + color_to_attr(Color::Rgb(190, 227, 186)), + color_to_attr(Color::Rgb(174, 220, 174)), + color_to_attr(Color::Rgb(159, 212, 163)), + color_to_attr(Color::Rgb(174, 220, 174)), + color_to_attr(Color::Rgb(190, 227, 186)), + color_to_attr(Color::Rgb(205, 235, 197)), + color_to_attr(Color::Rgb(221, 242, 209)), +]; + const ATTR_YELLOW_BOLD: Attr = Attr { fg: Color::YELLOW, bg: Color::Default, @@ -179,7 +201,7 @@ impl<'a> WinMain<'a> { fn normal_first_row(&self, disk_space: &str) -> FmResult<Vec<String>> { Ok(vec![ - format!("{} ", self.tab.path_content.path.display()), + format!("{} ", shorten_path(&self.tab.path_content.path, None)?), format!("{} files ", self.tab.path_content.true_len()), format!("{} ", self.tab.path_content.used_space()), format!("Avail: {disk_space} "), @@ -195,6 +217,13 @@ impl<'a> WinMain<'a> { ] } + fn log_first_row() -> Vec<String> { + vec![ + LOG_FIRST_SENTENCE.to_owned(), + LOG_SECOND_SENTENCE.to_owned(), + ] + } + fn default_preview_first_line(&self, tab: &Tab) -> Vec<String> { match tab.path_content.selected() { Some(fileinfo) => { @@ -215,13 +244,11 @@ impl<'a> WinMain<'a> { let first_row = match tab.mode { Mode::Normal | Mode::Tree => self.normal_first_row(disk_space)?, Mode::Preview => match &tab.preview { - Preview::Text(text_content) => { - if matches!(text_content.kind, TextKind::HELP) { - Self::help_first_row() - } else { - self.default_preview_first_line(tab) - } - } + Preview::Text(text_content) => match text_content.kind { + TextKind::HELP => Self::help_first_row(), + TextKind::LOG => Self::log_first_row(), + _ => self.default_preview_first_line(tab), + }, _ => self.default_preview_first_line(tab), }, _ => match self.tab.previous_mode { @@ -376,6 +403,9 @@ impl<'a> WinMain<'a> { Preview::Text(text) => { impl_preview!(text, tab, length, canvas, line_number_width, window) } + Preview::Diff(text) => { + impl_preview!(text, tab, length, canvas, line_number_width, window) + } Preview::Empty => (), } @@ -396,10 +426,12 @@ impl<'a> Draw for WinSecondary<'a> { Mode::Navigate(Navigate::Shortcut) => self.destination(canvas, &self.tab.shortcut), Mode::Navigate(Navigate::Trash) => self.trash(canvas, &self.status.trash), Mode::Navigate(Navigate::Compress) => self.compress(canvas, &self.status.compression), + Mode::Navigate(Navigate::Bulk) => self.bulk(canvas, &self.status.bulk), Mode::Navigate(Navigate::EncryptedDrive) => { self.encrypted_devices(self.status, self.tab, canvas) } - Mode::Navigate(Navigate::Marks(_)) => self.marks(self.status, self.tab, canvas), + Mode::Navigate(Navigate::Marks(_)) => self.marks(self.status, canvas), + Mode::Navigate(Navigate::ShellMenu) => self.shell_menu(self.status, canvas), Mode::NeedConfirmation(confirmed_mode) => { self.confirmation(self.status, self.tab, confirmed_mode, canvas) } @@ -432,7 +464,7 @@ impl<'a> WinSecondary<'a> { fn create_first_row(&self, tab: &Tab) -> FmResult<Vec<String>> { let first_row = match tab.mode { Mode::NeedConfirmation(confirmed_action) => { - vec![format!("{confirmed_action} (y/n)")] + vec![format!("{confirmed_action}"), " (y/n)".to_owned()] } Mode::Navigate(Navigate::Marks(MarkAction::Jump)) => { vec!["Jump to...".to_owned()] @@ -443,12 +475,21 @@ impl<'a> WinSecondary<'a> { Mode::InputSimple(InputSimple::Password(password_kind, _encrypted_action)) => { vec![format!("{password_kind}"), tab.input.password()] } - Mode::InputCompleted(_) => { + Mode::InputCompleted(mode) => { let mut completion_strings = vec![format!("{}", &tab.mode), tab.input.string()]; if let Some(completion) = tab.completion.complete_input_string(&tab.input.string()) { completion_strings.push(completion.to_owned()) } + if let InputCompleted::Exec = mode { + let selected_path = &tab + .selected() + .ok_or_else(|| FmError::custom("create_first_row", "can't parse path"))? + .path; + let selected_path = format!(" {}", selected_path.display()); + + completion_strings.push(selected_path); + } completion_strings } _ => { @@ -511,8 +552,8 @@ impl<'a> WinSecondary<'a> { selectable: &impl SelectableContent<PathBuf>, ) -> FmResult<()> { canvas.print(0, 0, "Go to...")?; - for (row, path) in selectable.content().iter().enumerate() { - let mut attr = Attr::default(); + for (row, path, attr) in enumerated_colored_iter!(selectable) { + let mut attr = *attr; if row == selectable.index() { attr.effect |= Effect::REVERSE; } @@ -527,18 +568,37 @@ impl<'a> WinSecondary<'a> { Ok(()) } + fn bulk( + &self, + canvas: &mut dyn Canvas, + selectable: &impl SelectableContent<String>, + ) -> FmResult<()> { + canvas.print(0, 0, "Action...")?; + for (row, text, attr) in enumerated_colored_iter!(selectable) { + let mut attr = *attr; + if row == selectable.index() { + attr.effect |= Effect::REVERSE; + } + let _ = canvas.print_with_attr(row + ContentWindow::WINDOW_MARGIN_TOP, 4, text, attr); + } + Ok(()) + } + fn trash( &self, canvas: &mut dyn Canvas, selectable: &impl SelectableContent<TrashInfo>, ) -> FmResult<()> { - canvas.print(1, 0, "Restore the selected file")?; - for (row, trashinfo) in selectable.content().iter().enumerate() { - let mut attr = Attr::default(); + canvas.print( + 1, + 0, + "Enter: restore the selected file - x: delete permanently", + )?; + for (row, trashinfo, attr) in enumerated_colored_iter!(selectable) { + let mut attr = *attr; if row == selectable.index() { attr.effect |= Effect::REVERSE; } - let _ = canvas.print_with_attr( row + ContentWindow::WINDOW_MARGIN_TOP, 4, @@ -560,8 +620,8 @@ impl<'a> WinSecondary<'a> { "Archive and compress the flagged files. Pick a compression algorithm.", Self::ATTR_YELLOW, )?; - for (row, compression_method) in selectable.content().iter().enumerate() { - let mut attr = Attr::default(); + for (row, compression_method, attr) in enumerated_colored_iter!(selectable) { + let mut attr = *attr; if row == selectable.index() { attr.effect |= Effect::REVERSE; } @@ -576,16 +636,38 @@ impl<'a> WinSecondary<'a> { Ok(()) } - fn marks(&self, status: &Status, tab: &Tab, canvas: &mut dyn Canvas) -> FmResult<()> { + fn marks(&self, status: &Status, canvas: &mut dyn Canvas) -> FmResult<()> { canvas.print_with_attr(2, 1, "mark path", Self::ATTR_YELLOW)?; - for (i, line) in status.marks.as_strings().iter().enumerate() { - let row = calc_line_row(i, &tab.window) + 2; - let mut attr = Attr::default(); - if i == status.marks.index() { + for ((row, line), attr) in std::iter::zip( + status.marks.as_strings().iter().enumerate(), + MENU_COLORS.iter().cycle(), + ) { + let mut attr = *attr; + if row == status.marks.index() { attr.effect |= Effect::REVERSE; } - canvas.print_with_attr(row, 3, line, attr)?; + + canvas.print_with_attr(row + 4, 3, line, attr)?; + } + Ok(()) + } + + fn shell_menu(&self, status: &Status, canvas: &mut dyn Canvas) -> FmResult<()> { + canvas.print_with_attr(2, 1, "pick a command", Self::ATTR_YELLOW)?; + + let tab = status.selected_non_mut(); + for ((row, (command, _)), attr) in std::iter::zip( + status.shell_menu.content.iter().enumerate(), + MENU_COLORS.iter().cycle(), + ) { + let mut attr = *attr; + if row == status.shell_menu.index() { + attr.effect |= Effect::REVERSE; + } + let row = calc_line_row(row, &tab.window) + 2; + + canvas.print_with_attr(row, 3, command, attr)?; } Ok(()) } @@ -733,6 +815,13 @@ impl Display { Ok(self.term.present()?) } + pub fn force_clear(&mut self) -> FmResult<()> { + self.hide_cursor()?; + self.term.clear()?; + self.term.present()?; + Ok(()) + } + fn size_for_second_window(&self, tab: &Tab) -> FmResult<usize> { if tab.need_second_window() { Ok(self.height()? / 2) |