@@ -4150,19 +4150,19 @@ enum ShellBehavior {
41504150}
41514151
41524152fn shell_pipe(cx: &mut Context) {
4153− shell(cx, "pipe:".into(), ShellBehavior::Replace);
4153+ shell_prompt(cx, "pipe:".into(), ShellBehavior::Replace);
41544154}
41554155
41564156fn shell_pipe_to(cx: &mut Context) {
4157− shell(cx, "pipe-to:".into(), ShellBehavior::Ignore);
4157+ shell_prompt(cx, "pipe-to:".into(), ShellBehavior::Ignore);
41584158}
41594159
41604160fn shell_insert_output(cx: &mut Context) {
4161− shell(cx, "insert-output:".into(), ShellBehavior::Insert);
4161+ shell_prompt(cx, "insert-output:".into(), ShellBehavior::Insert);
41624162}
41634163
41644164fn shell_append_output(cx: &mut Context) {
4165− shell(cx, "append-output:".into(), ShellBehavior::Append);
4165+ shell_prompt(cx, "append-output:".into(), ShellBehavior::Append);
41664166}
41674167
41684168fn shell_keep_pipe(cx: &mut Context) {
@@ -4256,65 +4256,69 @@ fn shell_impl(
42564256 Ok((tendril, output.status.success()))
42574257}
42584258
4259−fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
4259+fn shell(cx: &mut compositor::Context, cmd: &str, behavior: &ShellBehavior) {
42604260 let pipe = match behavior {
42614261 ShellBehavior::Replace | ShellBehavior::Ignore => true,
42624262 ShellBehavior::Insert | ShellBehavior::Append => false,
42634263 };
42644264
4265+ let config = cx.editor.config();
4266+ let shell = &config.shell;
4267+ let (view, doc) = current!(cx.editor);
4268+ let selection = doc.selection(view.id);
4269+
4270+ let mut changes = Vec::with_capacity(selection.len());
4271+ let text = doc.text().slice(..);
4272+
4273+ for range in selection.ranges() {
4274+ let fragment = range.fragment(text);
4275+ let (output, success) = match shell_impl(shell, cmd, pipe.then(|| fragment.as_bytes())) {
4276+ Ok(result) => result,
4277+ Err(err) => {
4278+ cx.editor.set_error(err.to_string());
4279+ return;
4280+ }
4281+ };
4282+
4283+ if !success {
4284+ cx.editor.set_error("Command failed");
4285+ return;
4286+ }
4287+
4288+ let (from, to) = match behavior {
4289+ ShellBehavior::Replace => (range.from(), range.to()),
4290+ ShellBehavior::Insert => (range.from(), range.from()),
4291+ ShellBehavior::Append => (range.to(), range.to()),
4292+ _ => (range.from(), range.from()),
4293+ };
4294+ changes.push((from, to, Some(output)));
4295+ }
4296+
4297+ if behavior != &ShellBehavior::Ignore {
4298+ let transaction = Transaction::change(doc.text(), changes.into_iter());
4299+ doc.apply(&transaction, view.id);
4300+ }
4301+
4302+ // after replace cursor may be out of bounds, do this to
4303+ // make sure cursor is in view and update scroll as well
4304+ view.ensure_cursor_in_view(doc, config.scrolloff);
4305+}
4306+
4307+fn shell_prompt(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
42654308 ui::prompt(
42664309 cx,
42674310 prompt,
42684311 Some('|'),
42694312 ui::completers::none,
42704313 move |cx, input: &str, event: PromptEvent| {
4271− let config = cx.editor.config();
4272− let shell = &config.shell;
42734314 if event != PromptEvent::Validate {
42744315 return;
42754316 }
42764317 if input.is_empty() {
42774318 return;
42784319 }
4279− let (view, doc) = current!(cx.editor);
4280− let selection = doc.selection(view.id);
4281−
4282− let mut changes = Vec::with_capacity(selection.len());
4283− let text = doc.text().slice(..);
4284−
4285− for range in selection.ranges() {
4286− let fragment = range.fragment(text);
4287− let (output, success) =
4288− match shell_impl(shell, input, pipe.then(|| fragment.as_bytes())) {
4289− Ok(result) => result,
4290− Err(err) => {
4291− cx.editor.set_error(err.to_string());
4292− return;
4293− }
4294− };
4295−
4296− if !success {
4297− cx.editor.set_error("Command failed");
4298− return;
4299− }
4300−
4301− let (from, to) = match behavior {
4302− ShellBehavior::Replace => (range.from(), range.to()),
4303− ShellBehavior::Insert => (range.from(), range.from()),
4304− ShellBehavior::Append => (range.to(), range.to()),
4305− _ => (range.from(), range.from()),
4306− };
4307− changes.push((from, to, Some(output)));
4308− }
4309−
4310− if behavior != ShellBehavior::Ignore {
4311− let transaction = Transaction::change(doc.text(), changes.into_iter());
4312− doc.apply(&transaction, view.id);
4313− }
43144320
4315− // after replace cursor may be out of bounds, do this to
4316− // make sure cursor is in view and update scroll as well
4317− view.ensure_cursor_in_view(doc, config.scrolloff);
4321+ shell(cx, input, &behavior);
43184322 },
43194323 );
43204324}