diff options
Diffstat (limited to 'src/shell_menu.rs')
-rw-r--r-- | src/shell_menu.rs | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/src/shell_menu.rs b/src/shell_menu.rs new file mode 100644 index 0000000..21d1cd5 --- /dev/null +++ b/src/shell_menu.rs @@ -0,0 +1,86 @@ +use crate::fm_error::{FmError, FmResult}; +use crate::impl_selectable_content; +use crate::opener::{execute_in_child_without_output, execute_in_child_without_output_with_path}; +use crate::status::Status; +use crate::utils::is_program_in_path; + +#[derive(Clone)] +pub struct ShellMenu { + pub content: Vec<(String, bool)>, + index: usize, +} + +impl Default for ShellMenu { + fn default() -> Self { + let index = 0; + let content = vec![("shell".to_owned(), false)]; + Self { content, index } + } +} + +impl ShellMenu { + fn update_from_file(&mut self, yaml: &serde_yaml::mapping::Mapping) -> FmResult<()> { + for (key, mapping) in yaml.into_iter() { + let Some(command) = key.as_str() else { continue; }; + if !is_program_in_path(command) { + continue; + } + let command = command.to_owned(); + let Some(require_cwd) = mapping.get("cwd") else { continue; }; + let Some(require_cwd) = require_cwd.as_bool() else { continue; }; + self.content.push((command, require_cwd)); + } + Ok(()) + } + + pub fn execute(&self, status: &Status) -> FmResult<()> { + let (name, require_cwd) = &self.content[self.index]; + if name.as_str() == "shell" { + Self::require_cwd(status)? + } else if *require_cwd { + Self::require_cwd_and_command(status, name.as_str())? + } else { + Self::simple(status, name.as_str())? + }; + Ok(()) + } + + fn require_cwd_and_command(status: &Status, command: &str) -> FmResult<()> { + let tab = status.selected_non_mut(); + let path = tab + .directory_of_selected()? + .to_str() + .ok_or_else(|| FmError::custom("event_shell", "Couldn't parse the directory"))?; + execute_in_child_without_output(&status.opener.terminal, &vec!["-d", path, "-e", command])?; + Ok(()) + } + + fn simple(status: &Status, command: &str) -> FmResult<()> { + execute_in_child_without_output(&status.opener.terminal, &vec!["-e", command])?; + Ok(()) + } + + fn _simple_with_args(status: &Status, args: Vec<&str>) -> FmResult<()> { + execute_in_child_without_output(&status.opener.terminal, &args)?; + Ok(()) + } + + fn require_cwd(status: &Status) -> FmResult<()> { + 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(()) + } +} + +type SBool = (String, bool); + +impl_selectable_content!(SBool, ShellMenu); + +pub fn load_shell_menu(path: &str) -> FmResult<ShellMenu> { + let mut shell_menu = ShellMenu::default(); + let file = std::fs::File::open(std::path::Path::new(&shellexpand::tilde(path).to_string()))?; + let yaml = serde_yaml::from_reader(file)?; + shell_menu.update_from_file(&yaml)?; + Ok(shell_menu) +} |