From 4c4ecd54359b52f463385b8b0e11634ffa5c19a5 Mon Sep 17 00:00:00 2001 From: Isak Johansson Date: Thu, 23 Apr 2020 12:32:59 +0200 Subject: [PATCH] Add Shell basic shell completion. I had to change some of the cli options around to make the shell completions more usable. To the user the cli should act the same however. Added build script for generating completion files to `SHELL_COMPLETIONS_DIR` or `completions`. TODO installation script for completion files. --- .gitignore | 1 + Cargo.toml | 3 +++ build.rs | 16 ++++++++++++++++ src/cli.rs | 3 +-- src/error.rs | 3 +++ src/lib.rs | 2 +- src/main.rs | 13 +++++++++---- 7 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 build.rs diff --git a/.gitignore b/.gitignore index e0abcb3..f735749 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /.idea /target +/completions **/*.rs.bk diff --git a/Cargo.toml b/Cargo.toml index 5b169fa..47727df 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,9 @@ edition = "2018" autotests = false +[build-dependencies] +structopt = "0.3" + [dependencies] toml = "0.4" serde = { version = '1.0.83', features = ['derive'] } diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..90fc245 --- /dev/null +++ b/build.rs @@ -0,0 +1,16 @@ +use std::fs; +use structopt::clap::Shell; + +include!("src/cli.rs"); + +fn main() { + let pkg_name = env!("CARGO_PKG_NAME"); + + if let Ok(outdir) = std::env::var("SHELL_COMPLETIONS_DIR") { + + fs::create_dir_all(&outdir).unwrap(); + Cli::clap().gen_completions(pkg_name, Shell::Bash, &outdir); + Cli::clap().gen_completions(pkg_name, Shell::Fish, &outdir); + Cli::clap().gen_completions(pkg_name, Shell::Zsh, &outdir); + } +} diff --git a/src/cli.rs b/src/cli.rs index 229d1fc..6395e0e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -98,14 +98,13 @@ pub struct CliOpts { } #[derive(Debug, StructOpt)] -#[structopt(setting = AppSettings::SubcommandsNegateReqs, author)] +#[structopt(setting = AppSettings::SubcommandsNegateReqs, setting = AppSettings::ArgRequiredElseHelp, author)] /// A simple script management CLI pub struct Cli { #[structopt(flatten)] pub opts: CliOpts, /// The alias or name for the script. - #[structopt(required_unless = "cmd")] pub alias: Option, /// Pier subcommands diff --git a/src/error.rs b/src/error.rs index 1ecc5ce..78b6435 100644 --- a/src/error.rs +++ b/src/error.rs @@ -28,6 +28,9 @@ pub enum PierError { source: std::io::Error, path: PathBuf, }, + #[snafu(display("error: AliasOrSubcommandRequired: No alias or subcommand supplied."))] + AliasOrSubcommandRequired, + #[snafu(display("error: AliasNotFound: No script found by alias {}", alias))] AliasNotFound { alias: String }, diff --git a/src/lib.rs b/src/lib.rs index 640f849..703ba79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ pub mod cli; mod config; pub mod error; use config::Config; -mod macros; +pub mod macros; mod defaults; use defaults::*; pub mod script; diff --git a/src/main.rs b/src/main.rs index fe681cf..2047317 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,19 @@ +use snafu::ensure; use std::process; +use structopt::clap::Shell; use structopt::StructOpt; use pier::{ cli::{Cli, CliSubcommand}, - open_editor, + error::*, + open_editor, pier_err, script::Script, Pier, Result, }; fn main() { let opt = Cli::from_args(); - + //Cli::clap().gen_completions(env!("CARGO_PKG_NAME"), Shell::Zsh, "target"); if let Err(err) = handle_subcommands(opt) { eprintln!("{}", err); // Only exits the process once the used memory has been cleaned up. @@ -73,8 +76,10 @@ fn handle_subcommands(cli: Cli) -> Result<()> { }; } else { let arg = ""; - let alias = &cli.alias.expect("Alias is required unless subcommand."); - pier.run_script(alias, arg)?; + match &cli.alias { + Some(alias) => pier.run_script(&alias, arg)?, + None => pier_err!(PierError::AliasOrSubcommandRequired), + } } Ok(())