aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Deiml2022-10-29 15:24:33 +0000
committerGitHub2022-10-29 15:24:33 +0000
commit5e256e4a98561c2085b1ecae1e39e27bf3744724 (patch)
tree3ca6d7a30edfc8f2739e23eb4a6ea1ded8dd1b9f
parentc58e1729cef774db6619e394942465c12abd65cd (diff)
Make shell_impl concurrent (#3180)
-rw-r--r--helix-term/src/commands.rs41
1 files changed, 27 insertions, 14 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index fca55b68..172a7b2e 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<Rope>) -> 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<RopeSlice>,
+ input: Option<Rope>,
) -> 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());