summaryrefslogtreecommitdiffstats
path: root/src/event/event_exec.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/event/event_exec.rs')
-rw-r--r--src/event/event_exec.rs584
1 files changed, 410 insertions, 174 deletions
diff --git a/src/event/event_exec.rs b/src/event/event_exec.rs
index ab4802b..454887b 100644
--- a/src/event/event_exec.rs
+++ b/src/event/event_exec.rs
@@ -5,6 +5,8 @@ use anyhow::{Context, Result};
use crate::app::Status;
use crate::app::Tab;
+use crate::common::filename_to_clipboard;
+use crate::common::filepath_to_clipboard;
use crate::common::LAZYGIT;
use crate::common::NCDU;
use crate::common::{is_program_in_path, open_in_current_neovim};
@@ -17,16 +19,22 @@ use crate::log_info;
use crate::log_line;
use crate::modes::help_string;
use crate::modes::lsblk_and_cryptsetup_installed;
+use crate::modes::open_tui_program;
+use crate::modes::Content;
+use crate::modes::ContentWindow;
use crate::modes::Display;
+use crate::modes::Edit;
use crate::modes::InputCompleted;
+use crate::modes::InputSimple;
use crate::modes::LeaveMode;
+use crate::modes::MarkAction;
use crate::modes::Mocp;
+use crate::modes::Navigate;
+use crate::modes::NeedConfirmation;
use crate::modes::Preview;
use crate::modes::RemovableDevices;
-use crate::modes::SelectableContent;
-use crate::modes::TuiApplications;
+use crate::modes::Selectable;
use crate::modes::MOCP;
-use crate::modes::{Edit, InputSimple, MarkAction, Navigate, NeedConfirmation};
/// Links events from tuikit to custom actions.
/// It mutates `Status` or its children `Tab`.
@@ -57,17 +65,22 @@ impl EventAction {
/// Leave current mode to normal mode.
/// Reset the inputs and completion, reset the window, exit the preview.
pub fn reset_mode(status: &mut Status) -> Result<()> {
- let tab = &mut status.tabs[status.index];
- if matches!(tab.display_mode, Display::Preview) {
- tab.set_display_mode(Display::Directory);
+ if !matches!(status.current_tab().edit_mode, Edit::Nothing) {
+ if status.reset_edit_mode()? {
+ status.tabs[status.index].refresh_view()?;
+ } else {
+ status.tabs[status.index].refresh_params()?;
+ }
+ } else if matches!(
+ status.current_tab().display_mode,
+ Display::Preview | Display::Flagged
+ ) {
+ status.tabs[status.index].set_display_mode(Display::Directory);
+ status.tabs[status.index].refresh_view()?;
}
status.menu.input.reset();
status.menu.completion.reset();
- if tab.reset_edit_mode() {
- tab.refresh_view()
- } else {
- tab.refresh_params()
- }
+ Ok(())
}
/// Toggle between a full display (aka ls -lah) or a simple mode (only the
@@ -89,9 +102,10 @@ impl EventAction {
pub fn toggle_preview_second(status: &mut Status) -> Result<()> {
status.display_settings.toggle_preview();
if status.display_settings.preview() {
- status.set_second_pane_for_preview()?;
+ status.update_second_pane_for_preview()?;
} else {
- status.tabs[1].reset_edit_mode();
+ status.set_edit_mode(1, Edit::Nothing)?;
+ status.tabs[1].display_mode = Display::Directory;
status.tabs[1].refresh_view()?;
}
Ok(())
@@ -99,14 +113,15 @@ impl EventAction {
/// Creates a tree in every mode but "Tree".
/// In display_mode tree it will exit this view.
- pub fn tree(tab: &mut Tab) -> Result<()> {
- tab.toggle_tree_mode()
+ pub fn tree(status: &mut Status) -> Result<()> {
+ status.current_tab_mut().toggle_tree_mode()?;
+ status.refresh_view()
}
/// Fold the current node of the tree.
/// Has no effect on "file" nodes.
pub fn tree_fold(tab: &mut Tab) -> Result<()> {
- tab.tree.toggle_fold();
+ tab.tree.toggle_fold(&tab.users);
Ok(())
}
@@ -114,7 +129,7 @@ impl EventAction {
/// Recursively explore the tree and unfold every node.
/// Reset the display.
pub fn tree_unfold_all(tab: &mut Tab) -> Result<()> {
- tab.tree.unfold_all();
+ tab.tree.unfold_all(&tab.users);
Ok(())
}
@@ -122,7 +137,22 @@ impl EventAction {
/// Recursively explore the tree and fold every node.
/// Reset the display.
pub fn tree_fold_all(tab: &mut Tab) -> Result<()> {
- tab.tree.fold_all();
+ tab.tree.fold_all(&tab.users);
+ Ok(())
+ }
+
+ pub fn display_flagged(status: &mut Status) -> Result<()> {
+ if matches!(status.current_tab().display_mode, Display::Flagged) {
+ status
+ .current_tab_mut()
+ .set_display_mode(Display::Directory);
+ } else {
+ status
+ .menu
+ .flagged
+ .set_height(status.internal_settings.term.term_size()?.1);
+ status.current_tab_mut().set_display_mode(Display::Flagged);
+ }
Ok(())
}
@@ -175,15 +205,13 @@ impl EventAction {
return Ok(());
}
if let Some(parent) = status.current_tab().directory.path.parent() {
- if sel_path == std::rc::Rc::from(parent) {
+ if sel_path == std::sync::Arc::from(parent) {
return Ok(());
}
}
let old_name = &selected.filename;
+ status.set_edit_mode(status.index, Edit::InputSimple(InputSimple::Rename))?;
status.menu.input.replace(old_name);
- status
- .current_tab_mut()
- .set_edit_mode(Edit::InputSimple(InputSimple::Rename));
Ok(())
}
@@ -204,13 +232,13 @@ impl EventAction {
}
fn set_copy_paste(status: &mut Status, copy_or_move: NeedConfirmation) -> Result<()> {
+ if matches!(status.current_tab().display_mode, Display::Flagged) {
+ return Ok(());
+ };
if status.menu.flagged.is_empty() {
return Ok(());
}
- status
- .current_tab_mut()
- .set_edit_mode(Edit::NeedConfirmation(copy_or_move));
- Ok(())
+ status.set_edit_mode(status.index, Edit::NeedConfirmation(copy_or_move))
}
/// Creates a symlink of every flagged file to the current directory.
@@ -238,10 +266,10 @@ impl EventAction {
if status.menu.flagged.is_empty() {
Self::toggle_flag(status)?;
}
- status
- .current_tab_mut()
- .set_edit_mode(Edit::NeedConfirmation(NeedConfirmation::Delete));
- Ok(())
+ status.set_edit_mode(
+ status.index,
+ Edit::NeedConfirmation(NeedConfirmation::Delete),
+ )
}
/// Change to CHMOD mode allowing to edit permissions of a file.
@@ -250,21 +278,34 @@ impl EventAction {
}
/// Enter the new dir mode.
- pub fn new_dir(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::InputSimple(InputSimple::Newdir));
- Ok(())
+ pub fn new_dir(status: &mut Status) -> Result<()> {
+ if matches!(
+ status.current_tab().display_mode,
+ Display::Directory | Display::Tree
+ ) {
+ status.set_edit_mode(status.index, Edit::InputSimple(InputSimple::Newdir))
+ } else {
+ Ok(())
+ }
}
/// Enter the new file mode.
- pub fn new_file(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::InputSimple(InputSimple::Newfile));
- Ok(())
+ pub fn new_file(status: &mut Status) -> Result<()> {
+ if matches!(
+ status.current_tab().display_mode,
+ Display::Directory | Display::Tree
+ ) {
+ status.set_edit_mode(status.index, Edit::InputSimple(InputSimple::Newfile))
+ } else {
+ Ok(())
+ }
}
fn enter_file(status: &mut Status) -> Result<()> {
match status.current_tab_mut().display_mode {
Display::Directory => Self::normal_enter_file(status),
Display::Tree => Self::tree_enter_file(status),
+ Display::Flagged => Self::jump_fuzzy(status),
_ => Ok(()),
}
}
@@ -314,34 +355,61 @@ impl EventAction {
}
}
+ pub fn open_all(status: &mut Status) -> Result<()> {
+ status.open_flagged_files()
+ }
+
/// Enter the execute mode. Most commands must be executed to allow for
/// a confirmation.
- pub fn exec(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::InputCompleted(InputCompleted::Exec));
- Ok(())
+ pub fn exec(status: &mut Status) -> Result<()> {
+ if status.menu.flagged.is_empty() {
+ status
+ .menu
+ .flagged
+ .push(status.current_tab().current_file()?.path.to_path_buf());
+ }
+ status.set_edit_mode(status.index, Edit::InputCompleted(InputCompleted::Exec))
}
/// Enter the sort mode, allowing the user to select a sort method.
- pub fn sort(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::InputSimple(InputSimple::Sort));
+ pub fn sort(status: &mut Status) -> Result<()> {
+ status.set_height_for_edit_mode(status.index, Edit::Nothing)?;
+ status.tabs[status.index].edit_mode = Edit::Nothing;
+ let len = status.menu.len(Edit::Nothing);
+ let height = status.second_window_height()?;
+ status.menu.window = ContentWindow::new(len, height);
+ status.tabs[status.index].edit_mode = Edit::InputSimple(InputSimple::Sort);
Ok(())
}
/// Enter the filter mode, where you can filter.
/// See `crate::modes::Filter` for more details.
- pub fn filter(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::InputSimple(InputSimple::Filter));
+ pub fn filter(status: &mut Status) -> Result<()> {
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::InputSimple(InputSimple::Filter)
+ ) {
+ status.reset_edit_mode()?;
+ } else if matches!(
+ status.current_tab().display_mode,
+ Display::Tree | Display::Directory
+ ) {
+ status.set_edit_mode(status.index, Edit::InputSimple(InputSimple::Filter))?;
+ }
Ok(())
}
/// Enter JUMP mode, allowing to jump to any flagged file.
/// Does nothing if no file is flagged.
pub fn jump(status: &mut Status) -> Result<()> {
- if !status.menu.flagged.is_empty() {
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::Jump)
+ ) {
+ status.reset_edit_mode()?;
+ } else if !status.menu.flagged.is_empty() {
status.menu.flagged.index = 0;
- status
- .current_tab_mut()
- .set_edit_mode(Edit::Navigate(Navigate::Jump))
+ status.set_edit_mode(status.index, Edit::Navigate(Navigate::Jump))?;
}
Ok(())
}
@@ -350,29 +418,36 @@ impl EventAction {
/// can edit the selected filenames.
/// Once the temp file is saved, those file names are changed.
pub fn bulk(status: &mut Status) -> Result<()> {
- status.menu.init_bulk();
- status
- .current_tab_mut()
- .set_edit_mode(Edit::Navigate(Navigate::Bulk));
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::BulkMenu)
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ status.set_edit_mode(status.index, Edit::Navigate(Navigate::BulkMenu))?;
+ }
Ok(())
}
/// Enter the search mode.
/// Matching items are displayed as you type them.
- pub fn search(tab: &mut Tab) -> Result<()> {
+ pub fn search(status: &mut Status) -> Result<()> {
+ let tab = status.current_tab_mut();
tab.searched = None;
- tab.set_edit_mode(Edit::InputCompleted(InputCompleted::Search));
- Ok(())
+ status.set_edit_mode(status.index, Edit::InputCompleted(InputCompleted::Search))
}
/// Enter the regex mode.
/// Every file matching the typed regex will be flagged.
- pub fn regex_match(tab: &mut Tab) -> Result<()> {
- if !matches!(tab.edit_mode, Edit::Nothing) {
- return Ok(());
+ pub fn regex_match(status: &mut Status) -> Result<()> {
+ if matches!(
+ status.current_tab().display_mode,
+ Display::Tree | Display::Directory
+ ) {
+ status.set_edit_mode(status.index, Edit::InputSimple(InputSimple::RegexMatch))
+ } else {
+ Ok(())
}
- tab.set_edit_mode(Edit::InputSimple(InputSimple::RegexMatch));
- Ok(())
}
/// Display the help which can be navigated and displays the configrable
@@ -388,7 +463,9 @@ impl EventAction {
/// Display the last actions impacting the file tree
pub fn log(tab: &mut Tab) -> Result<()> {
- let log = read_log()?;
+ let Ok(log) = read_log() else {
+ return Ok(());
+ };
tab.set_display_mode(Display::Preview);
tab.preview = Preview::log(log);
tab.window.reset(tab.preview.len());
@@ -396,12 +473,17 @@ impl EventAction {
Ok(())
}
- /// Enter the goto mode where an user can type a path to jump to.
- pub fn goto(status: &mut Status) -> Result<()> {
- status
- .current_tab_mut()
- .set_edit_mode(Edit::InputCompleted(InputCompleted::Goto));
- status.menu.completion.reset();
+ /// Enter the cd mode where an user can type a path to jump to.
+ pub fn cd(status: &mut Status) -> Result<()> {
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::InputCompleted(InputCompleted::Cd)
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ status.set_edit_mode(status.index, Edit::InputCompleted(InputCompleted::Cd))?;
+ status.menu.completion.reset();
+ }
Ok(())
}
@@ -415,36 +497,69 @@ impl EventAction {
Ok(())
}
- pub fn shell_command(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::InputSimple(InputSimple::Shell));
- Ok(())
+ /// Enter the shell input command mode. The user can type a command which
+ /// will be parsed and run.
+ pub fn shell_command(status: &mut Status) -> Result<()> {
+ status.set_edit_mode(status.index, Edit::InputSimple(InputSimple::Shell))
}
/// Enter the shell menu mode. You can pick a TUI application to be run
- pub fn tui_menu(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::Navigate(Navigate::TuiApplication));
+ pub fn tui_menu(status: &mut Status) -> Result<()> {
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::TuiApplication)
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ status.set_edit_mode(status.index, Edit::Navigate(Navigate::TuiApplication))?;
+ }
Ok(())
}
/// Enter the cli info mode. You can pick a Text application to be
/// displayed/
pub fn cli_menu(status: &mut Status) -> Result<()> {
- status
- .current_tab_mut()
- .set_edit_mode(Edit::Navigate(Navigate::CliApplication));
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::CliApplication)
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ status.set_edit_mode(status.index, Edit::Navigate(Navigate::CliApplication))?;
+ }
Ok(())
}
/// Enter the history mode, allowing to navigate to previously visited
/// directory.
- pub fn history(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::Navigate(Navigate::History));
+ pub fn history(status: &mut Status) -> Result<()> {
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::History)
+ ) {
+ status.reset_edit_mode()?;
+ } else if matches!(
+ status.current_tab().display_mode,
+ Display::Directory | Display::Tree
+ ) {
+ status.set_edit_mode(status.index, Edit::Navigate(Navigate::History))?;
+ }
Ok(())
}
/// Enter Marks new mode, allowing to bind a char to a path.
- pub fn marks_new(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::Navigate(Navigate::Marks(MarkAction::New)));
+ pub fn marks_new(status: &mut Status) -> Result<()> {
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::Marks(MarkAction::New))
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ status.set_edit_mode(
+ status.index,
+ Edit::Navigate(Navigate::Marks(MarkAction::New)),
+ )?;
+ }
Ok(())
}
@@ -453,9 +568,17 @@ impl EventAction {
if status.menu.marks.is_empty() {
return Ok(());
}
- status
- .current_tab_mut()
- .set_edit_mode(Edit::Navigate(Navigate::Marks(MarkAction::Jump)));
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::Marks(MarkAction::Jump))
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ status.set_edit_mode(
+ status.index,
+ Edit::Navigate(Navigate::Marks(MarkAction::Jump)),
+ )?;
+ }
Ok(())
}
@@ -463,13 +586,19 @@ impl EventAction {
/// Basic folders (/, /dev... $HOME) and mount points (even impossible to
/// visit ones) are proposed.
pub fn shortcut(status: &mut Status) -> Result<()> {
- std::env::set_current_dir(status.current_tab().directory_of_selected()?)?;
- status.menu.shortcut.update_git_root();
- status
- .current_tab_mut()
- .set_edit_mode(Edit::Navigate(Navigate::Shortcut));
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::Shortcut)
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ std::env::set_current_dir(status.current_tab().directory_of_selected()?)?;
+ status.menu.shortcut.update_git_root();
+ status.set_edit_mode(status.index, Edit::Navigate(Navigate::Shortcut))?;
+ }
Ok(())
}
+
/// Send a signal to parent NVIM process, picking files.
/// If there's no flagged file, it picks the selected one.
/// otherwise, flagged files are picked.
@@ -497,22 +626,24 @@ impl EventAction {
Ok(())
}
- pub fn set_nvim_server(tab: &mut Tab) -> Result<()> {
- tab.set_edit_mode(Edit::InputSimple(InputSimple::SetNvimAddr));
- Ok(())
+ /// Enter the set neovim RPC address mode where the user can type
+ /// the RPC address himself
+ pub fn set_nvim_server(status: &mut Status) -> Result<()> {
+ status.set_edit_mode(status.index, Edit::InputSimple(InputSimple::SetNvimAddr))
}
/// Move back in history to the last visited directory.
- pub fn back(tab: &mut Tab) -> Result<()> {
- tab.back()
+ pub fn back(status: &mut Status) -> Result<()> {
+ status.current_tab_mut().back()?;
+ status.update_second_pane_for_preview()
}
/// Move to $HOME aka ~.
pub fn home(status: &mut Status) -> Result<()> {
let home_cow = shellexpand::tilde("~");
let home: &str = home_cow.borrow();
- let path = std::fs::canonicalize(home)?;
- status.current_tab_mut().cd(&path)?;
+ let home_path = path::Path::new(home);
+ status.current_tab_mut().cd(home_path)?;
status.update_second_pane_for_preview()
}
@@ -527,6 +658,18 @@ impl EventAction {
status.update_second_pane_for_preview()
}
+ pub fn jump_fuzzy(status: &mut Status) -> Result<()> {
+ let Some(path) = status.menu.flagged.selected() else {
+ return Ok(());
+ };
+ let path = path.to_owned();
+ let tab = status.current_tab_mut();
+ tab.set_display_mode(Display::Directory);
+ tab.refresh_view()?;
+ tab.jump(path)?;
+ status.update_second_pane_for_preview()
+ }
+
pub fn search_next(status: &mut Status) -> Result<()> {
let tab = status.current_tab_mut();
let Some(searched) = tab.searched.clone() else {
@@ -538,8 +681,10 @@ impl EventAction {
Display::Preview => {
return Ok(());
}
+ Display::Flagged => todo!("search next"),
}
- status.set_second_pane_for_preview()?;
+ status.refresh_status()?;
+ status.update_second_pane_for_preview()?;
Ok(())
}
@@ -549,29 +694,35 @@ impl EventAction {
let tab = status.current_tab_mut();
match tab.edit_mode {
Edit::Nothing => Self::move_display_up(status)?,
- Edit::Navigate(Navigate::Jump) => status.menu.flagged.prev(),
Edit::Navigate(Navigate::History) => tab.history.prev(),
- Edit::Navigate(Navigate::Trash) => status.menu.trash.prev(),
- Edit::Navigate(Navigate::Shortcut) => status.menu.shortcut.prev(),
- Edit::Navigate(Navigate::Marks(_)) => status.menu.marks.prev(),
- Edit::Navigate(Navigate::Compress) => status.menu.compression.prev(),
- Edit::Navigate(Navigate::Context) => status.menu.context.prev(),
- Edit::Navigate(Navigate::Bulk) => status.menu.bulk_prev(),
- Edit::Navigate(Navigate::TuiApplication) => status.menu.tui_applications.prev(),
- Edit::Navigate(Navigate::CliApplication) => status.menu.cli_applications.prev(),
- Edit::Navigate(Navigate::EncryptedDrive) => status.menu.encrypted_devices.prev(),
- Edit::InputCompleted(_) => status.menu.completion.prev(),
+ Edit::Navigate(navigate) => status.menu.prev(navigate),
+ Edit::InputCompleted(input_completed) => status.menu.completion_prev(input_completed),
_ => (),
};
status.update_second_pane_for_preview()
}
+ pub fn next_sibling(tab: &mut Tab) -> Result<()> {
+ if matches!(tab.display_mode, Display::Tree) {
+ tab.tree_next_sibling();
+ }
+ Ok(())
+ }
+
+ pub fn previous_sibling(tab: &mut Tab) -> Result<()> {
+ if matches!(tab.display_mode, Display::Tree) {
+ tab.tree_prev_sibling();
+ }
+ Ok(())
+ }
+
fn move_display_up(status: &mut Status) -> Result<()> {
let tab = status.current_tab_mut();
match tab.display_mode {
Display::Directory => tab.normal_up_one_row(),
Display::Preview => tab.preview_page_up(),
Display::Tree => tab.tree_select_prev()?,
+ Display::Flagged => status.menu.flagged.select_prev(),
}
Ok(())
}
@@ -582,6 +733,7 @@ impl EventAction {
Display::Directory => tab.normal_down_one_row(),
Display::Preview => tab.preview_page_down(),
Display::Tree => tab.tree_select_next()?,
+ Display::Flagged => status.menu.flagged.select_next(),
}
Ok(())
}
@@ -590,18 +742,9 @@ impl EventAction {
pub fn move_down(status: &mut Status) -> Result<()> {
match status.current_tab_mut().edit_mode {
Edit::Nothing => Self::move_display_down(status)?,
- Edit::Navigate(Navigate::Jump) => status.menu.flagged.next(),
Edit::Navigate(Navigate::History) => status.current_tab_mut().history.next(),
- Edit::Navigate(Navigate::Trash) => status.menu.trash.next(),
- Edit::Navigate(Navigate::Shortcut) => status.menu.shortcut.next(),
- Edit::Navigate(Navigate::Marks(_)) => status.menu.marks.next(),
- Edit::Navigate(Navigate::Compress) => status.menu.compression.next(),
- Edit::Navigate(Navigate::Context) => status.menu.context.next(),
- Edit::Navigate(Navigate::Bulk) => status.menu.bulk_next(),
- Edit::Navigate(Navigate::TuiApplication) => status.menu.tui_applications.next(),
- Edit::Navigate(Navigate::CliApplication) => status.menu.cli_applications.next(),
- Edit::Navigate(Navigate::EncryptedDrive) => status.menu.encrypted_devices.next(),
- Edit::InputCompleted(_) => status.menu.completion.next(),
+ Edit::Navigate(navigate) => status.menu.next(navigate),
+ Edit::InputCompleted(input_completed) => status.menu.completion_next(input_completed),
_ => (),
};
status.update_second_pane_for_preview()
@@ -642,7 +785,7 @@ impl EventAction {
pub fn left_click(status: &mut Status, binds: &Bindings, row: u16, col: u16) -> Result<()> {
EventAction::select_pane(status, col)?;
- EventAction::click_file(status, row, col, binds)
+ EventAction::click(status, row, col, binds)
}
pub fn wheel_up(status: &mut Status, col: u16, nb_of_scrolls: u16) -> Result<()> {
@@ -663,7 +806,7 @@ impl EventAction {
/// A right click opens a file or a directory.
pub fn double_click(status: &mut Status, row: u16, col: u16, binds: &Bindings) -> Result<()> {
- if let Ok(()) = EventAction::click_file(status, row, col, binds) {
+ if let Ok(()) = EventAction::click(status, row, col, binds) {
EventAction::enter_file(status)?;
};
Ok(())
@@ -672,6 +815,7 @@ impl EventAction {
/// Delete a char to the left in modes allowing edition.
pub fn backspace(status: &mut Status) -> Result<()> {
match status.current_tab().edit_mode {
+ Edit::Navigate(Navigate::Marks(MarkAction::New)) => status.menu.marks.remove_selected(),
Edit::InputSimple(_) | Edit::InputCompleted(_) => {
status.menu.input.delete_char_left();
Ok(())
@@ -700,6 +844,7 @@ impl EventAction {
Display::Directory => tab.normal_go_top(),
Display::Preview => tab.preview_go_top(),
Display::Tree => tab.tree_go_to_root()?,
+ Display::Flagged => status.menu.flagged.select_first(),
};
}
_ => status.menu.input.cursor_start(),
@@ -716,6 +861,7 @@ impl EventAction {
Display::Directory => tab.normal_go_bottom(),
Display::Preview => tab.preview_go_bottom(),
Display::Tree => tab.tree_go_to_bottom_leaf()?,
+ Display::Flagged => status.menu.flagged.select_last(),
};
}
_ => status.menu.input.cursor_end(),
@@ -726,6 +872,21 @@ impl EventAction {
/// Move up 10 lines in normal mode and preview.
pub fn page_up(status: &mut Status) -> Result<()> {
let tab = status.current_tab_mut();
+ match tab.edit_mode {
+ Edit::Nothing => Self::file_page_up(status)?,
+ Edit::Navigate(navigate) => status.menu.page_up(navigate),
+ Edit::InputCompleted(input_completed) => {
+ for _ in 0..10 {
+ status.menu.completion_prev(input_completed)
+ }
+ }
+ _ => (),
+ };
+ Ok(())
+ }
+
+ fn file_page_up(status: &mut Status) -> Result<()> {
+ let tab = status.current_tab_mut();
match tab.display_mode {
Display::Directory => {
tab.normal_page_up();
@@ -736,6 +897,7 @@ impl EventAction {
tab.tree_page_up();
status.update_second_pane_for_preview()?;
}
+ Display::Flagged => status.menu.flagged.page_up(),
};
Ok(())
}
@@ -743,6 +905,21 @@ impl EventAction {
/// Move down 10 lines in normal & preview mode.
pub fn page_down(status: &mut Status) -> Result<()> {
let tab = status.current_tab_mut();
+ match tab.edit_mode {
+ Edit::Nothing => Self::file_page_down(status)?,
+ Edit::Navigate(navigate) => status.menu.page_down(navigate),
+ Edit::InputCompleted(input_completed) => {
+ for _ in 0..10 {
+ status.menu.completion_next(input_completed)
+ }
+ }
+ _ => (),
+ };
+ Ok(())
+ }
+
+ fn file_page_down(status: &mut Status) -> Result<()> {
+ let tab = status.current_tab_mut();
match tab.display_mode {
Display::Directory => {
tab.normal_page_down();
@@ -750,9 +927,10 @@ impl EventAction {
}
Display::Preview => tab.preview_page_down(),
Display::Tree => {
- tab.tree_page_down()?;
+ tab.tree_page_down();
status.update_second_pane_for_preview()?;
}
+ Display::Flagged => status.menu.flagged.page_down(),
};
Ok(())
}
@@ -774,10 +952,7 @@ impl EventAction {
/// insert a completion in modes allowing completion.
pub fn tab(status: &mut Status) -> Result<()> {
match status.current_tab_mut().edit_mode {
- Edit::InputCompleted(_) => status
- .menu
- .input
- .replace(status.menu.completion.current_proposition()),
+ Edit::InputCompleted(_) => status.menu.completion_tab(),
Edit::Nothing => status.next(),
_ => (),
};
@@ -811,17 +986,41 @@ impl EventAction {
}
/// Copy the filename of the selected file in normal mode.
- pub fn copy_filename(tab: &mut Tab) -> Result<()> {
- if let Display::Directory | Display::Tree = tab.display_mode {
- tab.filename_to_clipboard();
+ pub fn copy_filename(status: &Status) -> Result<()> {
+ match status.current_tab().display_mode {
+ Display::Tree | Display::Directory => {
+ let Ok(file_info) = status.current_tab().current_file() else {
+ return Ok(());
+ };
+ filename_to_clipboard(&file_info.path);
+ }
+ Display::Flagged => {
+ let Some(path) = status.menu.flagged.selected() else {
+ return Ok(());
+ };
+ filename_to_clipboard(path);
+ }
+ _ => return Ok(()),
}
Ok(())
}
/// Copy the filepath of the selected file in normal mode.
- pub fn copy_filepath(tab: &mut Tab) -> Result<()> {
- if let Display::Directory | Display::Tree = tab.display_mode {
- tab.filepath_to_clipboard();
+ pub fn copy_filepath(status: &Status) -> Result<()> {
+ match status.current_tab().display_mode {
+ Display::Tree | Display::Directory => {
+ let Ok(file_info) = status.current_tab().current_file() else {
+ return Ok(());
+ };
+ filepath_to_clipboard(&file_info.path);
+ }
+ Display::Flagged => {
+ let Some(path) = status.menu.flagged.selected() else {
+ return Ok(());
+ };
+ filepath_to_clipboard(path);
+ }
+ _ => return Ok(()),
}
Ok(())
}
@@ -839,7 +1038,7 @@ impl EventAction {
status.menu.trash.update()?;
for flagged in status.menu.flagged.content.iter() {
- status.menu.trash.trash(flagged)?;
+ let _ = status.menu.trash.trash(flagged);
}
status.menu.flagged.clear();
status.current_tab_mut().refresh_view()?;
@@ -849,10 +1048,18 @@ impl EventAction {
/// Ask the user if he wants to empty the trash.
/// It requires a confimation before doing anything
pub fn trash_empty(status: &mut Status) -> Result<()> {
- status.menu.trash.update()?;
- status
- .current_tab_mut()
- .set_edit_mode(Edit::NeedConfirmation(NeedConfirmation::EmptyTrash));
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::NeedConfirmation(NeedConfirmation::EmptyTrash)
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ status.menu.trash.update()?;
+ status.set_edit_mode(
+ status.index,
+ Edit::NeedConfirmation(NeedConfirmation::EmptyTrash),
+ )?;
+ }
Ok(())
}
@@ -861,38 +1068,54 @@ impl EventAction {
/// Each item can be restored or deleted.
/// Each opening refresh the trash content.
pub fn trash_open(status: &mut Status) -> Result<()> {
- status.menu.trash.update()?;
- status
- .current_tab_mut()
- .set_edit_mode(Edit::Navigate(Navigate::Trash));
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::Trash)
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ status.menu.trash.update()?;
+ status.set_edit_mode(status.index, Edit::Navigate(Navigate::Trash))?;
+ }
Ok(())
}
/// Enter the encrypted device menu, allowing the user to mount/umount
/// a luks encrypted device.
pub fn encrypted_drive(status: &mut Status) -> Result<()> {
- if !lsblk_and_cryptsetup_installed() {
- log_line!("lsblk and cryptsetup must be installed.");
- return Ok(());
- }
- if status.menu.encrypted_devices.is_empty() {
- status.menu.encrypted_devices.update()?;
+ if matches!(
+ status.current_tab().edit_mode,
+ Edit::Navigate(Navigate::EncryptedDrive)
+ ) {
+ status.reset_edit_mode()?;
+ } else {
+ if !lsblk_and_cryptsetup_installed() {
+ log_line!("lsblk and cryptsetup must be installed.");
+ return Ok(());
+ }
+ if status.menu.encrypted_devices.is_empty() {
+ status.menu.encrypted_devices.update()?;
+ }
+ status.set_edit_mode(status.index, Edit::Navigate(Navigate