mirror of
https://github.com/atuinsh/atuin.git
synced 2025-08-04 18:58:13 +00:00
feat: Binaries as subcommands (#2661)
* Run 'atuin-<subcmd>' if present when a given subcommand is not recognized * Send errors to stderr * Use String instead of OsString for external subcommands * Remove unused import * Move external subcommand handling up a level * Clippy
This commit is contained in:
parent
a82a001391
commit
653894d359
2 changed files with 78 additions and 0 deletions
72
crates/atuin/src/command/external.rs
Normal file
72
crates/atuin/src/command/external.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use std::fmt::Write as _;
|
||||
use std::process::Command;
|
||||
use std::{io, process};
|
||||
|
||||
use clap::CommandFactory;
|
||||
use clap::builder::{StyledStr, Styles};
|
||||
use eyre::Result;
|
||||
|
||||
use crate::Atuin;
|
||||
|
||||
pub fn run(args: &[String]) -> Result<()> {
|
||||
let subcommand = &args[0];
|
||||
let bin = format!("atuin-{subcommand}");
|
||||
let mut cmd = Command::new(&bin);
|
||||
cmd.args(&args[1..]);
|
||||
|
||||
let spawn_result = match cmd.spawn() {
|
||||
Ok(child) => Ok(child),
|
||||
Err(e) => match e.kind() {
|
||||
io::ErrorKind::NotFound => {
|
||||
let output = render_not_found(subcommand, &bin);
|
||||
Err(output)
|
||||
}
|
||||
_ => Err(e.to_string().into()),
|
||||
},
|
||||
};
|
||||
|
||||
match spawn_result {
|
||||
Ok(mut child) => {
|
||||
let status = child.wait()?;
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
process::exit(status.code().unwrap_or(1));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}", e.ansi());
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render_not_found(subcommand: &str, bin: &str) -> StyledStr {
|
||||
let mut output = StyledStr::new();
|
||||
let styles = Styles::styled();
|
||||
let mut atuin_cmd = Atuin::command();
|
||||
let usage = atuin_cmd.render_usage();
|
||||
|
||||
let error = styles.get_error();
|
||||
let invalid = styles.get_invalid();
|
||||
let literal = styles.get_literal();
|
||||
|
||||
let _ = write!(output, "{error}error:{error:#} ");
|
||||
let _ = write!(
|
||||
output,
|
||||
"unrecognized subcommand '{invalid}{subcommand}{invalid:#}' "
|
||||
);
|
||||
let _ = write!(
|
||||
output,
|
||||
"and no executable named '{invalid}{bin}{invalid:#}' found in your PATH"
|
||||
);
|
||||
let _ = write!(output, "\n\n");
|
||||
let _ = write!(output, "{usage}");
|
||||
let _ = write!(output, "\n\n");
|
||||
let _ = write!(
|
||||
output,
|
||||
"For more information, try '{literal}--help{literal:#}'."
|
||||
);
|
||||
|
||||
output
|
||||
}
|
|
@ -14,6 +14,8 @@ mod contributors;
|
|||
|
||||
mod gen_completions;
|
||||
|
||||
mod external;
|
||||
|
||||
#[derive(Subcommand)]
|
||||
#[command(infer_subcommands = true)]
|
||||
pub enum AtuinCmd {
|
||||
|
@ -33,6 +35,9 @@ pub enum AtuinCmd {
|
|||
|
||||
/// Generate shell completions
|
||||
GenCompletions(gen_completions::Cmd),
|
||||
|
||||
#[command(external_subcommand)]
|
||||
External(Vec<String>),
|
||||
}
|
||||
|
||||
impl AtuinCmd {
|
||||
|
@ -60,6 +65,7 @@ impl AtuinCmd {
|
|||
Ok(())
|
||||
}
|
||||
Self::GenCompletions(gen_completions) => gen_completions.run(),
|
||||
Self::External(args) => external::run(&args),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue