on master help sign in
Extract the shell command into a separate function
commitdc609cafb506e9677d16632b6fede3c488d4c4bb authorBlaž Hrastnik <blaz@mxxn.io> dateWed 1 Sep 2021, 10:46 (5 years ago) parenta3bd80a
1 file changed+50−40
helix-term/src/commands.rs+50−40
helix-term/src/commands.rs+50−40
@@ -4322,9 +4322,46 @@ fn shell_keep_pipe(cx: &mut Context) {
43224322 shell(cx, "keep-pipe:".into(), ShellBehavior::Filter);
43234323}
43244324
4325−fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
4325+fn shell_impl(
4326+ shell: &[String],
4327+ cmd: &str,
4328+ input: Option<&[u8]>,
4329+) -> anyhow::Result<(Tendril, bool)> {
43264330 use std::io::Write;
43274331 use std::process::{Command, Stdio};
4332+ let mut process = match Command::new(&shell[0])
4333+ .args(&shell[1..])
4334+ .arg(cmd)
4335+ .stdin(Stdio::piped())
4336+ .stdout(Stdio::piped())
4337+ .stderr(Stdio::piped())
4338+ .spawn()
4339+ {
4340+ Ok(process) => process,
4341+ Err(e) => {
4342+ log::error!("Failed to start shell: {}", e);
4343+ return Err(e.into());
4344+ }
4345+ };
4346+ if let Some(input) = input {
4347+ let mut stdin = process.stdin.take().unwrap();
4348+ stdin.write_all(input)?;
4349+ }
4350+ let output = process.wait_with_output()?;
4351+
4352+ if !output.status.success() {
4353+ if !output.stderr.is_empty() {
4354+ log::error!("Shell error: {}", String::from_utf8_lossy(&output.stderr));
4355+ }
4356+ bail!("Command failed");
4357+ }
4358+
4359+ let tendril = Tendril::try_from_byte_slice(&output.stdout)
4360+ .map_err(|_| anyhow!("Process did not output valid UTF-8"))?;
4361+ Ok((tendril, output.status.success()))
4362+}
4363+
4364+fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
43284365 if cx.editor.config.shell.is_empty() {
43294366 cx.editor.set_error("No shell set".to_owned());
43304367 return;
@@ -4338,67 +4375,40 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
43384375 Some('|'),
43394376 |_input: &str| Vec::new(),
43404377 move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
4378+ let shell = &cx.editor.config.shell;
43414379 if event != PromptEvent::Validate {
43424380 return;
43434381 }
4344− let shell = &cx.editor.config.shell;
43454382 let (view, doc) = current!(cx.editor);
43464383 let selection = doc.selection(view.id);
43474384
43484385 let mut changes = Vec::with_capacity(selection.len());
4386+ let text = doc.text().slice(..);
43494387
43504388 for range in selection.ranges() {
4351− let mut process = match Command::new(&shell[0])
4352− .args(&shell[1..])
4353− .arg(input)
4354− .stdin(Stdio::piped())
4355− .stdout(Stdio::piped())
4356− .stderr(Stdio::piped())
4357− .spawn()
4358− {
4359− Ok(process) => process,
4360− Err(e) => {
4361− log::error!("Failed to start shell: {}", e);
4362− cx.editor.set_error("Failed to start shell".to_owned());
4363− return;
4364− }
4365− };
4366− if pipe {
4367− let stdin = process.stdin.as_mut().unwrap();
4368− let fragment = range.fragment(doc.text().slice(..));
4369− stdin.write_all(fragment.as_bytes()).unwrap();
4370− }
4371− let output = process.wait_with_output().unwrap();
4372−
4373− if behavior != ShellBehavior::Filter {
4374− if !output.status.success() {
4375− if !output.stderr.is_empty() {
4376− log::error!("Shell error: {}", String::from_utf8_lossy(&output.stderr));
4377− }
4378− cx.editor.set_error("Command failed".to_owned());
4379− return;
4380− }
4381− let tendril = match Tendril::try_from_byte_slice(&output.stdout) {
4382− Ok(tendril) => tendril,
4383− Err(_) => {
4384− cx.editor
4385− .set_error("Process did not output valid UTF-8".to_owned());
4389+ let fragment = range.fragment(text);
4390+ let (output, success) =
4391+ match shell_impl(shell, input, pipe.then(|| fragment.as_bytes())) {
4392+ Ok(result) => result,
4393+ Err(err) => {
4394+ cx.editor.set_error(err.to_string());
43864395 return;
43874396 }
43884397 };
4398+
4399+ if behavior != ShellBehavior::Filter {
43894400 let (from, to) = match behavior {
43904401 ShellBehavior::Replace => (range.from(), range.to()),
43914402 ShellBehavior::Insert => (range.from(), range.from()),
43924403 ShellBehavior::Append => (range.to(), range.to()),
43934404 _ => (range.from(), range.from()),
43944405 };
4395− changes.push((from, to, Some(tendril)));
4406+ changes.push((from, to, Some(output)));
43964407 } else {
43974408 // if the process exits successfully, keep the selection, otherwise delete it.
4398− let keep = output.status.success();
43994409 changes.push((
44004410 range.from(),
4401− if keep { range.from() } else { range.to() },
4411+ if success { range.from() } else { range.to() },
44024412 None,
44034413 ));
44044414 }