1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
use anyhow::{Context, Result};
use crate::impl_selectable_content;
use crate::log_line;
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 {
pub fn new(path: &str) -> Result<Self> {
let mut shell_menu = Self::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)
}
fn update_from_file(&mut self, yaml: &serde_yaml::mapping::Mapping) -> Result<()> {
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) -> Result<()> {
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())?
};
log_line!("Executed {name}");
Ok(())
}
fn require_cwd_and_command(status: &Status, command: &str) -> Result<()> {
let tab = status.selected_non_mut();
let path = tab
.directory_of_selected()?
.to_str()
.context("event_shell: couldn't parse the directory")?;
execute_in_child_without_output(&status.opener.terminal, &["-d", path, "-e", command])?;
Ok(())
}
fn simple(status: &Status, command: &str) -> Result<()> {
execute_in_child_without_output(&status.opener.terminal, &["-e", command])?;
Ok(())
}
fn _simple_with_args(status: &Status, args: Vec<&str>) -> Result<()> {
execute_in_child_without_output(&status.opener.terminal, &args)?;
Ok(())
}
fn require_cwd(status: &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(())
}
}
type SBool = (String, bool);
impl_selectable_content!(SBool, ShellMenu);
|