summaryrefslogtreecommitdiffstats
path: root/src/shell_parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/shell_parser.rs')
-rw-r--r--src/shell_parser.rs102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/shell_parser.rs b/src/shell_parser.rs
new file mode 100644
index 0000000..53ffc9c
--- /dev/null
+++ b/src/shell_parser.rs
@@ -0,0 +1,102 @@
+use anyhow::{Context, Result};
+
+use crate::status::Status;
+
+/// Expanded tokens from a configured command.
+/// %s is converted into a `Selected`
+/// %f is converted into a `Flagged`
+/// %e is converted into a `Extension`
+/// %n is converted into a `Filename`
+/// Everything else is left intact and wrapped into an `Arg(string)`.
+#[derive(Debug, Clone)]
+pub enum Token {
+ Arg(String),
+ Extension,
+ Filename,
+ Flagged,
+ Path,
+ Selected,
+}
+
+impl Token {
+ fn from(arg: &str) -> Self {
+ match arg {
+ "%s" => Self::Selected,
+ "%e" => Self::Extension,
+ "%n" => Self::Filename,
+ "%f" => Self::Flagged,
+ "%p" => Self::Path,
+ _ => Self::Arg(arg.to_owned()),
+ }
+ }
+}
+
+/// Parse a command defined in the config file into a list of tokens
+/// Those tokens are converted back into a list of arguments to be run
+#[derive(Debug, Clone)]
+pub struct ShellCommandParser {
+ parsed: Vec<Token>,
+}
+
+impl ShellCommandParser {
+ /// Parse a command into a list of tokens
+ pub fn new(command: &str) -> Self {
+ Self {
+ parsed: Self::parse(command),
+ }
+ }
+
+ fn parse(command: &str) -> Vec<Token> {
+ command.split(' ').map(Token::from).collect()
+ }
+
+ /// Compute the command back into an arg list to be executed.
+ pub fn compute(&self, status: &Status) -> Result<Vec<String>> {
+ let mut computed = vec![];
+ for token in self.parsed.iter() {
+ match token {
+ Token::Arg(string) => computed.push(string.to_owned()),
+ Token::Selected => {
+ let path = status
+ .selected_non_mut()
+ .path_content
+ .selected_path_string()
+ .context("Empty directory")?;
+ computed.push(path);
+ }
+ Token::Path => {
+ let path = status
+ .selected_non_mut()
+ .path_content_str()
+ .context("Couldn't read path")?
+ .to_owned();
+ computed.push(path);
+ }
+ Token::Filename => {
+ let filename = status
+ .selected_non_mut()
+ .selected()
+ .context("Empty directory")?
+ .filename
+ .clone();
+ computed.push(filename);
+ }
+ Token::Extension => {
+ let extension = status
+ .selected_non_mut()
+ .selected()
+ .context("Empty directory")?
+ .extension
+ .clone();
+ computed.push(extension);
+ }
+ Token::Flagged => {
+ for path in status.flagged.content.iter() {
+ computed.push(path.to_str().context("Couldn't parse the path")?.to_owned());
+ }
+ }
+ }
+ }
+ Ok(computed)
+ }
+}