summaryrefslogtreecommitdiffstats
path: root/src/shell_menu.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/shell_menu.rs')
-rw-r--r--src/shell_menu.rs86
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)
+}