@@ -8,7 +8,7 @@ use tui::text::Spans;
8pub use typed::*;
8pub use typed::*;
10use helix_core::{
10use helix_core::{
11− comment, coords_at_pos, find_first_non_whitespace_char, find_root, graphemes,
11+ comment, coords_at_pos, encoding, find_first_non_whitespace_char, find_root, graphemes,
12 history::UndoKind,
12 history::UndoKind,
13 increment::date_time::DateTimeIncrementor,
13 increment::date_time::DateTimeIncrementor,
14 increment::{number::NumberIncrementor, Increment},
14 increment::{number::NumberIncrementor, Increment},
@@ -4630,7 +4630,7 @@ fn shell_keep_pipe(cx: &mut Context) {
4631 for (i, range) in selection.ranges().iter().enumerate() {
4631 for (i, range) in selection.ranges().iter().enumerate() {
4632 let fragment = range.slice(text);
4632 let fragment = range.slice(text);
4633− let (_output, success) = match shell_impl(shell, input, Some(fragment)) {
4633+ let (_output, success) = match shell_impl(shell, input, Some(fragment.into())) {
4634 Ok(result) => result,
4634 Ok(result) => result,
4635 Err(err) => {
4635 Err(err) => {
4636 cx.editor.set_error(err.to_string());
4636 cx.editor.set_error(err.to_string());
@@ -4658,13 +4658,17 @@ fn shell_keep_pipe(cx: &mut Context) {
4661−fn shell_impl(
4661+fn shell_impl(shell: &[String], cmd: &str, input: Option<Rope>) -> anyhow::Result<(Tendril, bool)> {
4662+ tokio::task::block_in_place(|| helix_lsp::block_on(shell_impl_async(shell, cmd, input)))
4665+async fn shell_impl_async(
4662 shell: &[String],
4666 shell: &[String],
4663 cmd: &str,
4667 cmd: &str,
4664− input: Option<RopeSlice>,
4668+ input: Option<Rope>,
4665) -> anyhow::Result<(Tendril, bool)> {
4669) -> anyhow::Result<(Tendril, bool)> {
4666− use std::io::Write;
4670+ use std::process::Stdio;
4667− use std::process::{Command, Stdio};
4671+ use tokio::process::Command;
4668 ensure!(!shell.is_empty(), "No shell set");
4672 ensure!(!shell.is_empty(), "No shell set");
4670 let mut process = Command::new(&shell[0]);
4674 let mut process = Command::new(&shell[0]);
@@ -4687,13 +4691,22 @@ fn shell_impl(
4687 return Err(e.into());
4691 return Err(e.into());
4690− if let Some(input) = input {
4694+ let output = if let Some(mut stdin) = process.stdin.take() {
4691− let mut stdin = process.stdin.take().unwrap();
4695+ let input_task = tokio::spawn(async move {
4692− for chunk in input.chunks() {
4696+ if let Some(input) = input {
4693− stdin.write_all(chunk.as_bytes())?;
4697+ helix_view::document::to_writer(&mut stdin, encoding::UTF_8, &input).await?;
4699+ Ok::<_, anyhow::Error>(())
4701+ let (output, _) = tokio::join! {
4702+ process.wait_with_output(),
4707+ // Process has no stdin, so we just take the output
4696− let output = process.wait_with_output()?;
4708+ process.wait_with_output().await?
4698 if !output.status.success() {
4711 if !output.status.success() {
4699 if !output.stderr.is_empty() {
4712 if !output.stderr.is_empty() {
@@ -4731,7 +4744,7 @@ fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
4732 for range in selection.ranges() {
4745 for range in selection.ranges() {
4733 let fragment = range.slice(text);
4746 let fragment = range.slice(text);
4734− let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment)) {
4747+ let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment.into())) {
4735 Ok(result) => result,
4748 Ok(result) => result,
4736 Err(err) => {
4749 Err(err) => {
4737 cx.editor.set_error(err.to_string());
4750 cx.editor.set_error(err.to_string());