aboutsummaryrefslogtreecommitdiff
path: root/helix-term
diff options
context:
space:
mode:
authorBlaž Hrastnik2021-08-31 09:17:22 +0000
committerBlaž Hrastnik2021-08-31 09:19:18 +0000
commit4a76ea8f8834a880d63246c8d43587693ac7cc81 (patch)
treee51d6c39f67915be91669ef94ec1679c900ed090 /helix-term
parente772808a5b0417e4d074eb9683d79376f83dae2d (diff)
shell: Move changes outside so we can properly handle errors
Diffstat (limited to 'helix-term')
-rw-r--r--helix-term/src/commands.rs123
1 files changed, 61 insertions, 62 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 6437bf52..42495b7e 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -4346,74 +4346,73 @@ fn shell(cx: &mut Context, prompt: &str, behavior: ShellBehavior) {
if event == PromptEvent::Validate {
let (view, doc) = current!(cx.editor);
let selection = doc.selection(view.id);
- let mut error: Option<&str> = None;
- let transaction =
- Transaction::change_by_selection(doc.text(), selection, |range| {
- let mut process;
- match Command::new(&shell[0])
- .args(&shell[1..])
- .arg(input)
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .spawn()
- {
- Ok(p) => process = p,
- Err(e) => {
- log::error!("Failed to start shell: {}", e);
- error = Some("Failed to start shell");
- return (0, 0, None);
- }
- }
- if pipe {
- let stdin = process.stdin.as_mut().unwrap();
- let fragment = range.fragment(doc.text().slice(..));
- stdin.write_all(fragment.as_bytes()).unwrap();
+
+ let mut changes = Vec::with_capacity(selection.len());
+
+ for range in selection.ranges() {
+ let mut process;
+ match Command::new(&shell[0])
+ .args(&shell[1..])
+ .arg(input)
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .spawn()
+ {
+ Ok(p) => process = p,
+ 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() {
- let stderr = output.stderr;
- if !stderr.is_empty() {
- log::error!(
- "Shell error: {}",
- String::from_utf8_lossy(&stderr)
- );
- }
- error = Some("Command failed");
- return (0, 0, None);
+ let output = process.wait_with_output().unwrap();
+ if behavior != ShellBehavior::Filter {
+ if !output.status.success() {
+ let stderr = output.stderr;
+ if !stderr.is_empty() {
+ log::error!("Shell error: {}", String::from_utf8_lossy(&stderr));
}
- let stdout = output.stdout;
- let tendril;
- match Tendril::try_from_byte_slice(&stdout) {
- Ok(t) => tendril = t,
- Err(_) => {
- error = Some("Process did not output valid UTF-8");
- return (0, 0, None);
- }
+ cx.editor.set_error("Command failed".to_owned());
+ return;
+ }
+ let stdout = output.stdout;
+ let tendril;
+ match Tendril::try_from_byte_slice(&stdout) {
+ Ok(t) => tendril = t,
+ Err(_) => {
+ cx.editor
+ .set_error("Process did not output valid UTF-8".to_owned());
+ return;
}
- let (from, to) = match behavior {
- ShellBehavior::Replace => (range.from(), range.to()),
- ShellBehavior::Insert => (range.from(), range.from()),
- ShellBehavior::Append => (range.to(), range.to()),
- _ => (range.from(), range.from()),
- };
- (from, to, Some(tendril))
- } else {
- // if the process exits successfully, keep the selection, otherwise delete it.
- let keep = output.status.success();
- (
- range.from(),
- if keep { range.from() } else { range.to() },
- None,
- )
}
- });
+ let (from, to) = match behavior {
+ ShellBehavior::Replace => (range.from(), range.to()),
+ ShellBehavior::Insert => (range.from(), range.from()),
+ ShellBehavior::Append => (range.to(), range.to()),
+ _ => (range.from(), range.from()),
+ };
+ changes.push((from, to, Some(tendril)));
+ } else {
+ // if the process exits successfully, keep the selection, otherwise delete it.
+ let keep = output.status.success();
+ changes.push((
+ range.from(),
+ if keep { range.from() } else { range.to() },
+ None,
+ ));
+ }
+ }
+
+ let transaction = Transaction::change(doc.text(), changes.into_iter());
- if let Some(error) = error {
- cx.editor.set_error(error.to_owned());
- } else if behavior != ShellBehavior::Ignore {
+ if behavior != ShellBehavior::Ignore {
doc.apply(&transaction, view.id);
doc.append_changes_to_history(view.id);
}