summaryrefslogtreecommitdiffstats
path: root/vendor/clap_complete/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clap_complete/src')
-rw-r--r--vendor/clap_complete/src/dynamic.rs551
-rw-r--r--vendor/clap_complete/src/generator/mod.rs12
-rw-r--r--vendor/clap_complete/src/generator/utils.rs49
-rw-r--r--vendor/clap_complete/src/lib.rs12
-rw-r--r--vendor/clap_complete/src/macros.rs4
-rw-r--r--vendor/clap_complete/src/shells/bash.rs76
-rw-r--r--vendor/clap_complete/src/shells/elvish.rs16
-rw-r--r--vendor/clap_complete/src/shells/fish.rs29
-rw-r--r--vendor/clap_complete/src/shells/powershell.rs16
-rw-r--r--vendor/clap_complete/src/shells/shell.rs80
-rw-r--r--vendor/clap_complete/src/shells/zsh.rs45
11 files changed, 765 insertions, 125 deletions
diff --git a/vendor/clap_complete/src/dynamic.rs b/vendor/clap_complete/src/dynamic.rs
new file mode 100644
index 000000000..929841ec8
--- /dev/null
+++ b/vendor/clap_complete/src/dynamic.rs
@@ -0,0 +1,551 @@
+//! Complete commands within shells
+
+/// Complete commands within bash
+pub mod bash {
+ use std::ffi::OsString;
+ use std::io::Write;
+
+ use unicode_xid::UnicodeXID;
+
+ #[derive(clap::Subcommand)]
+ #[command(hide = true)]
+ #[allow(missing_docs)]
+ #[derive(Clone, Debug)]
+ pub enum CompleteCommand {
+ /// Register shell completions for this program
+ Complete(CompleteArgs),
+ }
+
+ #[derive(clap::Args)]
+ #[command(group = clap::ArgGroup::new("complete").multiple(true).conflicts_with("register"))]
+ #[allow(missing_docs)]
+ #[derive(Clone, Debug)]
+ pub struct CompleteArgs {
+ /// Path to write completion-registration to
+ #[arg(long, required = true)]
+ register: Option<std::path::PathBuf>,
+
+ #[arg(
+ long,
+ required = true,
+ value_name = "COMP_CWORD",
+ hide_short_help = true,
+ group = "complete"
+ )]
+ index: Option<usize>,
+
+ #[arg(long, hide_short_help = true, group = "complete")]
+ ifs: Option<String>,
+
+ #[arg(
+ long = "type",
+ required = true,
+ hide_short_help = true,
+ group = "complete"
+ )]
+ comp_type: Option<CompType>,
+
+ #[arg(long, hide_short_help = true, group = "complete")]
+ space: bool,
+
+ #[arg(
+ long,
+ conflicts_with = "space",
+ hide_short_help = true,
+ group = "complete"
+ )]
+ no_space: bool,
+
+ #[arg(raw = true, hide_short_help = true, group = "complete")]
+ comp_words: Vec<OsString>,
+ }
+
+ impl CompleteCommand {
+ /// Process the completion request
+ pub fn complete(&self, cmd: &mut clap::Command) -> std::convert::Infallible {
+ self.try_complete(cmd).unwrap_or_else(|e| e.exit());
+ std::process::exit(0)
+ }
+
+ /// Process the completion request
+ pub fn try_complete(&self, cmd: &mut clap::Command) -> clap::error::Result<()> {
+ debug!("CompleteCommand::try_complete: {:?}", self);
+ let CompleteCommand::Complete(args) = self;
+ if let Some(out_path) = args.register.as_deref() {
+ let mut buf = Vec::new();
+ let name = cmd.get_name();
+ let bin = cmd.get_bin_name().unwrap_or_else(|| cmd.get_name());
+ register(name, [bin], bin, &Behavior::default(), &mut buf)?;
+ if out_path == std::path::Path::new("-") {
+ std::io::stdout().write_all(&buf)?;
+ } else if out_path.is_dir() {
+ let out_path = out_path.join(file_name(name));
+ std::fs::write(out_path, buf)?;
+ } else {
+ std::fs::write(out_path, buf)?;
+ }
+ } else {
+ let index = args.index.unwrap_or_default();
+ let comp_type = args.comp_type.unwrap_or_default();
+ let space = match (args.space, args.no_space) {
+ (true, false) => Some(true),
+ (false, true) => Some(false),
+ (true, true) => {
+ unreachable!("`--space` and `--no-space` set, clap should prevent this")
+ }
+ (false, false) => None,
+ }
+ .unwrap();
+ let current_dir = std::env::current_dir().ok();
+ let completions = complete(
+ cmd,
+ args.comp_words.clone(),
+ index,
+ comp_type,
+ space,
+ current_dir.as_deref(),
+ )?;
+
+ let mut buf = Vec::new();
+ for (i, completion) in completions.iter().enumerate() {
+ if i != 0 {
+ write!(&mut buf, "{}", args.ifs.as_deref().unwrap_or("\n"))?;
+ }
+ write!(&mut buf, "{}", completion.to_string_lossy())?;
+ }
+ std::io::stdout().write_all(&buf)?;
+ }
+
+ Ok(())
+ }
+ }
+
+ /// The recommended file name for the registration code
+ pub fn file_name(name: &str) -> String {
+ format!("{}.bash", name)
+ }
+
+ /// Define the completion behavior
+ pub enum Behavior {
+ /// Bare bones behavior
+ Minimal,
+ /// Fallback to readline behavior when no matches are generated
+ Readline,
+ /// Customize bash's completion behavior
+ Custom(String),
+ }
+
+ impl Default for Behavior {
+ fn default() -> Self {
+ Self::Readline
+ }
+ }
+
+ /// Generate code to register the dynamic completion
+ pub fn register(
+ name: &str,
+ executables: impl IntoIterator<Item = impl AsRef<str>>,
+ completer: &str,
+ behavior: &Behavior,
+ buf: &mut dyn Write,
+ ) -> Result<(), std::io::Error> {
+ let escaped_name = name.replace('-', "_");
+ debug_assert!(
+ escaped_name.chars().all(|c| c.is_xid_continue()),
+ "`name` must be an identifier, got `{}`",
+ escaped_name
+ );
+ let mut upper_name = escaped_name.clone();
+ upper_name.make_ascii_uppercase();
+
+ let executables = executables
+ .into_iter()
+ .map(|s| shlex::quote(s.as_ref()).into_owned())
+ .collect::<Vec<_>>()
+ .join(" ");
+
+ let options = match behavior {
+ Behavior::Minimal => "-o nospace -o bashdefault",
+ Behavior::Readline => "-o nospace -o default -o bashdefault",
+ Behavior::Custom(c) => c.as_str(),
+ };
+
+ let completer = shlex::quote(completer);
+
+ let script = r#"
+_clap_complete_NAME() {
+ local IFS=$'\013'
+ local SUPPRESS_SPACE=0
+ if compopt +o nospace 2> /dev/null; then
+ SUPPRESS_SPACE=1
+ fi
+ if [[ ${SUPPRESS_SPACE} == 1 ]]; then
+ SPACE_ARG="--no-space"
+ else
+ SPACE_ARG="--space"
+ fi
+ COMPREPLY=( $("COMPLETER" complete --index ${COMP_CWORD} --type ${COMP_TYPE} ${SPACE_ARG} --ifs="$IFS" -- "${COMP_WORDS[@]}") )
+ if [[ $? != 0 ]]; then
+ unset COMPREPLY
+ elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then
+ compopt -o nospace
+ fi
+}
+complete OPTIONS -F _clap_complete_NAME EXECUTABLES
+"#
+ .replace("NAME", &escaped_name)
+ .replace("EXECUTABLES", &executables)
+ .replace("OPTIONS", options)
+ .replace("COMPLETER", &completer)
+ .replace("UPPER", &upper_name);
+
+ writeln!(buf, "{}", script)?;
+ Ok(())
+ }
+
+ /// Type of completion attempted that caused a completion function to be called
+ #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+ #[non_exhaustive]
+ pub enum CompType {
+ /// Normal completion
+ Normal,
+ /// List completions after successive tabs
+ Successive,
+ /// List alternatives on partial word completion
+ Alternatives,
+ /// List completions if the word is not unmodified
+ Unmodified,
+ /// Menu completion
+ Menu,
+ }
+
+ impl clap::ValueEnum for CompType {
+ fn value_variants<'a>() -> &'a [Self] {
+ &[
+ Self::Normal,
+ Self::Successive,
+ Self::Alternatives,
+ Self::Unmodified,
+ Self::Menu,
+ ]
+ }
+ fn to_possible_value(&self) -> ::std::option::Option<clap::builder::PossibleValue> {
+ match self {
+ Self::Normal => {
+ let value = "9";
+ debug_assert_eq!(b'\t'.to_string(), value);
+ Some(
+ clap::builder::PossibleValue::new(value)
+ .alias("normal")
+ .help("Normal completion"),
+ )
+ }
+ Self::Successive => {
+ let value = "63";
+ debug_assert_eq!(b'?'.to_string(), value);
+ Some(
+ clap::builder::PossibleValue::new(value)
+ .alias("successive")
+ .help("List completions after successive tabs"),
+ )
+ }
+ Self::Alternatives => {
+ let value = "33";
+ debug_assert_eq!(b'!'.to_string(), value);
+ Some(
+ clap::builder::PossibleValue::new(value)
+ .alias("alternatives")
+ .help("List alternatives on partial word completion"),
+ )
+ }
+ Self::Unmodified => {
+ let value = "64";
+ debug_assert_eq!(b'@'.to_string(), value);
+ Some(
+ clap::builder::PossibleValue::new(value)
+ .alias("unmodified")
+ .help("List completions if the word is not unmodified"),
+ )
+ }
+ Self::Menu => {
+ let value = "37";
+ debug_assert_eq!(b'%'.to_string(), value);
+ Some(
+ clap::builder::PossibleValue::new(value)
+ .alias("menu")
+ .help("Menu completion"),
+ )
+ }
+ }
+ }
+ }
+
+ impl Default for CompType {
+ fn default() -> Self {
+ Self::Normal
+ }
+ }
+
+ /// Complete the command specified
+ pub fn complete(
+ cmd: &mut clap::Command,
+ args: Vec<std::ffi::OsString>,
+ arg_index: usize,
+ _comp_type: CompType,
+ _trailing_space: bool,
+ current_dir: Option<&std::path::Path>,
+ ) -> Result<Vec<std::ffi::OsString>, std::io::Error> {
+ cmd.build();
+
+ let raw_args = clap_lex::RawArgs::new(args.into_iter());
+ let mut cursor = raw_args.cursor();
+ let mut target_cursor = raw_args.cursor();
+ raw_args.seek(
+ &mut target_cursor,
+ clap_lex::SeekFrom::Start(arg_index as u64),
+ );
+ // As we loop, `cursor` will always be pointing to the next item
+ raw_args.next_os(&mut target_cursor);
+
+ // TODO: Multicall support
+ if !cmd.is_no_binary_name_set() {
+ raw_args.next_os(&mut cursor);
+ }
+
+ let mut current_cmd = &*cmd;
+ let mut pos_index = 1;
+ let mut is_escaped = false;
+ while let Some(arg) = raw_args.next(&mut cursor) {
+ if cursor == target_cursor {
+ return complete_arg(&arg, current_cmd, current_dir, pos_index, is_escaped);
+ }
+
+ debug!(
+ "complete::next: Begin parsing '{:?}' ({:?})",
+ arg.to_value_os(),
+ arg.to_value_os().as_raw_bytes()
+ );
+
+ if let Ok(value) = arg.to_value() {
+ if let Some(next_cmd) = current_cmd.find_subcommand(value) {
+ current_cmd = next_cmd;
+ pos_index = 0;
+ continue;
+ }
+ }
+
+ if is_escaped {
+ pos_index += 1;
+ } else if arg.is_escape() {
+ is_escaped = true;
+ } else if let Some(_long) = arg.to_long() {
+ } else if let Some(_short) = arg.to_short() {
+ } else {
+ pos_index += 1;
+ }
+ }
+
+ Err(std::io::Error::new(
+ std::io::ErrorKind::Other,
+ "No completion generated",
+ ))
+ }
+
+ fn complete_arg(
+ arg: &clap_lex::ParsedArg<'_>,
+ cmd: &clap::Command,
+ current_dir: Option<&std::path::Path>,
+ pos_index: usize,
+ is_escaped: bool,
+ ) -> Result<Vec<std::ffi::OsString>, std::io::Error> {
+ debug!(
+ "complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={}, is_escaped={}",
+ arg,
+ cmd.get_name(),
+ current_dir,
+ pos_index,
+ is_escaped
+ );
+ let mut completions = Vec::new();
+
+ if !is_escaped {
+ if let Some((flag, value)) = arg.to_long() {
+ if let Ok(flag) = flag {
+ if let Some(value) = value {
+ if let Some(arg) = cmd.get_arguments().find(|a| a.get_long() == Some(flag))
+ {
+ completions.extend(
+ complete_arg_value(value.to_str().ok_or(value), arg, current_dir)
+ .into_iter()
+ .map(|os| {
+ // HACK: Need better `OsStr` manipulation
+ format!("--{}={}", flag, os.to_string_lossy()).into()
+ }),
+ )
+ }
+ } else {
+ completions.extend(
+ crate::generator::utils::longs_and_visible_aliases(cmd)
+ .into_iter()
+ .filter_map(|f| {
+ f.starts_with(flag).then(|| format!("--{}", f).into())
+ }),
+ );
+ }
+ }
+ } else if arg.is_escape() || arg.is_stdio() || arg.is_empty() {
+ // HACK: Assuming knowledge of is_escape / is_stdio
+ completions.extend(
+ crate::generator::utils::longs_and_visible_aliases(cmd)
+ .into_iter()
+ .map(|f| format!("--{}", f).into()),
+ );
+ }
+
+ if arg.is_empty() || arg.is_stdio() || arg.is_short() {
+ // HACK: Assuming knowledge of is_stdio
+ completions.extend(
+ crate::generator::utils::shorts_and_visible_aliases(cmd)
+ .into_iter()
+ // HACK: Need better `OsStr` manipulation
+ .map(|f| format!("{}{}", arg.to_value_os().to_str_lossy(), f).into()),
+ );
+ }
+ }
+
+ if let Some(positional) = cmd
+ .get_positionals()
+ .find(|p| p.get_index() == Some(pos_index))
+ {
+ completions.extend(complete_arg_value(arg.to_value(), positional, current_dir));
+ }
+
+ if let Ok(value) = arg.to_value() {
+ completions.extend(complete_subcommand(value, cmd));
+ }
+
+ Ok(completions)
+ }
+
+ fn complete_arg_value(
+ value: Result<&str, &clap_lex::RawOsStr>,
+ arg: &clap::Arg,
+ current_dir: Option<&std::path::Path>,
+ ) -> Vec<OsString> {
+ let mut values = Vec::new();
+ debug!("complete_arg_value: arg={:?}, value={:?}", arg, value);
+
+ if let Some(possible_values) = crate::generator::utils::possible_values(arg) {
+ if let Ok(value) = value {
+ values.extend(possible_values.into_iter().filter_map(|p| {
+ let name = p.get_name();
+ name.starts_with(value).then(|| name.into())
+ }));
+ }
+ } else {
+ let value_os = match value {
+ Ok(value) => clap_lex::RawOsStr::from_str(value),
+ Err(value_os) => value_os,
+ };
+ match arg.get_value_hint() {
+ clap::ValueHint::Other => {
+ // Should not complete
+ }
+ clap::ValueHint::Unknown | clap::ValueHint::AnyPath => {
+ values.extend(complete_path(value_os, current_dir, |_| true));
+ }
+ clap::ValueHint::FilePath => {
+ values.extend(complete_path(value_os, current_dir, |p| p.is_file()));
+ }
+ clap::ValueHint::DirPath => {
+ values.extend(complete_path(value_os, current_dir, |p| p.is_dir()));
+ }
+ clap::ValueHint::ExecutablePath => {
+ use is_executable::IsExecutable;
+ values.extend(complete_path(value_os, current_dir, |p| p.is_executable()));
+ }
+ clap::ValueHint::CommandName
+ | clap::ValueHint::CommandString
+ | clap::ValueHint::CommandWithArguments
+ | clap::ValueHint::Username
+ | clap::ValueHint::Hostname
+ | clap::ValueHint::Url
+ | clap::ValueHint::EmailAddress => {
+ // No completion implementation
+ }
+ _ => {
+ // Safe-ish fallback
+ values.extend(complete_path(value_os, current_dir, |_| true));
+ }
+ }
+ values.sort();
+ }
+
+ values
+ }
+
+ fn complete_path(
+ value_os: &clap_lex::RawOsStr,
+ current_dir: Option<&std::path::Path>,
+ is_wanted: impl Fn(&std::path::Path) -> bool,
+ ) -> Vec<OsString> {
+ let mut completions = Vec::new();
+
+ let current_dir = match current_dir {
+ Some(current_dir) => current_dir,
+ None => {
+ // Can't complete without a `current_dir`
+ return Vec::new();
+ }
+ };
+ let (existing, prefix) = value_os
+ .split_once('\\')
+ .unwrap_or((clap_lex::RawOsStr::from_str(""), value_os));
+ let root = current_dir.join(existing.to_os_str());
+ debug!("complete_path: root={:?}, prefix={:?}", root, prefix);
+
+ for entry in std::fs::read_dir(&root)
+ .ok()
+ .into_iter()
+ .flatten()
+ .filter_map(Result::ok)
+ {
+ let raw_file_name = clap_lex::RawOsString::new(entry.file_name());
+ if !raw_file_name.starts_with_os(prefix) {
+ continue;
+ }
+
+ if entry.metadata().map(|m| m.is_dir()).unwrap_or(false) {
+ let path = entry.path();
+ let mut suggestion = pathdiff::diff_paths(&path, current_dir).unwrap_or(path);
+ suggestion.push(""); // Ensure trailing `/`
+ completions.push(suggestion.as_os_str().to_owned());
+ } else {
+ let path = entry.path();
+ if is_wanted(&path) {
+ let suggestion = pathdiff::diff_paths(&path, current_dir).unwrap_or(path);
+ completions.push(suggestion.as_os_str().to_owned());
+ }
+ }
+ }
+
+ completions
+ }
+
+ fn complete_subcommand(value: &str, cmd: &clap::Command) -> Vec<OsString> {
+ debug!(
+ "complete_subcommand: cmd={:?}, value={:?}",
+ cmd.get_name(),
+ value
+ );
+
+ let mut scs = crate::generator::utils::all_subcommands(cmd)
+ .into_iter()
+ .filter(|x| x.0.starts_with(value))
+ .map(|x| OsString::from(&x.0))
+ .collect::<Vec<_>>();
+ scs.sort();
+ scs.dedup();
+ scs
+ }
+}
diff --git a/vendor/clap_complete/src/generator/mod.rs b/vendor/clap_complete/src/generator/mod.rs
index 2d00c281d..c025697ed 100644
--- a/vendor/clap_complete/src/generator/mod.rs
+++ b/vendor/clap_complete/src/generator/mod.rs
@@ -83,10 +83,8 @@ pub trait Generator {
///
/// ```
/// // src/cli.rs
-///
-/// use clap::{Command, Arg};
-///
-/// pub fn build_cli() -> Command<'static> {
+/// # use clap::{Command, Arg, ArgAction};
+/// pub fn build_cli() -> Command {
/// Command::new("compl")
/// .about("Tests completions")
/// .arg(Arg::new("file")
@@ -95,7 +93,7 @@ pub trait Generator {
/// .about("tests things")
/// .arg(Arg::new("case")
/// .long("case")
-/// .takes_value(true)
+/// .action(ArgAction::Set)
/// .help("the case to test")))
/// }
/// ```
@@ -195,7 +193,7 @@ where
///
/// # Examples
///
-/// Assuming a separate `cli.rs` like the [example above](generate_to()),
+/// Assuming a separate `cli.rs` like the [`generate_to` example](generate_to()),
/// we can let users generate a completion script using a command:
///
/// ```ignore
@@ -236,7 +234,7 @@ where
G: Generator,
S: Into<String>,
{
- cmd._build_all();
+ cmd.build();
gen.generate(cmd, buf)
}
diff --git a/vendor/clap_complete/src/generator/utils.rs b/vendor/clap_complete/src/generator/utils.rs
index b8aaa4bd5..ca76d189b 100644
--- a/vendor/clap_complete/src/generator/utils.rs
+++ b/vendor/clap_complete/src/generator/utils.rs
@@ -19,10 +19,7 @@ pub fn all_subcommands(cmd: &Command) -> Vec<(String, String)> {
/// Finds the subcommand [`clap::Command`] from the given [`clap::Command`] with the given path.
///
/// **NOTE:** `path` should not contain the root `bin_name`.
-pub fn find_subcommand_with_path<'help, 'cmd>(
- p: &'cmd Command<'help>,
- path: Vec<&str>,
-) -> &'cmd Command<'help> {
+pub fn find_subcommand_with_path<'cmd>(p: &'cmd Command, path: Vec<&str>) -> &'cmd Command {
let mut cmd = p;
for sc in path {
@@ -42,10 +39,6 @@ pub fn subcommands(p: &Command) -> Vec<(String, String)> {
let mut subcmds = vec![];
- if !p.has_subcommands() {
- return subcmds;
- }
-
for sc in p.get_subcommands() {
let sc_bin_name = sc.get_bin_name().unwrap();
@@ -62,7 +55,7 @@ pub fn subcommands(p: &Command) -> Vec<(String, String)> {
}
/// Gets all the short options, their visible aliases and flags of a [`clap::Command`].
-/// Includes `h` and `V` depending on the [`clap::AppSettings`].
+/// Includes `h` and `V` depending on the [`clap::Command`] settings.
pub fn shorts_and_visible_aliases(p: &Command) -> Vec<char> {
debug!("shorts: name={}", p.get_name());
@@ -87,7 +80,7 @@ pub fn shorts_and_visible_aliases(p: &Command) -> Vec<char> {
}
/// Gets all the long options, their visible aliases and flags of a [`clap::Command`].
-/// Includes `help` and `version` depending on the [`clap::AppSettings`].
+/// Includes `help` and `version` depending on the [`clap::Command`] settings.
pub fn longs_and_visible_aliases(p: &Command) -> Vec<String> {
debug!("longs: name={}", p.get_name());
@@ -117,22 +110,33 @@ pub fn longs_and_visible_aliases(p: &Command) -> Vec<String> {
}
/// Gets all the flags of a [`clap::Command`](Command).
-/// Includes `help` and `version` depending on the [`clap::AppSettings`].
-pub fn flags<'help>(p: &Command<'help>) -> Vec<Arg<'help>> {
+/// Includes `help` and `version` depending on the [`clap::Command`] settings.
+pub fn flags(p: &Command) -> Vec<Arg> {
debug!("flags: name={}", p.get_name());
p.get_arguments()
- .filter(|a| !a.is_takes_value_set() && !a.is_positional())
+ .filter(|a| !a.get_num_args().expect("built").takes_values() && !a.is_positional())
.cloned()
.collect()
}
+/// Get the possible values for completion
+pub fn possible_values(a: &Arg) -> Option<Vec<clap::builder::PossibleValue>> {
+ if !a.get_num_args().expect("built").takes_values() {
+ None
+ } else {
+ a.get_value_parser()
+ .possible_values()
+ .map(|pvs| pvs.collect())
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
use clap::Arg;
- use pretty_assertions::assert_eq;
+ use clap::ArgAction;
- fn common_app() -> Command<'static> {
+ fn common_app() -> Command {
Command::new("myapp")
.subcommand(
Command::new("test").subcommand(Command::new("config")).arg(
@@ -141,6 +145,7 @@ mod tests {
.short_alias('c')
.visible_short_alias('p')
.long("file")
+ .action(ArgAction::SetTrue)
.visible_alias("path"),
),
)
@@ -148,17 +153,17 @@ mod tests {
.bin_name("my-cmd")
}
- fn built() -> Command<'static> {
+ fn built() -> Command {
let mut cmd = common_app();
- cmd._build_all();
+ cmd.build();
cmd
}
- fn built_with_version() -> Command<'static> {
+ fn built_with_version() -> Command {
let mut cmd = common_app().version("3.0");
- cmd._build_all();
+ cmd.build();
cmd
}
@@ -188,6 +193,12 @@ mod tests {
("help".to_string(), "my-cmd help".to_string()),
("config".to_string(), "my-cmd test config".to_string()),
("help".to_string(), "my-cmd test help".to_string()),
+ ("config".to_string(), "my-cmd test help config".to_string()),
+ ("help".to_string(), "my-cmd test help help".to_string()),
+ ("test".to_string(), "my-cmd help test".to_string()),
+ ("hello".to_string(), "my-cmd help hello".to_string()),
+ ("help".to_string(), "my-cmd help help".to_string()),
+ ("config".to_string(), "my-cmd help test config".to_string()),
]
);
}
diff --git a/vendor/clap_complete/src/lib.rs b/vendor/clap_complete/src/lib.rs
index a22ff9ac3..80fead4a5 100644
--- a/vendor/clap_complete/src/lib.rs
+++ b/vendor/clap_complete/src/lib.rs
@@ -22,11 +22,11 @@
//! ## Example
//!
//! ```rust,no_run
-//! use clap::{Command, AppSettings, Arg, ValueHint};
+//! use clap::{Command, Arg, ValueHint, value_parser, ArgAction};
//! use clap_complete::{generate, Generator, Shell};
//! use std::io;
//!
-//! fn build_cli() -> Command<'static> {
+//! fn build_cli() -> Command {
//! Command::new("example")
//! .arg(Arg::new("file")
//! .help("some input file")
@@ -35,7 +35,8 @@
//! .arg(
//! Arg::new("generator")
//! .long("generate")
-//! .possible_values(Shell::possible_values()),
+//! .action(ArgAction::Set)
+//! .value_parser(value_parser!(Shell)),
//! )
//! }
//!
@@ -46,7 +47,7 @@
//! fn main() {
//! let matches = build_cli().get_matches();
//!
-//! if let Ok(generator) = matches.value_of_t::<Shell>("generator") {
+//! if let Some(generator) = matches.get_one::<Shell>("generator").copied() {
//! let mut cmd = build_cli();
//! eprintln!("Generating completion file for {}...", generator);
//! print_completions(generator, &mut cmd);
@@ -68,3 +69,6 @@ pub use generator::generate;
pub use generator::generate_to;
pub use generator::Generator;
pub use shells::Shell;
+
+#[cfg(feature = "unstable-dynamic")]
+pub mod dynamic;
diff --git a/vendor/clap_complete/src/macros.rs b/vendor/clap_complete/src/macros.rs
index def051434..bc6979460 100644
--- a/vendor/clap_complete/src/macros.rs
+++ b/vendor/clap_complete/src/macros.rs
@@ -10,8 +10,8 @@ macro_rules! w {
#[cfg(feature = "debug")]
macro_rules! debug {
($($arg:tt)*) => {
- print!("[{:>w$}] \t", module_path!(), w = 28);
- println!($($arg)*)
+ eprint!("[{:>w$}] \t", module_path!(), w = 28);
+ eprintln!($($arg)*)
}
}
diff --git a/vendor/clap_complete/src/shells/bash.rs b/vendor/clap_complete/src/shells/bash.rs
index 08bf1190c..e110537e5 100644
--- a/vendor/clap_complete/src/shells/bash.rs
+++ b/vendor/clap_complete/src/shells/bash.rs
@@ -31,8 +31,8 @@ impl Generator for Bash {
for i in ${{COMP_WORDS[@]}}
do
- case \"${{i}}\" in
- \"$1\")
+ case \"${{cmd}},${{i}}\" in
+ \",$1\")
cmd=\"{cmd}\"
;;{subcmds}
*)
@@ -75,26 +75,52 @@ complete -F _{name} -o bashdefault -o default {name}
fn all_subcommands(cmd: &Command) -> String {
debug!("all_subcommands");
- let mut subcmds = vec![String::new()];
- let mut scs = utils::all_subcommands(cmd)
- .iter()
- .map(|x| x.0.clone())
- .collect::<Vec<_>>();
-
- scs.sort();
- scs.dedup();
+ fn add_command(
+ parent_fn_name: &str,
+ cmd: &Command,
+ subcmds: &mut Vec<(String, String, String)>,
+ ) {
+ let fn_name = format!(
+ "{parent_fn_name}__{cmd_name}",
+ parent_fn_name = parent_fn_name,
+ cmd_name = cmd.get_name().to_string().replace('-', "__")
+ );
+ subcmds.push((
+ parent_fn_name.to_string(),
+ cmd.get_name().to_string(),
+ fn_name.clone(),
+ ));
+ for alias in cmd.get_visible_aliases() {
+ subcmds.push((
+ parent_fn_name.to_string(),
+ alias.to_string(),
+ fn_name.clone(),
+ ));
+ }
+ for subcmd in cmd.get_subcommands() {
+ add_command(&fn_name, subcmd, subcmds);
+ }
+ }
+ let mut subcmds = vec![];
+ let fn_name = cmd.get_name().replace('-', "__");
+ for subcmd in cmd.get_subcommands() {
+ add_command(&fn_name, subcmd, &mut subcmds);
+ }
+ subcmds.sort();
- subcmds.extend(scs.iter().map(|sc| {
- format!(
- "{name})
- cmd+=\"__{fn_name}\"
+ let mut cases = vec![String::new()];
+ for (parent_fn_name, name, fn_name) in subcmds {
+ cases.push(format!(
+ "{parent_fn_name},{name})
+ cmd=\"{fn_name}\"
;;",
- name = sc,
- fn_name = sc.replace('-', "__")
- )
- }));
+ parent_fn_name = parent_fn_name,
+ name = name,
+ fn_name = fn_name,
+ ));
+ }
- subcmds.join("\n ")
+ cases.join("\n ")
}
fn subcommand_details(cmd: &Command) -> String {
@@ -125,9 +151,9 @@ fn subcommand_details(cmd: &Command) -> String {
return 0
;;",
subcmd = sc.replace('-', "__"),
- sc_opts = all_options_for_path(cmd, &*sc),
+ sc_opts = all_options_for_path(cmd, sc),
level = sc.split("__").map(|_| 1).sum::<u64>(),
- opts_details = option_details_for_path(cmd, &*sc)
+ opts_details = option_details_for_path(cmd, sc)
)
}));
@@ -174,12 +200,12 @@ fn option_details_for_path(cmd: &Command, path: &str) -> String {
fn vals_for(o: &Arg) -> String {
debug!("vals_for: o={}", o.get_id());
- if let Some(vals) = o.get_possible_values() {
+ if let Some(vals) = crate::generator::utils::possible_values(o) {
format!(
"$(compgen -W \"{}\" -- \"${{cur}}\")",
vals.iter()
- .filter(|pv| pv.is_hide_set())
- .map(PossibleValue::get_name)
+ .filter(|pv| !pv.is_hide_set())
+ .map(|n| n.get_name())
.collect::<Vec<_>>()
.join(" ")
)
@@ -201,7 +227,7 @@ fn all_options_for_path(cmd: &Command, path: &str) -> String {
write!(&mut opts, "--{} ", long).unwrap();
}
for pos in p.get_positionals() {
- if let Some(vals) = pos.get_possible_values() {
+ if let Some(vals) = utils::possible_values(pos) {
for value in vals {
write!(&mut opts, "{} ", value.get_name()).unwrap();
}
diff --git a/vendor/clap_complete/src/shells/elvish.rs b/vendor/clap_complete/src/shells/elvish.rs
index 959372087..07da28348 100644
--- a/vendor/clap_complete/src/shells/elvish.rs
+++ b/vendor/clap_complete/src/shells/elvish.rs
@@ -1,5 +1,6 @@
use std::io::Write;
+use clap::builder::StyledStr;
use clap::*;
use crate::generator::{utils, Generator};
@@ -19,8 +20,7 @@ impl Generator for Elvish {
.get_bin_name()
.expect("crate::generate should have set the bin_name");
- let mut names = vec![];
- let subcommands_cases = generate_inner(cmd, "", &mut names);
+ let subcommands_cases = generate_inner(cmd, "");
let result = format!(
r#"
@@ -59,18 +59,14 @@ fn escape_string(string: &str) -> String {
string.replace('\'', "''")
}
-fn get_tooltip<T: ToString>(help: Option<&str>, data: T) -> String {
+fn get_tooltip<T: ToString>(help: Option<&StyledStr>, data: T) -> String {
match help {
- Some(help) => escape_string(help),
+ Some(help) => escape_string(&help.to_string()),
_ => data.to_string(),
}
}
-fn generate_inner<'help>(
- p: &Command<'help>,
- previous_command_name: &str,
- names: &mut Vec<&'help str>,
-) -> String {
+fn generate_inner(p: &Command, previous_command_name: &str) -> String {
debug!("generate_inner");
let command_name = if previous_command_name.is_empty() {
@@ -134,7 +130,7 @@ fn generate_inner<'help>(
);
for subcommand in p.get_subcommands() {
- let subcommand_subcommands_cases = generate_inner(subcommand, &command_name, names);
+ let subcommand_subcommands_cases = generate_inner(subcommand, &command_name);
subcommands_cases.push_str(&subcommand_subcommands_cases);
}
diff --git a/vendor/clap_complete/src/shells/fish.rs b/vendor/clap_complete/src/shells/fish.rs
index 9b516084b..fd2f3a4f8 100644
--- a/vendor/clap_complete/src/shells/fish.rs
+++ b/vendor/clap_complete/src/shells/fish.rs
@@ -27,8 +27,13 @@ impl Generator for Fish {
}
// Escape string inside single quotes
-fn escape_string(string: &str) -> String {
- string.replace('\\', "\\\\").replace('\'', "\\'")
+fn escape_string(string: &str, escape_comma: bool) -> String {
+ let string = string.replace('\\', "\\\\").replace('\'', "\\'");
+ if escape_comma {
+ string.replace(',', "\\,")
+ } else {
+ string
+ }
}
fn gen_fish_inner(
@@ -88,12 +93,13 @@ fn gen_fish_inner(
if let Some(longs) = option.get_long_and_visible_aliases() {
for long in longs {
- template.push_str(format!(" -l {}", escape_string(long)).as_str());
+ template.push_str(format!(" -l {}", escape_string(long, false)).as_str());
}
}
if let Some(data) = option.get_help() {
- template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
+ template
+ .push_str(format!(" -d '{}'", escape_string(&data.to_string(), false)).as_str());
}
template.push_str(value_completion(option).as_str());
@@ -113,12 +119,13 @@ fn gen_fish_inner(
if let Some(longs) = flag.get_long_and_visible_aliases() {
for long in longs {
- template.push_str(format!(" -l {}", escape_string(long)).as_str());
+ template.push_str(format!(" -l {}", escape_string(long, false)).as_str());
}
}
if let Some(data) = flag.get_help() {
- template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
+ template
+ .push_str(format!(" -d '{}'", escape_string(&data.to_string(), false)).as_str());
}
buffer.push_str(template.as_str());
@@ -132,7 +139,7 @@ fn gen_fish_inner(
template.push_str(format!(" -a \"{}\"", &subcommand.get_name()).as_str());
if let Some(data) = subcommand.get_about() {
- template.push_str(format!(" -d '{}'", escape_string(data)).as_str())
+ template.push_str(format!(" -d '{}'", escape_string(&data.to_string(), false)).as_str())
}
buffer.push_str(template.as_str());
@@ -148,11 +155,11 @@ fn gen_fish_inner(
}
fn value_completion(option: &Arg) -> String {
- if !option.is_takes_value_set() {
+ if !option.get_num_args().expect("built").takes_values() {
return "".to_string();
}
- if let Some(data) = option.get_possible_values() {
+ if let Some(data) = crate::generator::utils::possible_values(option) {
// We return the possible values with their own empty description e.g. {a\t,b\t}
// this makes sure that a and b don't get the description of the option or argument
format!(
@@ -163,8 +170,8 @@ fn value_completion(option: &Arg) -> String {
} else {
Some(format!(
"{}\t{}",
- escape_string(value.get_name()).as_str(),
- escape_string(value.get_help().unwrap_or_default()).as_str()
+ escape_string(value.get_name(), true).as_str(),
+ escape_string(&value.get_help().unwrap_or_default().to_string(), true)
))
})
.collect::<Vec<_>>()
diff --git a/vendor/clap_complete/src/shells/powershell.rs b/vendor/clap_complete/src/shells/powershell.rs
index d35e61c7d..0d3a2a55f 100644
--- a/vendor/clap_complete/src/shells/powershell.rs
+++ b/vendor/clap_complete/src/shells/powershell.rs
@@ -1,5 +1,6 @@
use std::io::Write;
+use clap::builder::StyledStr;
use clap::*;
use crate::generator::{utils, Generator};
@@ -19,8 +20,7 @@ impl Generator for PowerShell {
.get_bin_name()
.expect("crate::generate should have set the bin_name");
- let mut names = vec![];
- let subcommands_cases = generate_inner(cmd, "", &mut names);
+ let subcommands_cases = generate_inner(cmd, "");
let result = format!(
r#"
@@ -64,18 +64,14 @@ fn escape_string(string: &str) -> String {
string.replace('\'', "''")
}
-fn get_tooltip<T: ToString>(help: Option<&str>, data: T) -> String {
+fn get_tooltip<T: ToString>(help: Option<&StyledStr>, data: T) -> String {
match help {
- Some(help) => escape_string(help),
+ Some(help) => escape_string(&help.to_string()),
_ => data.to_string(),
}
}
-fn generate_inner<'help>(
- p: &Command<'help>,
- previous_command_name: &str,
- names: &mut Vec<&'help str>,
-) -> String {
+fn generate_inner(p: &Command, previous_command_name: &str) -> String {
debug!("generate_inner");
let command_name = if previous_command_name.is_empty() {
@@ -170,7 +166,7 @@ fn generate_inner<'help>(
);
for subcommand in p.get_subcommands() {
- let subcommand_subcommands_cases = generate_inner(subcommand, &command_name, names);
+ let subcommand_subcommands_cases = generate_inner(subcommand, &command_name);
subcommands_cases.push_str(&subcommand_subcommands_cases);
}
diff --git a/vendor/clap_complete/src/shells/shell.rs b/vendor/clap_complete/src/shells/shell.rs
index 63063bb7c..f6e70f575 100644
--- a/vendor/clap_complete/src/shells/shell.rs
+++ b/vendor/clap_complete/src/shells/shell.rs
@@ -1,7 +1,9 @@
use std::fmt::Display;
+use std::path::Path;
use std::str::FromStr;
-use clap::{ArgEnum, PossibleValue};
+use clap::builder::PossibleValue;
+use clap::ValueEnum;
use crate::shells;
use crate::Generator;
@@ -22,15 +24,6 @@ pub enum Shell {
Zsh,
}
-impl Shell {
- /// Report all `possible_values`
- pub fn possible_values() -> impl Iterator<Item = PossibleValue<'static>> {
- Shell::value_variants()
- .iter()
- .filter_map(ArgEnum::to_possible_value)
- }
-}
-
impl Display for Shell {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.to_possible_value()
@@ -54,7 +47,7 @@ impl FromStr for Shell {
}
// Hand-rolled so it can work even when `derive` feature is disabled
-impl ArgEnum for Shell {
+impl ValueEnum for Shell {
fn value_variants<'a>() -> &'a [Self] {
&[
Shell::Bash,
@@ -65,7 +58,7 @@ impl ArgEnum for Shell {
]
}
- fn to_possible_value<'a>(&self) -> Option<PossibleValue<'a>> {
+ fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
Some(match self {
Shell::Bash => PossibleValue::new("bash"),
Shell::Elvish => PossibleValue::new("elvish"),
@@ -97,3 +90,66 @@ impl Generator for Shell {
}
}
}
+
+impl Shell {
+ /// Parse a shell from a path to the executable for the shell
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use clap_complete::shells::Shell;
+ ///
+ /// assert_eq!(Shell::from_shell_path("/bin/bash"), Some(Shell::Bash));
+ /// assert_eq!(Shell::from_shell_path("/usr/bin/zsh"), Some(Shell::Zsh));
+ /// assert_eq!(Shell::from_shell_path("/opt/my_custom_shell"), None);
+ /// ```
+ pub fn from_shell_path<P: AsRef<Path>>(path: P) -> Option<Shell> {
+ parse_shell_from_path(path.as_ref())
+ }
+
+ /// Determine the user's current shell from the environment
+ ///
+ /// This will read the SHELL environment variable and try to determine which shell is in use
+ /// from that.
+ ///
+ /// If SHELL is not set, then on windows, it will default to powershell, and on
+ /// other OSes it will return `None`.
+ ///
+ /// If SHELL is set, but contains a value that doesn't correspond to one of the supported shell
+ /// types, then return `None`.
+ ///
+ /// # Example:
+ ///
+ /// ```no_run
+ /// # use clap::Command;
+ /// use clap_complete::{generate, shells::Shell};
+ /// # fn build_cli() -> Command {
+ /// # Command::new("compl")
+ /// # }
+ /// let mut cmd = build_cli();
+ /// generate(Shell::from_env().unwrap_or(Shell::Bash), &mut cmd, "myapp", &mut std::io::stdout());
+ /// ```
+ pub fn from_env() -> Option<Shell> {
+ if let Some(env_shell) = std::env::var_os("SHELL") {
+ Shell::from_shell_path(env_shell)
+ } else if cfg!(windows) {
+ Some(Shell::PowerShell)
+ } else {
+ None
+ }
+ }
+}
+
+// use a separate function to avoid having to monomorphize the entire function due
+// to from_shell_path being generic
+fn parse_shell_from_path(path: &Path) -> Option<Shell> {
+ let name = path.file_stem()?.to_str()?;
+ match name {
+ "bash" => Some(Shell::Bash),
+ "zsh" => Some(Shell::Zsh),
+ "fish" => Some(Shell::Fish),
+ "elvish" => Some(Shell::Elvish),
+ "powershell" | "powershell_ise" => Some(Shell::PowerShell),
+ _ => None,
+ }
+}
diff --git a/vendor/clap_complete/src/shells/zsh.rs b/vendor/clap_complete/src/shells/zsh.rs
index 2b64739ce..580de77a2 100644
--- a/vendor/clap_complete/src/shells/zsh.rs
+++ b/vendor/clap_complete/src/shells/zsh.rs
@@ -153,12 +153,10 @@ fn subcommands_of(p: &Command) -> String {
let text = format!(
"'{name}:{help}' \\",
name = name,
- help = escape_help(subcommand.get_about().unwrap_or(""))
+ help = escape_help(&subcommand.get_about().unwrap_or_default().to_string())
);
- if !text.is_empty() {
- ret.push(text);
- }
+ ret.push(text);
}
// The subcommands
@@ -234,7 +232,7 @@ fn get_subcommands_of(parent: &Command) -> String {
);
let mut segments = vec![format!("({})", name)];
let subcommand_args = get_args_of(
- parser_of(parent, &*bin_name).expect(INTERNAL_ERROR_MSG),
+ parser_of(parent, bin_name).expect(INTERNAL_ERROR_MSG),
Some(parent),
);
@@ -243,7 +241,7 @@ fn get_subcommands_of(parent: &Command) -> String {
}
// Get the help text of all child subcommands.
- let children = get_subcommands_of(parser_of(parent, &*bin_name).expect(INTERNAL_ERROR_MSG));
+ let children = get_subcommands_of(parser_of(parent, bin_name).expect(INTERNAL_ERROR_MSG));
if !children.is_empty() {
segments.push(children);
@@ -280,13 +278,10 @@ esac",
//
// Given the bin_name "a b c" and the Command for "a" this returns the "c" Command.
// Given the bin_name "a b c" and the Command for "b" this returns the "c" Command.
-fn parser_of<'help, 'cmd>(
- parent: &'cmd Command<'help>,
- bin_name: &str,
-) -> Option<&'cmd Command<'help>> {
+fn parser_of<'cmd>(parent: &'cmd Command, bin_name: &str) -> Option<&'cmd Command> {
debug!("parser_of: p={}, bin_name={}", parent.get_name(), bin_name);
- if bin_name == parent.get_bin_name().unwrap_or(&String::new()) {
+ if bin_name == parent.get_bin_name().unwrap_or_default() {
return Some(parent);
}
@@ -359,7 +354,7 @@ fn get_args_of(parent: &Command, p_global: Option<&Command>) -> String {
// Uses either `possible_vals` or `value_hint` to give hints about possible argument values
fn value_completion(arg: &Arg) -> Option<String> {
- if let Some(values) = &arg.get_possible_values() {
+ if let Some(values) = crate::generator::utils::possible_values(arg) {
if values
.iter()
.any(|value| !value.is_hide_set() && value.get_help().is_some())
@@ -375,7 +370,8 @@ fn value_completion(arg: &Arg) -> Option<String> {
Some(format!(
r#"{name}\:"{tooltip}""#,
name = escape_value(value.get_name()),
- tooltip = value.get_help().map(escape_help).unwrap_or_default()
+ tooltip =
+ escape_help(&value.get_help().unwrap_or_default().to_string()),
))
}
})
@@ -388,7 +384,7 @@ fn value_completion(arg: &Arg) -> Option<String> {
values
.iter()
.filter(|pv| !pv.is_hide_set())
- .map(PossibleValue::get_name)
+ .map(|n| n.get_name())
.collect::<Vec<_>>()
.join(" ")
))
@@ -448,10 +444,10 @@ fn write_opts_of(p: &Command, p_global: Option<&Command>) -> String {
for o in p.get_opts() {
debug!("write_opts_of:iter: o={}", o.get_id());
- let help = o.get_help().map_or(String::new(), escape_help);
+ let help = escape_help(&o.get_help().unwrap_or_default().to_string());
let conflicts = arg_conflicts(p, o, p_global);
- let multiple = if o.is_multiple_occurrences_set() {
+ let multiple = if let ArgAction::Count | ArgAction::Append = o.get_action() {
"*"
} else {
""
@@ -465,10 +461,7 @@ fn write_opts_of(p: &Command, p_global: Option<&Command>) -> String {
Some(val) => format!(":{}:{}", vn, val),
None => format!(":{}: ", vn),
};
- let vc = match o.get_num_vals() {
- Some(num_vals) => vc.repeat(num_vals),
- None => vc,
- };
+ let vc = vc.repeat(o.get_num_args().expect("built").min_values());
if let Some(shorts) = o.get_short_and_visible_aliases() {
for short in shorts {
@@ -551,10 +544,10 @@ fn write_flags_of(p: &Command, p_global: Option<&Command>) -> String {
for f in utils::flags(p) {
debug!("write_flags_of:iter: f={}", f.get_id());
- let help = f.get_help().map_or(String::new(), escape_help);
+ let help = escape_help(&f.get_help().unwrap_or_default().to_string());
let conflicts = arg_conflicts(p, &f, p_global);
- let multiple = if f.is_multiple_occurrences_set() {
+ let multiple = if let ArgAction::Count | ArgAction::Append = f.get_action() {
"*"
} else {
""
@@ -632,7 +625,8 @@ fn write_positionals_of(p: &Command) -> String {
for arg in p.get_positionals() {
debug!("write_positionals_of:iter: arg={}", arg.get_id());
- let cardinality = if arg.is_multiple_values_set() || arg.is_multiple_occurrences_set() {
+ let num_args = arg.get_num_args().expect("built");
+ let cardinality = if num_args.max_values() > 1 {
"*:"
} else if !arg.is_required_set() {
":"
@@ -646,12 +640,13 @@ fn write_positionals_of(p: &Command) -> String {
name = arg.get_id(),
help = arg
.get_help()
- .map_or("".to_owned(), |v| " -- ".to_owned() + v)
+ .map(|s| s.to_string())
+ .map_or("".to_owned(), |v| " -- ".to_owned() + &v)
.replace('[', "\\[")
.replace(']', "\\]")
.replace('\'', "'\\''")
.replace(':', "\\:"),
- value_completion = value_completion(arg).unwrap_or_else(|| "".to_string())
+ value_completion = value_completion(arg).unwrap_or_default()
);
debug!("write_positionals_of:iter: Wrote...{}", a);