mirror of
https://github.com/helix-editor/helix.git
synced 2024-11-23 09:56:19 +04:00
Extract the shell command into a separate function
This commit is contained in:
parent
a3bd80a6fa
commit
dc609cafb5
@ -4322,9 +4322,46 @@ fn shell_keep_pipe(cx: &mut Context) {
|
|||||||
shell(cx, "keep-pipe:".into(), ShellBehavior::Filter);
|
shell(cx, "keep-pipe:".into(), ShellBehavior::Filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
|
fn shell_impl(
|
||||||
|
shell: &[String],
|
||||||
|
cmd: &str,
|
||||||
|
input: Option<&[u8]>,
|
||||||
|
) -> anyhow::Result<(Tendril, bool)> {
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
let mut process = match Command::new(&shell[0])
|
||||||
|
.args(&shell[1..])
|
||||||
|
.arg(cmd)
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
{
|
||||||
|
Ok(process) => process,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to start shell: {}", e);
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(input) = input {
|
||||||
|
let mut stdin = process.stdin.take().unwrap();
|
||||||
|
stdin.write_all(input)?;
|
||||||
|
}
|
||||||
|
let output = process.wait_with_output()?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
if !output.stderr.is_empty() {
|
||||||
|
log::error!("Shell error: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
|
}
|
||||||
|
bail!("Command failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
let tendril = Tendril::try_from_byte_slice(&output.stdout)
|
||||||
|
.map_err(|_| anyhow!("Process did not output valid UTF-8"))?;
|
||||||
|
Ok((tendril, output.status.success()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
|
||||||
if cx.editor.config.shell.is_empty() {
|
if cx.editor.config.shell.is_empty() {
|
||||||
cx.editor.set_error("No shell set".to_owned());
|
cx.editor.set_error("No shell set".to_owned());
|
||||||
return;
|
return;
|
||||||
@ -4338,67 +4375,40 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
|
|||||||
Some('|'),
|
Some('|'),
|
||||||
|_input: &str| Vec::new(),
|
|_input: &str| Vec::new(),
|
||||||
move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
|
move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
|
||||||
|
let shell = &cx.editor.config.shell;
|
||||||
if event != PromptEvent::Validate {
|
if event != PromptEvent::Validate {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let shell = &cx.editor.config.shell;
|
|
||||||
let (view, doc) = current!(cx.editor);
|
let (view, doc) = current!(cx.editor);
|
||||||
let selection = doc.selection(view.id);
|
let selection = doc.selection(view.id);
|
||||||
|
|
||||||
let mut changes = Vec::with_capacity(selection.len());
|
let mut changes = Vec::with_capacity(selection.len());
|
||||||
|
let text = doc.text().slice(..);
|
||||||
|
|
||||||
for range in selection.ranges() {
|
for range in selection.ranges() {
|
||||||
let mut process = match Command::new(&shell[0])
|
let fragment = range.fragment(text);
|
||||||
.args(&shell[1..])
|
let (output, success) =
|
||||||
.arg(input)
|
match shell_impl(shell, input, pipe.then(|| fragment.as_bytes())) {
|
||||||
.stdin(Stdio::piped())
|
Ok(result) => result,
|
||||||
.stdout(Stdio::piped())
|
Err(err) => {
|
||||||
.stderr(Stdio::piped())
|
cx.editor.set_error(err.to_string());
|
||||||
.spawn()
|
|
||||||
{
|
|
||||||
Ok(process) => process,
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Failed to start shell: {}", e);
|
|
||||||
cx.editor.set_error("Failed to start shell".to_owned());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if pipe {
|
|
||||||
let stdin = process.stdin.as_mut().unwrap();
|
|
||||||
let fragment = range.fragment(doc.text().slice(..));
|
|
||||||
stdin.write_all(fragment.as_bytes()).unwrap();
|
|
||||||
}
|
|
||||||
let output = process.wait_with_output().unwrap();
|
|
||||||
|
|
||||||
if behavior != ShellBehavior::Filter {
|
|
||||||
if !output.status.success() {
|
|
||||||
if !output.stderr.is_empty() {
|
|
||||||
log::error!("Shell error: {}", String::from_utf8_lossy(&output.stderr));
|
|
||||||
}
|
|
||||||
cx.editor.set_error("Command failed".to_owned());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let tendril = match Tendril::try_from_byte_slice(&output.stdout) {
|
|
||||||
Ok(tendril) => tendril,
|
|
||||||
Err(_) => {
|
|
||||||
cx.editor
|
|
||||||
.set_error("Process did not output valid UTF-8".to_owned());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if behavior != ShellBehavior::Filter {
|
||||||
let (from, to) = match behavior {
|
let (from, to) = match behavior {
|
||||||
ShellBehavior::Replace => (range.from(), range.to()),
|
ShellBehavior::Replace => (range.from(), range.to()),
|
||||||
ShellBehavior::Insert => (range.from(), range.from()),
|
ShellBehavior::Insert => (range.from(), range.from()),
|
||||||
ShellBehavior::Append => (range.to(), range.to()),
|
ShellBehavior::Append => (range.to(), range.to()),
|
||||||
_ => (range.from(), range.from()),
|
_ => (range.from(), range.from()),
|
||||||
};
|
};
|
||||||
changes.push((from, to, Some(tendril)));
|
changes.push((from, to, Some(output)));
|
||||||
} else {
|
} else {
|
||||||
// if the process exits successfully, keep the selection, otherwise delete it.
|
// if the process exits successfully, keep the selection, otherwise delete it.
|
||||||
let keep = output.status.success();
|
|
||||||
changes.push((
|
changes.push((
|
||||||
range.from(),
|
range.from(),
|
||||||
if keep { range.from() } else { range.to() },
|
if success { range.from() } else { range.to() },
|
||||||
None,
|
None,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user