From 5e256e4a98561c2085b1ecae1e39e27bf3744724 Mon Sep 17 00:00:00 2001 From: Matthias Deiml Date: Sat, 29 Oct 2022 17:24:33 +0200 Subject: [PATCH] Make shell_impl concurrent (#3180) --- helix-term/src/commands.rs | 41 +++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index fca55b682..172a7b2e7 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -8,7 +8,7 @@ use tui::text::Spans; pub use typed::*; use helix_core::{ - comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes, + comment, coords_at_pos, encoding, find_first_non_whitespace_char, find_root, graphemes, history::UndoKind, increment::date_time::DateTimeIncrementor, increment::{number::NumberIncrementor, Increment}, @@ -4630,7 +4630,7 @@ fn shell_keep_pipe(cx: &mut Context) { for (i, range) in selection.ranges().iter().enumerate() { let fragment = range.slice(text); - let (_output, success) = match shell_impl(shell, input, Some(fragment)) { + let (_output, success) = match shell_impl(shell, input, Some(fragment.into())) { Ok(result) => result, Err(err) => { cx.editor.set_error(err.to_string()); @@ -4658,13 +4658,17 @@ fn shell_keep_pipe(cx: &mut Context) { ); } -fn shell_impl( +fn shell_impl(shell: &[String], cmd: &str, input: Option) -> anyhow::Result<(Tendril, bool)> { + tokio::task::block_in_place(|| helix_lsp::block_on(shell_impl_async(shell, cmd, input))) +} + +async fn shell_impl_async( shell: &[String], cmd: &str, - input: Option, + input: Option, ) -> anyhow::Result<(Tendril, bool)> { - use std::io::Write; - use std::process::{Command, Stdio}; + use std::process::Stdio; + use tokio::process::Command; ensure!(!shell.is_empty(), "No shell set"); let mut process = Command::new(&shell[0]); @@ -4687,13 +4691,22 @@ fn shell_impl( return Err(e.into()); } }; - if let Some(input) = input { - let mut stdin = process.stdin.take().unwrap(); - for chunk in input.chunks() { - stdin.write_all(chunk.as_bytes())?; - } - } - let output = process.wait_with_output()?; + let output = if let Some(mut stdin) = process.stdin.take() { + let input_task = tokio::spawn(async move { + if let Some(input) = input { + helix_view::document::to_writer(&mut stdin, encoding::UTF_8, &input).await?; + } + Ok::<_, anyhow::Error>(()) + }); + let (output, _) = tokio::join! { + process.wait_with_output(), + input_task, + }; + output? + } else { + // Process has no stdin, so we just take the output + process.wait_with_output().await? + }; if !output.status.success() { if !output.stderr.is_empty() { @@ -4731,7 +4744,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) { for range in selection.ranges() { let fragment = range.slice(text); - let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment)) { + let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment.into())) { Ok(result) => result, Err(err) => { cx.editor.set_error(err.to_string());