diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index ac2102020..df0841b6f 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -63,3 +63,4 @@ | `:config-reload` | Refreshes helix's config. | | `:config-open` | Open the helix config.toml file. | | `:pipe` | Pipe each selection to the shell command. | +| `:run-shell-command`, `:sh` | Run a shell command | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 394760a2f..373c70180 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1116,6 +1116,43 @@ fn pipe( Ok(()) } +fn run_shell_command( + cx: &mut compositor::Context, + args: &[Cow], + _event: PromptEvent, +) -> anyhow::Result<()> { + let shell = &cx.editor.config().shell; + let (output, success) = shell_impl(shell, &args.join(" "), None)?; + if success { + cx.editor.set_status("Command succeed"); + } else { + cx.editor.set_error("Command failed"); + } + + if !output.is_empty() { + let callback = async move { + let call: job::Callback = + Box::new(move |editor: &mut Editor, compositor: &mut Compositor| { + let contents = ui::Markdown::new( + format!("```sh\n{}\n```", output), + editor.syn_loader.clone(), + ); + let mut popup = Popup::new("shell", contents); + popup.set_position(Some(helix_core::Position::new( + editor.cursor().0.unwrap_or_default().row, + 2, + ))); + compositor.replace_or_push("shell", popup); + }); + Ok(call) + }; + + cx.jobs.callback(callback); + } + + Ok(()) +} + pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ TypableCommand { name: "quit", @@ -1561,6 +1598,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: pipe, completer: None, }, + TypableCommand { + name: "run-shell-command", + aliases: &["sh"], + doc: "Run a shell command", + fun: run_shell_command, + completer: Some(completers::directory), + }, ]; pub static TYPABLE_COMMAND_MAP: Lazy> =