summaryrefslogtreecommitdiffstats
path: root/src/event_exec.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/event_exec.rs')
-rw-r--r--src/event_exec.rs720
1 files changed, 371 insertions, 349 deletions
diff --git a/src/event_exec.rs b/src/event_exec.rs
index 34763d8..47609ed 100644
--- a/src/event_exec.rs
+++ b/src/event_exec.rs
@@ -4,6 +4,7 @@ use std::fs;
use std::path;
use std::str::FromStr;
+use anyhow::{anyhow, Context, Result};
use copypasta::{ClipboardContext, ClipboardProvider};
use log::info;
use sysinfo::SystemExt;
@@ -11,28 +12,25 @@ use sysinfo::SystemExt;
use crate::action_map::ActionMap;
use crate::completion::InputCompleted;
use crate::config::Colors;
-use crate::constant_strings_paths::CONFIG_PATH;
-use crate::constant_strings_paths::DEFAULT_DRAGNDROP;
-use crate::constant_strings_paths::NVIM_RPC_SENDER;
+use crate::constant_strings_paths::{CONFIG_PATH, DEFAULT_DRAGNDROP};
use crate::content_window::RESERVED_ROWS;
use crate::copy_move::CopyMove;
-use crate::cryptsetup::EncryptedAction;
-use crate::cryptsetup::PasswordKind;
+use crate::cryptsetup::BlockDeviceAction;
use crate::fileinfo::FileKind;
use crate::filter::FilterKind;
-use crate::fm_error::{FmError, FmResult};
+use crate::iso::IsoMounter;
use crate::log::read_log;
use crate::mocp::Mocp;
-use crate::mode::Navigate;
-use crate::mode::{InputSimple, MarkAction, Mode, NeedConfirmation};
-use crate::opener::execute_in_child;
-use crate::opener::execute_in_child_without_output_with_path;
+use crate::mode::{InputSimple, MarkAction, Mode, Navigate, NeedConfirmation};
+use crate::mount_help::MountHelper;
+use crate::nvim::nvim;
+use crate::opener::{execute_in_child, execute_in_child_without_output_with_path, InternalVariant};
+use crate::password::{PasswordKind, PasswordUsage};
use crate::preview::Preview;
use crate::selectable_content::SelectableContent;
use crate::status::Status;
use crate::tab::Tab;
-use crate::utils::disk_used_by_path;
-use crate::utils::is_program_in_path;
+use crate::utils::{current_username, disk_used_by_path, filename_from_path};
/// Every kind of mutation of the application is defined here.
/// It mutates `Status` or its children `Tab`.
@@ -40,7 +38,7 @@ pub struct EventExec {}
impl EventExec {
/// Reset the selected tab view to the default.
- pub fn refresh_status(status: &mut Status, colors: &Colors) -> FmResult<()> {
+ pub fn refresh_status(status: &mut Status, colors: &Colors) -> Result<()> {
status.force_clear();
status.refresh_users()?;
status.selected().refresh_view()?;
@@ -54,12 +52,7 @@ impl EventExec {
/// isn't sufficiant to display enough information.
/// We also need to know the new height of the terminal to start scrolling
/// up or down.
- pub fn resize(
- status: &mut Status,
- width: usize,
- height: usize,
- colors: &Colors,
- ) -> FmResult<()> {
+ pub fn resize(status: &mut Status, width: usize, height: usize, colors: &Colors) -> Result<()> {
status.set_dual_pane_if_wide_enough(width)?;
status.selected().set_height(height);
Self::refresh_status(status, colors)?;
@@ -67,13 +60,13 @@ impl EventExec {
}
/// Remove every flag on files in this directory and others.
- pub fn event_clear_flags(status: &mut Status) -> FmResult<()> {
+ pub fn event_clear_flags(status: &mut Status) -> Result<()> {
status.flagged.clear();
Ok(())
}
/// Flag all files in the current directory.
- pub fn event_flag_all(status: &mut Status) -> FmResult<()> {
+ pub fn event_flag_all(status: &mut Status) -> Result<()> {
status.tabs[status.index]
.path_content
.content
@@ -86,7 +79,7 @@ impl EventExec {
/// Reverse every flag in _current_ directory. Flagged files in other
/// directory aren't affected.
- pub fn event_reverse_flags(status: &mut Status) -> FmResult<()> {
+ pub fn event_reverse_flags(status: &mut Status) -> Result<()> {
status.tabs[status.index]
.path_content
.content
@@ -96,7 +89,7 @@ impl EventExec {
}
/// Toggle a single flag and move down one row.
- pub fn event_toggle_flag(status: &mut Status) -> FmResult<()> {
+ pub fn event_toggle_flag(status: &mut Status) -> Result<()> {
let tab = status.selected_non_mut();
match tab.mode {
@@ -115,18 +108,8 @@ impl EventExec {
Ok(())
}
- /// Move to the next file in the jump list.
- pub fn event_jumplist_next(status: &mut Status) {
- status.flagged.next()
- }
-
- /// Move to the previous file in the jump list.
- pub fn event_jumplist_prev(status: &mut Status) {
- status.flagged.prev()
- }
-
/// Change to CHMOD mode allowing to edit permissions of a file.
- pub fn event_chmod(status: &mut Status) -> FmResult<()> {
+ pub fn event_chmod(status: &mut Status) -> Result<()> {
if status.selected().path_content.is_empty() {
return Ok(());
}
@@ -143,7 +126,7 @@ impl EventExec {
/// Enter JUMP mode, allowing to jump to any flagged file.
/// Does nothing if no file is flagged.
- pub fn event_jump(status: &mut Status) -> FmResult<()> {
+ pub fn event_jump(status: &mut Status) -> Result<()> {
if !status.flagged.is_empty() {
status.flagged.index = 0;
status.selected().set_mode(Mode::Navigate(Navigate::Jump))
@@ -152,13 +135,13 @@ impl EventExec {
}
/// Enter Marks new mode, allowing to bind a char to a path.
- pub fn event_marks_new(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_marks_new(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::Navigate(Navigate::Marks(MarkAction::New)));
Ok(())
}
/// Enter Marks jump mode, allowing to jump to a marked file.
- pub fn event_marks_jump(status: &mut Status) -> FmResult<()> {
+ pub fn event_marks_jump(status: &mut Status) -> Result<()> {
if status.marks.is_empty() {
return Ok(());
}
@@ -169,7 +152,7 @@ impl EventExec {
}
/// Jump to the current mark.
- pub fn exec_marks_jump_selected(status: &mut Status) -> FmResult<()> {
+ pub fn exec_marks_jump(status: &mut Status) -> Result<()> {
let marks = status.marks.clone();
let tab = status.selected();
if let Some((_, path)) = marks.selected() {
@@ -184,7 +167,7 @@ impl EventExec {
/// Update the selected mark with the current path.
/// Doesn't change its char.
/// If it doesn't fail, a new pair will be set with (oldchar, new path).
- pub fn exec_marks_update_selected(status: &mut Status) -> FmResult<()> {
+ pub fn exec_marks_update(status: &mut Status) -> Result<()> {
let marks = status.marks.clone();
let len = status.selected_non_mut().path_content.content.len();
if let Some((ch, _)) = marks.selected() {
@@ -198,7 +181,7 @@ impl EventExec {
}
/// Execute a new mark, saving it to a config file for futher use.
- pub fn exec_marks_new(status: &mut Status, c: char, colors: &Colors) -> FmResult<()> {
+ pub fn exec_marks_new(status: &mut Status, c: char, colors: &Colors) -> Result<()> {
let path = status.selected().path_content.path.clone();
status.marks.new_mark(c, path)?;
Self::event_normal(status.selected())?;
@@ -208,9 +191,10 @@ impl EventExec {
/// Execute a jump to a mark, moving to a valid path.
/// If the saved path is invalid, it does nothing but reset the view.
- pub fn exec_marks_jump(status: &mut Status, c: char, colors: &Colors) -> FmResult<()> {
+ pub fn exec_marks_jump_char(status: &mut Status, c: char, colors: &Colors) -> Result<()> {
if let Some(path) = status.marks.get(c) {
- status.selected().set_pathcontent(&path)?
+ status.selected().set_pathcontent(&path)?;
+ status.selected().history.push(&path);
}
Self::event_normal(status.selected())?;
status.selected().reset_mode();
@@ -218,12 +202,12 @@ impl EventExec {
}
/// Creates a symlink of every flagged file to the current directory.
- pub fn event_symlink(status: &mut Status) -> FmResult<()> {
+ pub fn event_symlink(status: &mut Status) -> Result<()> {
for original_file in status.flagged.content.iter() {
let filename = original_file
.as_path()
.file_name()
- .ok_or_else(|| FmError::custom("event symlink", "File not found"))?;
+ .context("event symlink: File not found")?;
let link = status
.selected_non_mut()
.directory_of_selected()?
@@ -237,51 +221,43 @@ impl EventExec {
/// Enter bulkrename mode, opening a random temp file where the user
/// can edit the selected filenames.
/// Once the temp file is saved, those file names are changed.
- pub fn event_bulk(status: &mut Status) -> FmResult<()> {
+ pub fn event_bulk(status: &mut Status) -> Result<()> {
status.selected().set_mode(Mode::Navigate(Navigate::Bulk));
Ok(())
}
- pub fn event_bulk_prev(status: &mut Status) {
- status.bulk.prev()
- }
-
- pub fn event_bulk_next(status: &mut Status) {
- status.bulk.next()
- }
-
- pub fn event_shell_menu_prev(status: &mut Status) {
- info!("shell menu prev");
- status.shell_menu.prev()
- }
-
- pub fn event_shell_menu_next(status: &mut Status) {
- info!("shell menu next");
- status.shell_menu.next()
- }
-
- pub fn exec_bulk(status: &mut Status) -> FmResult<()> {
+ pub fn exec_bulk(status: &mut Status) -> Result<()> {
status.bulk.execute_bulk(status)
}
- pub fn exec_shellmenu(status: &mut Status) -> FmResult<()> {
+ pub fn exec_shellmenu(status: &mut Status) -> Result<()> {
status.shell_menu.execute(status)
}
+ pub fn exec_cli_info(status: &mut Status) -> Result<()> {
+ let output = status.cli_info.execute()?;
+ info!("output\n{output}");
+ status.selected().set_mode(Mode::Preview);
+ let preview = Preview::cli_info(&output);
+ status.selected().window.reset(preview.len());
+ status.selected().preview = preview;
+ Ok(())
+ }
+
/// Copy the flagged file to current directory.
/// A progress bar is displayed and a notification is sent once it's done.
- pub fn exec_copy_paste(status: &mut Status) -> FmResult<()> {
+ pub fn exec_copy_paste(status: &mut Status) -> Result<()> {
status.cut_or_copy_flagged_files(CopyMove::Copy)
}
/// Move the flagged file to current directory.
/// A progress bar is displayed and a notification is sent once it's done.
- pub fn exec_cut_paste(status: &mut Status) -> FmResult<()> {
+ pub fn exec_cut_paste(status: &mut Status) -> Result<()> {
status.cut_or_copy_flagged_files(CopyMove::Move)
}
/// Recursively delete all flagged files.
- pub fn exec_delete_files(status: &mut Status, colors: &Colors) -> FmResult<()> {
+ pub fn exec_delete_files(status: &mut Status, colors: &Colors) -> Result<()> {
for pathbuf in status.flagged.content.iter() {
if pathbuf.is_dir() {
std::fs::remove_dir_all(pathbuf)?;
@@ -299,7 +275,7 @@ impl EventExec {
/// the file.
/// Nothing is done if the user typed nothing or an invalid permission like
/// 955.
- pub fn exec_chmod(status: &mut Status) -> FmResult<()> {
+ pub fn exec_chmod(status: &mut Status) -> Result<()> {
if status.selected().input.is_empty() {
return Ok(());
}
@@ -315,7 +291,7 @@ impl EventExec {
status.reset_tabs_view()
}
- pub fn exec_set_neovim_address(status: &mut Status) -> FmResult<()> {
+ pub fn exec_set_nvim_addr(status: &mut Status) -> Result<()> {
status.nvim_server = status.selected_non_mut().input.string();
status.selected().reset_mode();
Ok(())
@@ -324,22 +300,16 @@ impl EventExec {
/// Execute a jump to the selected flagged file.
/// If the user selected a directory, we jump inside it.
/// Otherwise, we jump to the parent and select the file.
- pub fn exec_jump(status: &mut Status) -> FmResult<()> {
+ pub fn exec_jump(status: &mut Status) -> Result<()> {
let Some(jump_target) = status.flagged.selected() else { return Ok(()) };
let jump_target = jump_target.to_owned();
let target_dir = match jump_target.parent() {
Some(parent) => parent,
None => &jump_target,
};
- let tab = status.selected();
- tab.input.clear();
- tab.history.push(target_dir);
- tab.path_content
- .change_directory(target_dir, &tab.filter, tab.show_hidden)?;
- let index = tab.find_jump_index(&jump_target).unwrap_or_default();
- tab.path_content.select_index(index);
- tab.set_window();
- tab.scroll_to(index);
+ status.selected().set_pathcontent(target_dir)?;
+ let index = status.selected().path_content.select_file(&jump_target);
+ status.selected().scroll_to(index);
Ok(())
}
@@ -349,9 +319,9 @@ impl EventExec {
status: &mut Status,
confirmed_action: NeedConfirmation,
colors: &Colors,
- ) -> FmResult<()> {
+ ) -> Result<()> {
Self::_exec_confirmed_action(status, confirmed_action, colors)?;
- status.selected().set_mode(Mode::Normal);
+ status.selected().reset_mode();
Ok(())
}
@@ -359,7 +329,7 @@ impl EventExec {
status: &mut Status,
confirmed_action: NeedConfirmation,
colors: &Colors,
- ) -> FmResult<()> {
+ ) -> Result<()> {
match confirmed_action {
NeedConfirmation::Delete => Self::exec_delete_files(status, colors),
NeedConfirmation::Move => Self::exec_cut_paste(status),
@@ -377,13 +347,13 @@ impl EventExec {
/// Leave current mode to normal mode.
/// Reset the inputs and completion, reset the window, exit the preview.
- pub fn event_reset_mode(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_reset_mode(tab: &mut Tab) -> Result<()> {
tab.reset_mode();
tab.refresh_view()
}
/// Reset the inputs and completion, reset the window, exit the preview.
- pub fn event_normal(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_normal(tab: &mut Tab) -> Result<()> {
tab.refresh_view()
}
@@ -499,7 +469,7 @@ impl EventExec {
}
/// Select the left or right tab depending on where the user clicked.
- pub fn event_select_pane(status: &mut Status, col: u16) -> FmResult<()> {
+ pub fn event_select_pane(status: &mut Status, col: u16) -> Result<()> {
let (width, _) = status.term_size()?;
if (col as usize) < width / 2 {
status.select_tab(0)?;
@@ -510,7 +480,7 @@ impl EventExec {
}
/// Select a given row, if there's something in it.
- pub fn event_select_row(status: &mut Status, row: u16, colors: &Colors) -> FmResult<()> {
+ pub fn event_select_row(status: &mut Status, row: u16, colors: &Colors) -> Result<()> {
let tab = status.selected();
match tab.mode {
Mode::Normal => {
@@ -531,44 +501,10 @@ impl EventExec {
Ok(())
}
- /// Select the next shortcut.
- pub fn event_shortcut_next(tab: &mut Tab) {
- tab.shortcut.next()
- }
-
- /// Select the previous shortcut.
- pub fn event_shortcut_prev(tab: &mut Tab) {
- tab.shortcut.prev()
- }
-
- /// Select the next shortcut.
- pub fn event_marks_next(status: &mut Status) {
- status.marks.next()
- }
-
- /// Select the previous shortcut.
- pub fn event_marks_prev(status: &mut Status) {
- status.marks.prev()
- }
-
- /// Select the next element in history of visited files.
- /// Watchout! Since the history is displayed in reverse order,
- /// we call the "prev" method of the `History` instance instead.
- pub fn event_history_next(tab: &mut Tab) {
- tab.history.next()
- }
-
- /// Select the previous element in history of visited files.
- /// Watchout! Since the history is displayed in reverse order,
- /// we call the "next" method of the `History` instance instead.
- pub fn event_history_prev(tab: &mut Tab) {
- tab.history.prev()
- }
-
/// Move to parent directory if there's one.
/// Does
/// Add the starting directory to history.
- pub fn event_move_to_parent(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_move_to_parent(tab: &mut Tab) -> Result<()> {
tab.move_to_parent()
}
@@ -578,7 +514,7 @@ impl EventExec {
}
/// Open the file with configured opener or enter the directory.
- pub fn exec_file(status: &mut Status) -> FmResult<()> {
+ pub fn exec_file(status: &mut Status) -> Result<()> {
let tab = status.selected();
if tab.path_content.is_empty() {
return Ok(());
@@ -606,7 +542,7 @@ impl EventExec {
}
/// Add a char to input string, look for a possible completion.
- pub fn event_text_insert_and_complete(tab: &mut Tab, c: char) -> FmResult<()> {
+ pub fn event_text_insert_and_complete(tab: &mut Tab, c: char) -> Result<()> {
Self::event_text_insertion(tab, c);
tab.fill_completion()
}
@@ -615,7 +551,7 @@ impl EventExec {
/// A confirmation is asked before copying all flagged files to
/// the current directory.
/// Does nothing if no file is flagged.
- pub fn event_copy_paste(status: &mut Status) -> FmResult<()> {
+ pub fn event_copy_paste(status: &mut Status) -> Result<()> {
if status.flagged.is_empty() {
return Ok(());
}
@@ -629,7 +565,7 @@ impl EventExec {
/// A confirmation is asked before moving all flagged files to
/// the current directory.
/// Does nothing if no file is flagged.
- pub fn event_cut_paste(status: &mut Status) -> FmResult<()> {
+ pub fn event_cut_paste(status: &mut Status) -> Result<()> {
if status.flagged.is_empty() {
return Ok(());
}
@@ -640,20 +576,20 @@ impl EventExec {
}
/// Enter the new dir mode.
- pub fn event_new_dir(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_new_dir(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::InputSimple(InputSimple::Newdir));
Ok(())
}
/// Enter the new file mode.
- pub fn event_new_file(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_new_file(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::InputSimple(InputSimple::Newfile));
Ok(())
}
/// Enter the execute mode. Most commands must be executed to allow for
/// a confirmation.
- pub fn event_exec(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_exec(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::InputCompleted(InputCompleted::Exec));
Ok(())
}
@@ -662,7 +598,7 @@ impl EventExec {
/// Every file can be previewed. See the `crate::enum::Preview` for
/// more details on previewinga file.
/// Does nothing if the directory is empty.
- pub fn event_preview(status: &mut Status, colors: &Colors) -> FmResult<()> {
+ pub fn event_preview(status: &mut Status, colors: &Colors) -> Result<()> {
if status.selected_non_mut().path_content.is_empty() {
return Ok(());
}
@@ -691,7 +627,7 @@ impl EventExec {
/// Enter the delete mode.
/// A confirmation is then asked before deleting all the flagged files.
/// Does nothing is no file is flagged.
- pub fn event_delete_file(status: &mut Status) -> FmResult<()> {
+ pub fn event_delete_file(status: &mut Status) -> Result<()> {
if status.flagged.is_empty() {
return Ok(());
}
@@ -703,7 +639,7 @@ impl EventExec {
/// Display the help which can be navigated and displays the configrable
/// binds.
- pub fn event_help(status: &mut Status) -> FmResult<()> {
+ pub fn event_help(status: &mut Status) -> Result<()> {
let help = status.help.clone();
let tab = status.selected();
tab.set_mode(Mode::Preview);
@@ -713,7 +649,7 @@ impl EventExec {
}
/// Display the last actions impacting the file tree
- pub fn event_log(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_log(tab: &mut Tab) -> Result<()> {
let log = read_log()?;
tab.set_mode(Mode::Preview);
tab.preview = Preview::log(log);
@@ -724,7 +660,7 @@ impl EventExec {
/// Enter the search mode.
/// Matching items are displayed as you type them.
- pub fn event_search(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_search(tab: &mut Tab) -> Result<()> {
tab.searched = None;
tab.set_mode(Mode::InputCompleted(InputCompleted::Search));
Ok(())
@@ -732,7 +668,7 @@ impl EventExec {
/// Enter the regex mode.
/// Every file matching the typed regex will be flagged.
- pub fn event_regex_match(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_regex_match(tab: &mut Tab) -> Result<()> {
match tab.mode {
Mode::Tree => (),
_ => tab.set_mode(Mode::InputSimple(InputSimple::RegexMatch)),
@@ -741,14 +677,14 @@ impl EventExec {
}
/// Enter the sort mode, allowing the user to select a sort method.
- pub fn event_sort(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_sort(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::InputSimple(InputSimple::Sort));
Ok(())
}
/// Once a quit event is received, we change a flag and break the main loop.
/// It's usefull to reset the cursor before leaving the application.
- pub fn event_quit(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_quit(tab: &mut Tab) -> Result<()> {
if let Mode::Tree = tab.mode {
Self::event_normal(tab)?;
tab.set_mode(Mode::Normal)
@@ -773,7 +709,7 @@ impl EventExec {
/// by extension.
/// The first letter is used to identify the method.
/// If the user types an uppercase char, the sort is reverse.
- pub fn event_leave_sort(status: &mut Status, c: char, colors: &Colors) -> FmResult<()> {
+ pub fn event_leave_sort(status: &mut Status, c: char, colors: &Colors) -> Result<()> {
if status.selected_non_mut().path_content.content.is_empty() {
return Ok(());
}
@@ -804,7 +740,7 @@ impl EventExec {
}
/// Toggle the display of hidden files.
- pub fn event_toggle_hidden(status: &mut Status, colors: &Colors) -> FmResult<()> {
+ pub fn event_toggle_hidden(status: &mut Status, colors: &Colors) -> Result<()> {
let tab = status.selected();
tab.show_hidden = !tab.show_hidden;
tab.path_content.reset_files(&tab.filter, tab.show_hidden)?;
@@ -816,20 +752,25 @@ impl EventExec {
}
/// Open a file with custom opener.
- pub fn event_open_file(status: &mut Status) -> FmResult<()> {
- match status.opener.open(
- &status
- .selected_non_mut()
- .selected()
- .ok_or_else(|| FmError::custom("event open file", "Empty directory"))?
- .path,
- ) {
- Ok(_) => (),
- Err(e) => info!(
- "Error opening {:?}: {:?}",
- status.selected_non_mut().path_content.selected(),
- e
- ),
+ pub fn event_open_file(status: &mut Status) -> Result<()> {
+ let filepath = &status
+ .selected_non_mut()
+ .selected()
+ .context("event open file, Empty directory")?
+ .path
+ .clone();
+ let opener = status.opener.open_info(filepath);
+ if let Some(InternalVariant::NotSupported) = opener.internal_variant.as_ref() {
+ Self::event_mount_iso_drive(status)?;
+ } else {
+ match status.opener.open(filepath) {
+ Ok(_) => (),
+ Err(e) => info!(
+ "Error opening {:?}: {:?}",
+ status.selected_non_mut().path_content.selected(),
+ e
+ ),
+ }
}
Ok(())
}
@@ -838,15 +779,26 @@ impl EventExec {
/// Keep a track of the current mode to ensure we rename the correct file.
/// When we enter rename from a "tree" mode, we'll need to rename the selected file in the tree,
/// not the selected file in the pathcontent.
- pub fn event_rename(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_rename(tab: &mut Tab) -> Result<()> {
if tab.selected().is_some() {
+ let old_name = match tab.mode {
+ Mode::Tree => tab.directory.tree.current_node.filename(),
+ _ => filename_from_path(
+ &tab.path_content
+ .selected()
+ .context("Event rename: no file in current directory")?
+ .path,
+ )?
+ .to_owned(),
+ };
+ tab.input.replace(&old_name);
tab.set_mode(Mode::InputSimple(InputSimple::Rename));
}
Ok(())
}
/// Enter the goto mode where an user can type a path to jump to.
- pub fn event_goto(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_goto(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::InputCompleted(InputCompleted::Goto));
tab.completion.reset();
Ok(())
@@ -855,22 +807,31 @@ impl EventExec {
/// Open a new terminal in current directory.
/// The shell is a fork of current process and will exit if the application
/// is terminated first.
- pub fn event_shell(status: &mut Status) -> FmResult<()> {
+ pub fn event_shell(status: &mut Status) -> Result<()> {
let tab = status.selected_non_mut();
let path = tab.directory_of_selected()?;
execute_in_child_without_output_with_path(&status.opener.terminal, path, None)?;
Ok(())
}
- /// Enter the history mode, allowing to navigate to previously visited
- /// directory.
- pub fn event_shell_menu(tab: &mut Tab) -> FmResult<()> {
+ /// Enter the shell menu mode. You can pick a TUI application to be run
+ pub fn event_shell_menu(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::Navigate(Navigate::ShellMenu));
Ok(())
}
+
+ /// Enter the cli info mode. You can pick a Text application to be
+ /// displayed/
+ pub fn event_cli_info(status: &mut Status) -> Result<()> {
+ status
+ .selected()
+ .set_mode(Mode::Navigate(Navigate::CliInfo));
+ Ok(())
+ }
+
/// Enter the history mode, allowing to navigate to previously visited
/// directory.
- pub fn event_history(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_history(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::Navigate(Navigate::History));
Ok(())
}
@@ -878,7 +839,7 @@ impl EventExec {
/// Enter the shortcut mode, allowing to visit predefined shortcuts.
/// Basic folders (/, /dev... $HOME) and mount points (even impossible to
/// visit ones) are proposed.
- pub fn event_shortcut(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_shortcut(tab: &mut Tab) -> Result<()> {
std::env::set_current_dir(tab.current_path())?;
tab.shortcut.update_git_root();
tab.set_mode(Mode::Navigate(Navigate::Shortcut));
@@ -886,7 +847,7 @@ impl EventExec {
}
/// A right click opens a file or a directory.
- pub fn event_right_click(status: &mut Status, colors: &Colors) -> FmResult<()> {
+ pub fn event_right_click(status: &mut Status, colors: &Colors) -> Result<()> {
match status.selected().mode {
Mode::Normal => Self::exec_file(status),
Mode::Tree => Self::exec_tree(status, colors),
@@ -903,10 +864,7 @@ impl EventExec {
/// If no RPC server were provided at launch time - which may happen for
/// reasons unknow to me - it does nothing.
/// It requires the "nvim-send" application to be in $PATH.
- pub fn event_nvim_filepicker(status: &mut Status) -> FmResult<()> {
- if !is_program_in_path(NVIM_RPC_SENDER) {
- return Ok(());
- };
+ pub fn event_nvim_filepicker(status: &mut Status) -> Result<()> {
Self::read_nvim_listen_address_if_needed(status);
if status.nvim_server.is_empty() {
return Ok(());
@@ -920,51 +878,44 @@ impl EventExec {
Ok(())
}
- pub fn event_set_nvim_server(status: &mut Status) -> FmResult<()> {
+ pub fn event_set_nvim_server(status: &mut Status) -> Result<()> {
status
.selected()
- .set_mode(Mode::InputSimple(InputSimple::SetNvimAddress));
+ .set_mode(Mode::InputSimple(InputSimple::SetNvimAddr));
Ok(())
}
fn open_in_current_neovim(path_str: &str, nvim_server: &str) {
- let _ = execute_in_child(
- NVIM_RPC_SENDER,
- &vec![
- "--remote-send",
- &format!("<esc>:e {path_str}<cr><esc>:set number<cr><esc>:close<cr>"),
- "--servername",
- nvim_server,
- ],
- );
+ let command = &format!("<esc>:e {path_str}<cr><esc>:set number<cr><esc>:close<cr>");
+ let _ = nvim(nvim_server, command);
}
/// Copy the selected filename to the clipboard. Only the filename.
- pub fn event_filename_to_clipboard(tab: &Tab) -> FmResult<()> {
+ pub fn event_filename_to_clipboard(tab: &Tab) -> Result<()> {
Self::set_clipboard(
tab.selected()
- .ok_or_else(|| FmError::custom("event_filename_to_clipboard", "no selected file"))?
+ .context("event_filename_to_clipboard: no selected file")?
.filename
.clone(),
)
}
/// Copy the selected filepath to the clipboard. The absolute path.
- pub fn event_filepath_to_clipboard(tab: &Tab) -> FmResult<()> {
+ pub fn event_filepath_to_clipboard(tab: &Tab) -> Result<()> {
Self::set_clipboard(
tab.selected()
- .ok_or_else(|| FmError::custom("event_filepath_to_clipboard", "no selected file"))?
+ .context("event_filepath_to_clipboard: no selected file")?
.path
.to_str()
- .ok_or_else(|| FmError::custom("event_filepath_to_clipboard", "no selected file"))?
+ .context("event_filepath_to_clipboard: no selected file")?
.to_owned(),
)
}
- fn set_clipboard(content: String) -> FmResult<()> {
+ fn set_clipboard(content: String) -> Result<()> {
info!("copied to clipboard: {}", content);
- let mut ctx = ClipboardContext::new()?;
- ctx.set_contents(content)?;
+ let Ok(mut ctx) = ClipboardContext::new() else { return Ok(()); };
+ let Ok(_) = ctx.set_contents(content) else { return Ok(()); };
// For some reason, it's not writen if you don't read it back...
let _ = ctx.get_contents();
Ok(())
@@ -972,13 +923,13 @@ impl EventExec {
/// Enter the filter mode, where you can filter.
/// See `crate::filter::Filter` for more details.
- pub fn event_filter(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_filter(tab: &mut Tab) -> Result<()> {
tab.set_mode(Mode::InputSimple(InputSimple::Filter));
Ok(())
}
/// Move back in history to the last visited directory.
- pub fn event_back(status: &mut Status, colors: &Colors) -> FmResult<()> {
+ pub fn event_back(status: &mut Status, colors: &Colors) -> Result<()> {
if status.selected_non_mut().history.content.len() <= 1 {
return Ok(());
}
@@ -995,7 +946,7 @@ impl EventExec {
}
/// Move to $HOME aka ~.
- pub fn event_home(tab: &mut Tab) -> FmResult<()> {
+ pub fn event_home(tab: &mut Tab) -> Result<()> {
let home_cow = shellexpand::tilde("~");
let home: &str = home_cow.borrow();
let path = std::fs::canonicalize(home)?;
@@ -1016,13 +967,13 @@ impl EventExec {
/// It uses the `fs::rename` function and has the same limitations.
/// We only try to rename in the same directory, so it shouldn't be a problem.
/// Filename is sanitized before processing.
- pub fn exec_rename(tab: &mut Tab) -> FmResult<()> {
+ pub fn exec_rename(tab: &mut Tab) -> Result<()> {
let fileinfo = match tab.previous_mode {
Mode::Tree => &tab.directory.tree.current_node.fileinfo,
_ => tab
.path_content
.selected()
- .ok_or_else(|| FmError::custom("rename", "couldnt parse selected"))?,
+ .context("rename: couldnt parse selected")?,
};
let original_path = &fileinfo.path;
@@ -1047,7 +998,7 @@ impl EventExec {
/// Creates a new file with input string as name.
/// Nothing is done if the file already exists.
/// Filename is sanitized before processing.
- pub fn exec_newfile(tab: &mut Tab) -> FmResult<()> {
+ pub fn exec_newfile(tab: &mut Tab) -> Result<()> {
let path = tab
.path_content
.path
@@ -1064,7 +1015,7 @@ impl EventExec {
/// We use `fs::create_dir` internally so it will fail if the input string
/// ie. the user can create `newdir` or `newdir/newfolder`.
/// Directory name is sanitized before processing.
- pub fn exec_newdir(tab: &mut Tab) -> FmResult<()> {
+ pub fn exec_newdir(tab: &mut Tab) -> Result<()> {
let path = tab
.path_content
.path
@@ -1080,9 +1031,9 @@ impl EventExec {
/// from the input string. It will fail silently if the executable can't
/// be found.
/// Optional parameters can be passed normally. ie. `"ls -lah"`
- pub fn exec_exec(tab: &mut Tab) -> FmResult<()> {
+ pub fn exec_exec(tab: &mut Tab) -> Result<()> {
if tab.path_content.content.is_empty() {
- return Err(FmError::custom("exec exec", "empty directory"));
+ return Err(anyhow!("exec exec: empty directory"));
}
let exec_command = tab.input.string();
let mut args: Vec<&str> = exec_command.split(' ').collect();
@@ -1090,16 +1041,12 @@ impl EventExec {
if std::path::Path::new(command).exists() {
let path = &tab