From fc66cf0e5917c166989360408d265133020fd510 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Thu, 1 Feb 2024 14:00:33 +0100 Subject: Upgrade clap_complete to 4.4.9 This project was upgraded with external_updater. Usage: tools/external_updater/updater.sh update external/rust/crates/clap_complete For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md Test: TreeHugger Change-Id: I8d6c3a390a21c87aed54d0714d84d92cce39db12 --- src/dynamic/completer.rs | 4 +-- src/dynamic/mod.rs | 2 ++ src/dynamic/shells/bash.rs | 2 +- src/dynamic/shells/fish.rs | 2 +- src/dynamic/shells/mod.rs | 6 ++++ src/dynamic/shells/shell.rs | 2 +- src/generator/mod.rs | 4 +-- src/generator/utils.rs | 2 +- src/lib.rs | 1 + src/shells/bash.rs | 72 +++++++++++++++++++++++++++++++-------------- 10 files changed, 67 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/dynamic/completer.rs b/src/dynamic/completer.rs index 8c8cb93..232dd4b 100644 --- a/src/dynamic/completer.rs +++ b/src/dynamic/completer.rs @@ -16,7 +16,7 @@ pub trait Completer { completer: &str, buf: &mut dyn std::io::Write, ) -> Result<(), std::io::Error>; - /// Complete the command + /// Complete the given command fn write_complete( &self, cmd: &mut clap::Command, @@ -26,7 +26,7 @@ pub trait Completer { ) -> Result<(), std::io::Error>; } -/// Complete the command specified +/// Complete the given command pub fn complete( cmd: &mut clap::Command, args: Vec, diff --git a/src/dynamic/mod.rs b/src/dynamic/mod.rs index f7c9857..ed72565 100644 --- a/src/dynamic/mod.rs +++ b/src/dynamic/mod.rs @@ -1,4 +1,6 @@ //! Complete commands within shells +//! +//! For quick-start, see [`shells::CompleteCommand`] mod completer; diff --git a/src/dynamic/shells/bash.rs b/src/dynamic/shells/bash.rs index 43c128e..1308e67 100644 --- a/src/dynamic/shells/bash.rs +++ b/src/dynamic/shells/bash.rs @@ -1,6 +1,6 @@ use unicode_xid::UnicodeXID as _; -/// Bash completions +/// Completion support for Bash #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Bash; diff --git a/src/dynamic/shells/fish.rs b/src/dynamic/shells/fish.rs index 9d7e8c6..cfb9519 100644 --- a/src/dynamic/shells/fish.rs +++ b/src/dynamic/shells/fish.rs @@ -1,4 +1,4 @@ -/// Fish completions +/// Completion support for Fish #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct Fish; diff --git a/src/dynamic/shells/mod.rs b/src/dynamic/shells/mod.rs index 54d23a3..6cfed97 100644 --- a/src/dynamic/shells/mod.rs +++ b/src/dynamic/shells/mod.rs @@ -13,20 +13,26 @@ use std::io::Write as _; use crate::dynamic::Completer as _; +/// A subcommand definition to `flatten` into your CLI +/// +/// This provides a one-stop solution for integrating completions into your CLI #[derive(clap::Subcommand)] #[allow(missing_docs)] #[derive(Clone, Debug)] +#[command(about = None, long_about = None)] pub enum CompleteCommand { /// Register shell completions for this program #[command(hide = true)] Complete(CompleteArgs), } +/// Generally used via [`CompleteCommand`] #[derive(clap::Args)] #[command(arg_required_else_help = true)] #[command(group = clap::ArgGroup::new("complete").multiple(true).conflicts_with("register"))] #[allow(missing_docs)] #[derive(Clone, Debug)] +#[command(about = None, long_about = None)] pub struct CompleteArgs { /// Specify shell to complete for #[arg(long)] diff --git a/src/dynamic/shells/shell.rs b/src/dynamic/shells/shell.rs index a9f48ce..c36d2a2 100644 --- a/src/dynamic/shells/shell.rs +++ b/src/dynamic/shells/shell.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use clap::builder::PossibleValue; use clap::ValueEnum; -/// Shell with auto-generated completion script available. +/// Completion support for built-in shells #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] #[non_exhaustive] pub enum Shell { diff --git a/src/generator/mod.rs b/src/generator/mod.rs index a371f68..415913e 100644 --- a/src/generator/mod.rs +++ b/src/generator/mod.rs @@ -36,7 +36,7 @@ pub trait Generator { /// ``` fn file_name(&self, name: &str) -> String; - /// Generates output out of [`clap::Command`](Command). + /// Generates output out of [`clap::Command`]. /// /// # Panics /// @@ -44,7 +44,7 @@ pub trait Generator { /// /// # Examples /// - /// The following example generator displays the [`clap::Command`](Command) + /// The following example generator displays the [`clap::Command`] /// as if it is printed using [`std::println`]. /// /// ``` diff --git a/src/generator/utils.rs b/src/generator/utils.rs index ca76d18..6ea10d2 100644 --- a/src/generator/utils.rs +++ b/src/generator/utils.rs @@ -109,7 +109,7 @@ pub fn longs_and_visible_aliases(p: &Command) -> Vec { .collect() } -/// Gets all the flags of a [`clap::Command`](Command). +/// Gets all the flags of a [`clap::Command`]. /// Includes `help` and `version` depending on the [`clap::Command`] settings. pub fn flags(p: &Command) -> Vec { debug!("flags: name={}", p.get_name()); diff --git a/src/lib.rs b/src/lib.rs index a442882..18fb282 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")] #![doc = include_str!("../README.md")] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_docs, trivial_casts, unused_allocation, trivial_numeric_casts)] #![forbid(unsafe_code)] #![allow(clippy::needless_doctest_main)] diff --git a/src/shells/bash.rs b/src/shells/bash.rs index 2a97e1d..f390853 100644 --- a/src/shells/bash.rs +++ b/src/shells/bash.rs @@ -18,6 +18,8 @@ impl Generator for Bash { .get_bin_name() .expect("crate::generate should have set the bin_name"); + let fn_name = bin_name.replace('-', "__"); + w!( buf, format!( @@ -58,13 +60,17 @@ impl Generator for Bash { esac }} -complete -F _{name} -o nosort -o bashdefault -o default {name} +if [[ \"${{BASH_VERSINFO[0]}}\" -eq 4 && \"${{BASH_VERSINFO[1]}}\" -ge 4 || \"${{BASH_VERSINFO[0]}}\" -gt 4 ]]; then + complete -F _{name} -o nosort -o bashdefault -o default {name} +else + complete -F _{name} -o bashdefault -o default {name} +fi ", name = bin_name, - cmd = bin_name.replace('-', "__"), + cmd = fn_name, name_opts = all_options_for_path(cmd, bin_name), name_opts_details = option_details_for_path(cmd, bin_name), - subcmds = all_subcommands(cmd), + subcmds = all_subcommands(cmd, &fn_name), subcmd_details = subcommand_details(cmd) ) .as_bytes() @@ -72,7 +78,7 @@ complete -F _{name} -o nosort -o bashdefault -o default {name} } } -fn all_subcommands(cmd: &Command) -> String { +fn all_subcommands(cmd: &Command, parent_fn_name: &str) -> String { debug!("all_subcommands"); fn add_command( @@ -102,9 +108,8 @@ fn all_subcommands(cmd: &Command) -> String { } } let mut subcmds = vec![]; - let fn_name = cmd.get_name().replace('-', "__"); for subcmd in cmd.get_subcommands() { - add_command(&fn_name, subcmd, &mut subcmds); + add_command(parent_fn_name, subcmd, &mut subcmds); } subcmds.sort(); @@ -164,29 +169,50 @@ fn option_details_for_path(cmd: &Command, path: &str) -> String { let mut opts = vec![String::new()]; for o in p.get_opts() { + let compopt = match o.get_value_hint() { + ValueHint::FilePath => Some("compopt -o filenames"), + ValueHint::DirPath => Some("compopt -o plusdirs"), + ValueHint::Other => Some("compopt -o nospace"), + _ => None, + }; + if let Some(longs) = o.get_long_and_visible_aliases() { opts.extend(longs.iter().map(|long| { - format!( - "--{}) - COMPREPLY=({}) - return 0 - ;;", - long, - vals_for(o) - ) + let mut v = vec![ + format!("--{})", long), + format!("COMPREPLY=({})", vals_for(o)), + ]; + + if let Some(copt) = compopt { + v.extend([ + r#"if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then"#.to_string(), + format!(" {}", copt), + "fi".to_string(), + ]); + } + + v.extend(["return 0", ";;"].iter().map(|s| s.to_string())); + v.join("\n ") })); } if let Some(shorts) = o.get_short_and_visible_aliases() { opts.extend(shorts.iter().map(|short| { - format!( - "-{}) - COMPREPLY=({}) - return 0 - ;;", - short, - vals_for(o) - ) + let mut v = vec![ + format!("-{})", short), + format!("COMPREPLY=({})", vals_for(o)), + ]; + + if let Some(copt) = compopt { + v.extend([ + r#"if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then"#.to_string(), + format!(" {}", copt), + "fi".to_string(), + ]); + } + + v.extend(["return 0", ";;"].iter().map(|s| s.to_string())); + v.join("\n ") })); } } @@ -206,6 +232,8 @@ fn vals_for(o: &Arg) -> String { .collect::>() .join(" ") ) + } else if o.get_value_hint() == ValueHint::DirPath { + String::from("") // should be empty to avoid duplicate candidates } else if o.get_value_hint() == ValueHint::Other { String::from("\"${cur}\"") } else { -- cgit v1.2.3