From 2b11951166ffa56528f23fe8840fae0f1122e4ab Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Sat, 17 Dec 2022 11:25:15 -0500 Subject: [PATCH] Add shell handling --- src/command.rs | 54 +++++++++++++++++++++++++++++++------------------- src/main.rs | 22 ++++++++++++++++++++ 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/command.rs b/src/command.rs index 65079d9..e0af510 100644 --- a/src/command.rs +++ b/src/command.rs @@ -25,32 +25,46 @@ impl Default for CommandResult { } pub fn run(app: &mut App) { - app.command_result = match run_inner(app) { - Ok(c) => c, - Err(e) => CommandResult { - status_success: false, - stdout: vec![], - stderr: format!("{e:?}").as_bytes().to_vec(), - }, - }; + match run_inner(app) { + Ok(c) => { + // If there was no stdout and the command failed, don't touch stdout + if !c.status_success && c.stdout.is_empty() { + app.command_result.stderr = c.stderr; + app.command_result.status_success = c.status_success; + } else { + app.command_result = c; + } + } + Err(e) => { + println!("asdf"); + app.command_result.status_success = false; + app.command_result.stderr = e.to_string().as_bytes().to_vec(); + } + } } fn run_inner(app: &mut App) -> Result { - let args = match shellwords::split(&app.cmdline) { - Ok(a) => a, - Err(e) => { - bail!("Argument error: {e:?}"); - } - }; - - let mut child = Command::new(&app.command) - .args(&app.hidden_options) - .args(args) + let mut command = Command::new(&app.command); + command .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()) - .spawn() - .context("Could not spawn child process")?; + .args(&app.hidden_options); + + if app.wordsplit { + match shellwords::split(&app.cmdline) { + Ok(a) => { + command.args(a); + } + Err(e) => { + bail!("Argument error: {e:?}"); + } + } + } else { + // TODO: Avoid cloning here + command.arg(&app.cmdline); + } + let mut child = command.spawn().context("Could not spawn child process")?; let mut stdin = child.stdin.take().context("Could not take stdin")?; let text_orig_clone = app.text_orig.clone(); diff --git a/src/main.rs b/src/main.rs index 9b49a3a..ba922e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -52,6 +52,9 @@ pub struct App { /// Should every keystroke transform the original text? autorun: bool, + + /// Should wordsplitting be enabled + wordsplit: bool, } impl App { @@ -61,6 +64,7 @@ impl App { let command_result = CommandResult::default(); let command = template.command(); let cmdline_position = 0; + let wordsplit = true; match template { Template::Awk | Template::Generic(_) => Self { @@ -71,6 +75,17 @@ impl App { autorun: true, command, hidden_options: vec![], + wordsplit, + }, + Template::Sh(_) => Self { + cmdline: String::from(""), + cmdline_position: 0, + text_orig, + command_result, + autorun: true, + command, + hidden_options: vec!["-c"], + wordsplit: false, }, Template::Jq => Self { cmdline: String::from("'.'"), @@ -80,6 +95,7 @@ impl App { autorun: true, command, hidden_options: vec!["-C"], + wordsplit, }, Template::Grep | Template::Rg => Self { cmdline: String::from("''"), @@ -89,6 +105,7 @@ impl App { autorun: true, command, hidden_options: vec!["--color=always"], + wordsplit, }, Template::Sed => Self { cmdline: String::from("'s///g'"), @@ -98,6 +115,7 @@ impl App { autorun: true, command, hidden_options: vec![], + wordsplit, }, Template::Perl => Self { cmdline: String::from("-p -e 's///'"), @@ -107,6 +125,7 @@ impl App { autorun: true, command, hidden_options: vec![], + wordsplit, }, } } @@ -114,6 +133,7 @@ impl App { pub enum Template { Generic(String), + Sh(String), Jq, Grep, Rg, @@ -132,6 +152,7 @@ impl Template { "sed" => Self::Sed, "awk" => Self::Awk, "perl" => Self::Perl, + s @ "sh" | s @ "bash" | s @ "zsh" | s @ "dash" => Self::Sh(s.to_string()), c => Self::Generic(c.to_string()), } } @@ -140,6 +161,7 @@ impl Template { pub fn command(&self) -> String { match self { Self::Generic(c) => c.to_string(), + Self::Sh(s) => s.to_string(), Self::Jq => String::from("jq"), Self::Grep => String::from("grep"), Self::Rg => String::from("rg"),