From 9287846aed173efb450ad20834a2d2031bc8b191 Mon Sep 17 00:00:00 2001 From: remche Date: Wed, 14 Apr 2021 10:28:23 +0200 Subject: [PATCH] add completion subcommands (#99) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add completion subcommands * improve error mgmt, add entry to readme Co-authored-by: Clément DOUIN --- README.md | 27 +++++++++++++++++++++++++++ src/completion/cli.rs | 34 ++++++++++++++++++++++++++++++++++ src/main.rs | 21 +++++++++++++++++---- 3 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 src/completion/cli.rs diff --git a/README.md b/README.md index 4229cd6..f1ccec9 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Minimalist CLI email client, written in Rust. * [Move a message](#move-a-message) * [Delete a message](#delete-a-message) * [Listen to new messages](#listen-to-new-messages) +* [Completions](#completions) * [Interfaces](#interfaces) * [GUI](#gui) * [TUI](#tui) @@ -237,6 +238,32 @@ systemctl --user enable himalaya.service systemctl --user start himalaya.service ``` +## Completions + +```sh +# For bash shells +himalaya bash-completions + +# For zsh shells +himalaya zsh-completions + +# For fish shells +himalaya fish-completions +``` + +Those commands print the generated scripts to the stdout. You will have +to manually save and source them. For example: + +```sh +himalaya bash-completions > himalaya-completions.bash +``` + +```sh +# ~/.bashrc + +source himalaya-completions.bash +``` + ## Interfaces ### GUI diff --git a/src/completion/cli.rs b/src/completion/cli.rs new file mode 100644 index 0000000..056cb6d --- /dev/null +++ b/src/completion/cli.rs @@ -0,0 +1,34 @@ +use clap::{self, App, ArgMatches, SubCommand}; +use error_chain::error_chain; +use std::io; + +error_chain! {} + +pub fn completion_subcmds<'a>() -> Vec> { + vec![ + SubCommand::with_name("bash-completions").about("Generates bash completions script"), + SubCommand::with_name("zsh-completions").about("Generates zsh completions script"), + SubCommand::with_name("fish-completions").about("Generates fish completions script"), + ] +} + +pub fn completion_matches(mut app: App, matches: &ArgMatches) -> Result { + use clap::Shell::*; + + if matches.is_present("bash-completions") { + app.gen_completions_to("himalaya", Bash, &mut io::stdout()); + return Ok(true); + } + + if matches.is_present("zsh-completions") { + app.gen_completions_to("himalaya", Zsh, &mut io::stdout()); + return Ok(true); + } + + if matches.is_present("fish-completions") { + app.gen_completions_to("himalaya", Fish, &mut io::stdout()); + return Ok(true); + } + + Ok(false) +} diff --git a/src/main.rs b/src/main.rs index 291d56b..4bfe70f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,13 +27,17 @@ mod mbox { pub(crate) mod cli; pub(crate) mod model; } +mod completion { + pub(crate) mod cli; +} -use clap; +use clap::{self, App}; use error_chain::error_chain; use log::{debug, error}; use std::env; use crate::{ + completion::cli::{completion_matches, completion_subcmds}, config::cli::account_arg, flag::cli::{flag_matches, flag_subcmds}, imap::cli::{imap_matches, imap_subcmds}, @@ -52,12 +56,13 @@ error_chain! { ImapCli(crate::imap::cli::Error, crate::imap::cli::ErrorKind); MboxCli(crate::mbox::cli::Error, crate::mbox::cli::ErrorKind); MsgCli(crate::msg::cli::Error, crate::msg::cli::ErrorKind); + CompletionCli(crate::completion::cli::Error, crate::completion::cli::ErrorKind); OutputLog(crate::output::log::Error, crate::output::log::ErrorKind); } } -fn run() -> Result<()> { - let matches = clap::App::new(env!("CARGO_PKG_NAME")) +fn build_cli() -> App<'static, 'static> { + clap::App::new(env!("CARGO_PKG_NAME")) .version(env!("CARGO_PKG_VERSION")) .about(env!("CARGO_PKG_DESCRIPTION")) .author(env!("CARGO_PKG_AUTHORS")) @@ -68,7 +73,11 @@ fn run() -> Result<()> { .subcommands(imap_subcmds()) .subcommands(mbox_subcmds()) .subcommands(msg_subcmds()) - .get_matches(); + .subcommands(completion_subcmds()) +} + +fn run() -> Result<()> { + let matches = build_cli().get_matches(); let output_fmt: OutputFmt = matches.value_of("output").unwrap().into(); let log_level: LogLevel = matches.value_of("log").unwrap().into(); @@ -91,6 +100,10 @@ fn run() -> Result<()> { break; } + if completion_matches(build_cli(), &matches)? { + break; + } + msg_matches(&matches)?; break; }