on master help sign in
Reimplement keep-pipe, it needs to manipulate selections, not text
commitce7ad2beb5b763e55cc40933d70ca7c7b325292e authorBlaž Hrastnik <blaz@mxxn.io> dateWed 1 Sep 2021, 11:01 (5 years ago) parentdc609ca
2 files changed+78−34
book/src/keymap.md+7−7 helix-term/src/commands.rs+71−27
book/src/keymap.md+7−7
@@ -124,13 +124,13 @@ in reverse, or searching via smartcase.
124124
125125### Shell
126126
127−| Key | Description | Command |
128−| ------ | ----------- | ------- |
129−| `\|` | Pipe each selection through shell command, replacing with output | `shell_pipe` |
130−| `A-\|` | Pipe each selection into shell command, ignoring output | `shell_pipe_to` |
131−| `!` | Run shell command, inserting output before each selection | `shell_insert_output` |
132−| `A-!` | Run shell command, appending output after each selection | `shell_append_output` |
133−| `$` | Pipe each selection into shell command, removing if the command exits >0 | `shell_keep_pipe` |
127+| Key | Description | Command |
128+| ------ | ----------- | ------- |
129+| `\|` | Pipe each selection through shell command, replacing with output | `shell_pipe` |
130+| `A-\|` | Pipe each selection into shell command, ignoring output | `shell_pipe_to` |
131+| `!` | Run shell command, inserting output before each selection | `shell_insert_output` |
132+| `A-!` | Run shell command, appending output after each selection | `shell_append_output` |
133+| `$` | Pipe each selection into shell command, keep selections where command returned 0 | `shell_keep_pipe` |
134134
135135## Select / extend mode
136136
helix-term/src/commands.rs+71−27
@@ -4299,7 +4299,6 @@ enum ShellBehavior {
42994299 Ignore,
43004300 Insert,
43014301 Append,
4302− Filter,
43034302}
43044303
43054304fn shell_pipe(cx: &mut Context) {
@@ -4319,7 +4318,56 @@ fn shell_append_output(cx: &mut Context) {
43194318}
43204319
43214320fn shell_keep_pipe(cx: &mut Context) {
4322− shell(cx, "keep-pipe:".into(), ShellBehavior::Filter);
4321+ let prompt = Prompt::new(
4322+ "keep-pipe:".into(),
4323+ Some('|'),
4324+ |_input: &str| Vec::new(),
4325+ move |cx: &mut compositor::Context, input: &str, event: PromptEvent| {
4326+ let shell = &cx.editor.config.shell;
4327+ if event != PromptEvent::Validate {
4328+ return;
4329+ }
4330+ if input.is_empty() {
4331+ return;
4332+ }
4333+ let (view, doc) = current!(cx.editor);
4334+ let selection = doc.selection(view.id);
4335+
4336+ let mut ranges = SmallVec::with_capacity(selection.len());
4337+ let old_index = selection.primary_index();
4338+ let mut index: Option<usize> = None;
4339+ let text = doc.text().slice(..);
4340+
4341+ for (i, range) in selection.ranges().iter().enumerate() {
4342+ let fragment = range.fragment(text);
4343+ let (_output, success) = match shell_impl(shell, input, Some(fragment.as_bytes())) {
4344+ Ok(result) => result,
4345+ Err(err) => {
4346+ cx.editor.set_error(err.to_string());
4347+ return;
4348+ }
4349+ };
4350+
4351+ // if the process exits successfully, keep the selection
4352+ if success {
4353+ ranges.push(*range);
4354+ if i >= old_index && index.is_none() {
4355+ index = Some(ranges.len() - 1);
4356+ }
4357+ }
4358+ }
4359+
4360+ if ranges.is_empty() {
4361+ cx.editor.set_error("No selections remaining".to_string());
4362+ return;
4363+ }
4364+
4365+ let index = index.unwrap_or_else(|| ranges.len() - 1);
4366+ doc.set_selection(view.id, Selection::new(ranges, index));
4367+ },
4368+ );
4369+
4370+ cx.push_layer(Box::new(prompt));
43234371}
43244372
43254373fn shell_impl(
@@ -4329,6 +4377,10 @@ fn shell_impl(
43294377) -> anyhow::Result<(Tendril, bool)> {
43304378 use std::io::Write;
43314379 use std::process::{Command, Stdio};
4380+ if shell.is_empty() {
4381+ bail!("No shell set");
4382+ }
4383+
43324384 let mut process = match Command::new(&shell[0])
43334385 .args(&shell[1..])
43344386 .arg(cmd)
@@ -4349,11 +4401,8 @@ fn shell_impl(
43494401 }
43504402 let output = process.wait_with_output()?;
43514403
4352− if !output.status.success() {
4353− if !output.stderr.is_empty() {
4354− log::error!("Shell error: {}", String::from_utf8_lossy(&output.stderr));
4355− }
4356− bail!("Command failed");
4404+ if !output.stderr.is_empty() {
4405+ log::error!("Shell error: {}", String::from_utf8_lossy(&output.stderr));
43574406 }
43584407
43594408 let tendril = Tendril::try_from_byte_slice(&output.stdout)
@@ -4362,12 +4411,8 @@ fn shell_impl(
43624411}
43634412
43644413fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
4365− if cx.editor.config.shell.is_empty() {
4366− cx.editor.set_error("No shell set".to_owned());
4367− return;
4368− }
43694414 let pipe = match behavior {
4370− ShellBehavior::Replace | ShellBehavior::Ignore | ShellBehavior::Filter => true,
4415+ ShellBehavior::Replace | ShellBehavior::Ignore => true,
43714416 ShellBehavior::Insert | ShellBehavior::Append => false,
43724417 };
43734418 let prompt = Prompt::new(
@@ -4379,6 +4424,9 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
43794424 if event != PromptEvent::Validate {
43804425 return;
43814426 }
4427+ if input.is_empty() {
4428+ return;
4429+ }
43824430 let (view, doc) = current!(cx.editor);
43834431 let selection = doc.selection(view.id);
43844432
@@ -4396,22 +4444,18 @@ fn shell(cx: &mut Context, prompt: Cow<'static, str>, behavior: ShellBehavior) {
43964444 }
43974445 };
43984446
4399− if behavior != ShellBehavior::Filter {
4400− let (from, to) = match behavior {
4401− ShellBehavior::Replace => (range.from(), range.to()),
4402− ShellBehavior::Insert => (range.from(), range.from()),
4403− ShellBehavior::Append => (range.to(), range.to()),
4404− _ => (range.from(), range.from()),
4405− };
4406− changes.push((from, to, Some(output)));
4407− } else {
4408− // if the process exits successfully, keep the selection, otherwise delete it.
4409− changes.push((
4410− range.from(),
4411− if success { range.from() } else { range.to() },
4412− None,
4413− ));
4447+ if !success {
4448+ cx.editor.set_error("Command failed".to_string());
4449+ return;
44144450 }
4451+
4452+ let (from, to) = match behavior {
4453+ ShellBehavior::Replace => (range.from(), range.to()),
4454+ ShellBehavior::Insert => (range.from(), range.from()),
4455+ ShellBehavior::Append => (range.to(), range.to()),
4456+ _ => (range.from(), range.from()),
4457+ };
4458+ changes.push((from, to, Some(output)));
44154459 }
44164460
44174461 if behavior != ShellBehavior::Ignore {