on master help sign in
shell: Move changes outside so we can properly handle errors
commit4a76ea8f8834a880d63246c8d43587693ac7cc81 authorBlaž Hrastnik <blaz@mxxn.io> dateTue 31 Aug 2021, 18:17 (5 years ago) parente772808
1 file changed+61−62
helix-term/src/commands.rs+61−62
helix-term/src/commands.rs+61−62
@@ -4346,74 +4346,73 @@ fn shell(cx: &mut Context, prompt: &str, behavior: ShellBehavior) {
43464346 if event == PromptEvent::Validate {
43474347 let (view, doc) = current!(cx.editor);
43484348 let selection = doc.selection(view.id);
4349− let mut error: Option<&str> = None;
4350− let transaction =
4351− Transaction::change_by_selection(doc.text(), selection, |range| {
4352− let mut process;
4353− match Command::new(&shell[0])
4354− .args(&shell[1..])
4355− .arg(input)
4356− .stdin(Stdio::piped())
4357− .stdout(Stdio::piped())
4358− .stderr(Stdio::piped())
4359− .spawn()
4360− {
4361− Ok(p) => process = p,
4362− Err(e) => {
4363− log::error!("Failed to start shell: {}", e);
4364− error = Some("Failed to start shell");
4365− return (0, 0, None);
4366− }
4367− }
4368− if pipe {
4369− let stdin = process.stdin.as_mut().unwrap();
4370− let fragment = range.fragment(doc.text().slice(..));
4371− stdin.write_all(fragment.as_bytes()).unwrap();
4349+
4350+ let mut changes = Vec::with_capacity(selection.len());
4351+
4352+ for range in selection.ranges() {
4353+ let mut process;
4354+ match Command::new(&shell[0])
4355+ .args(&shell[1..])
4356+ .arg(input)
4357+ .stdin(Stdio::piped())
4358+ .stdout(Stdio::piped())
4359+ .stderr(Stdio::piped())
4360+ .spawn()
4361+ {
4362+ Ok(p) => process = p,
4363+ Err(e) => {
4364+ log::error!("Failed to start shell: {}", e);
4365+ cx.editor.set_error("Failed to start shell".to_owned());
4366+ return;
43724367 }
4368+ }
4369+ if pipe {
4370+ let stdin = process.stdin.as_mut().unwrap();
4371+ let fragment = range.fragment(doc.text().slice(..));
4372+ stdin.write_all(fragment.as_bytes()).unwrap();
4373+ }
43734374
4374− let output = process.wait_with_output().unwrap();
4375− if behavior != ShellBehavior::Filter {
4376− if !output.status.success() {
4377− let stderr = output.stderr;
4378− if !stderr.is_empty() {
4379− log::error!(
4380− "Shell error: {}",
4381− String::from_utf8_lossy(&stderr)
4382− );
4383− }
4384− error = Some("Command failed");
4385− return (0, 0, None);
4375+ let output = process.wait_with_output().unwrap();
4376+ if behavior != ShellBehavior::Filter {
4377+ if !output.status.success() {
4378+ let stderr = output.stderr;
4379+ if !stderr.is_empty() {
4380+ log::error!("Shell error: {}", String::from_utf8_lossy(&stderr));
43864381 }
4387− let stdout = output.stdout;
4388− let tendril;
4389− match Tendril::try_from_byte_slice(&stdout) {
4390− Ok(t) => tendril = t,
4391− Err(_) => {
4392− error = Some("Process did not output valid UTF-8");
4393− return (0, 0, None);
4394− }
4382+ cx.editor.set_error("Command failed".to_owned());
4383+ return;
4384+ }
4385+ let stdout = output.stdout;
4386+ let tendril;
4387+ match Tendril::try_from_byte_slice(&stdout) {
4388+ Ok(t) => tendril = t,
4389+ Err(_) => {
4390+ cx.editor
4391+ .set_error("Process did not output valid UTF-8".to_owned());
4392+ return;
43954393 }
4396− let (from, to) = match behavior {
4397− ShellBehavior::Replace => (range.from(), range.to()),
4398− ShellBehavior::Insert => (range.from(), range.from()),
4399− ShellBehavior::Append => (range.to(), range.to()),
4400− _ => (range.from(), range.from()),
4401− };
4402− (from, to, Some(tendril))
4403− } else {
4404− // if the process exits successfully, keep the selection, otherwise delete it.
4405− let keep = output.status.success();
4406− (
4407− range.from(),
4408− if keep { range.from() } else { range.to() },
4409− None,
4410− )
44114394 }
4412− });
4395+ let (from, to) = match behavior {
4396+ ShellBehavior::Replace => (range.from(), range.to()),
4397+ ShellBehavior::Insert => (range.from(), range.from()),
4398+ ShellBehavior::Append => (range.to(), range.to()),
4399+ _ => (range.from(), range.from()),
4400+ };
4401+ changes.push((from, to, Some(tendril)));
4402+ } else {
4403+ // if the process exits successfully, keep the selection, otherwise delete it.
4404+ let keep = output.status.success();
4405+ changes.push((
4406+ range.from(),
4407+ if keep { range.from() } else { range.to() },
4408+ None,
4409+ ));
4410+ }
4411+ }
4412+
4413+ let transaction = Transaction::change(doc.text(), changes.into_iter());
44134414
4414− if let Some(error) = error {
4415− cx.editor.set_error(error.to_owned());
4416− } else if behavior != ShellBehavior::Ignore {
4415+ if behavior != ShellBehavior::Ignore {
44174416 doc.apply(&transaction, view.id);
44184417 doc.append_changes_to_history(view.id);
44194418 }