diff --git a/Cargo.lock b/Cargo.lock index 278ec60036e..79915ec0975 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -485,7 +485,6 @@ dependencies = [ "shlex", "snapbox", "trycmd", - "unicode-xid", ] [[package]] diff --git a/clap_complete/Cargo.toml b/clap_complete/Cargo.toml index f359b82ce00..1397450ceb9 100644 --- a/clap_complete/Cargo.toml +++ b/clap_complete/Cargo.toml @@ -38,7 +38,6 @@ clap = { path = "../", version = "4.5.15", default-features = false, features = clap_lex = { path = "../clap_lex", version = "0.7.0", optional = true } is_executable = { version = "1.0.1", optional = true } shlex = { version = "1.3.0", optional = true } -unicode-xid = { version = "0.2.2", optional = true } [dev-dependencies] snapbox = { version = "0.6.0", features = ["diff", "dir", "examples"] } @@ -51,13 +50,12 @@ automod = "1.0.14" [[example]] name = "dynamic" -required-features = ["unstable-dynamic", "unstable-command"] +required-features = ["unstable-dynamic"] [features] default = [] -unstable-doc = ["unstable-dynamic", "unstable-command"] # for docs.rs +unstable-doc = ["unstable-dynamic"] # for docs.rs unstable-dynamic = ["dep:clap_lex", "dep:shlex", "dep:is_executable", "clap/unstable-ext"] -unstable-command = ["unstable-dynamic", "dep:unicode-xid", "clap/derive", "dep:is_executable", "clap/unstable-ext"] debug = ["clap/debug"] [lints] diff --git a/clap_complete/examples/dynamic.rs b/clap_complete/examples/dynamic.rs index ba61f5fdc35..2c393a3e749 100644 --- a/clap_complete/examples/dynamic.rs +++ b/clap_complete/examples/dynamic.rs @@ -1,8 +1,5 @@ -use clap::FromArgMatches; -use clap::Subcommand; - fn command() -> clap::Command { - let cmd = clap::Command::new("dynamic") + clap::Command::new("dynamic") .arg( clap::Arg::new("input") .long("input") @@ -15,8 +12,7 @@ fn command() -> clap::Command { .short('F') .value_parser(["json", "yaml", "toml"]), ) - .args_conflicts_with_subcommands(true); - clap_complete::CompleteCommand::augment_subcommands(cmd) + .args_conflicts_with_subcommands(true) } fn main() { @@ -24,11 +20,7 @@ fn main() { let cmd = command(); let matches = cmd.get_matches(); - if let Ok(completions) = clap_complete::CompleteCommand::from_arg_matches(&matches) { - completions.complete(&mut command()); - } else { - println!("{matches:#?}"); - } + println!("{matches:#?}"); } #[test] diff --git a/clap_complete/examples/exhaustive.rs b/clap_complete/examples/exhaustive.rs index 83050bdd56f..cbe604ac054 100644 --- a/clap_complete/examples/exhaustive.rs +++ b/clap_complete/examples/exhaustive.rs @@ -1,6 +1,4 @@ use clap::builder::PossibleValue; -#[cfg(feature = "unstable-command")] -use clap::{FromArgMatches, Subcommand}; use clap_complete::{generate, Generator, Shell}; fn main() { @@ -15,12 +13,6 @@ fn main() { return; } - #[cfg(feature = "unstable-command")] - if let Ok(completions) = clap_complete::CompleteCommand::from_arg_matches(&matches) { - completions.complete(&mut cli()); - return; - }; - println!("{:?}", matches); } @@ -30,7 +22,7 @@ fn print_completions(gen: G, cmd: &mut clap::Command) { #[allow(clippy::let_and_return)] fn cli() -> clap::Command { - let cli = clap::Command::new("exhaustive") + clap::Command::new("exhaustive") .version("3.0") .propagate_version(true) .args([ @@ -197,8 +189,5 @@ fn cli() -> clap::Command { .long("email") .value_hint(clap::ValueHint::EmailAddress), ]), - ]); - #[cfg(feature = "unstable-command")] - let cli = clap_complete::CompleteCommand::augment_subcommands(cli); - cli + ]) } diff --git a/clap_complete/src/command/mod.rs b/clap_complete/src/command/mod.rs deleted file mode 100644 index ed3ebeabd58..00000000000 --- a/clap_complete/src/command/mod.rs +++ /dev/null @@ -1,253 +0,0 @@ -//! [` complete`][CompleteCommand] completion integration -//! -//! - If you aren't using a subcommand, see [`CompleteCommand`] -//! - If you are using subcommands, see [`CompleteArgs`] -//! -//! To source your completions: -//! -//! **WARNING:** We recommend re-sourcing your completions on upgrade. -//! These completions work by generating shell code that calls into `your_program` while completing. -//! That interface is unstable and a mismatch between the shell code and `your_program` may result -//! in either invalid completions or no completions being generated. -//! For this reason, we recommend generating the shell code anew on shell startup so that it is -//! "self-correcting" on shell launch, rather than writing the generated completions to a file. -//! -//! Bash -//! ```bash -//! echo "source <(your_program complete bash)" >> ~/.bashrc -//! ``` -//! -//! Elvish -//! ```elvish -//! echo "eval (your_program complete elvish)" >> ~/.elvish/rc.elv -//! ``` -//! -//! Fish -//! ```fish -//! echo "source (your_program complete fish | psub)" >> ~/.config/fish/config.fish -//! ``` -//! -//! Powershell -//! ```powershell -//! echo "your_program complete powershell | Invoke-Expression" >> $PROFILE -//! ``` -//! -//! Zsh -//! ```zsh -//! echo "source <(your_program complete zsh)" >> ~/.zshrc -//! ``` - -mod shells; - -use std::ffi::OsString; -use std::io::Write as _; - -pub use shells::*; - -/// A completion subcommand to add to your CLI -/// -/// To customize completions, see -/// - [`ValueHint`][crate::ValueHint] -/// - [`ValueEnum`][clap::ValueEnum] -/// - [`ArgValueCandidates`][crate::ArgValueCandidates] -/// - [`ArgValueCompleter`][crate::ArgValueCompleter] -/// -/// **Warning:** `stdout` should not be written to before [`CompleteCommand::complete`] has had a -/// chance to run. -/// -/// # Examples -/// -/// To integrate completions into an application without subcommands: -/// ```no_run -/// // src/main.rs -/// use clap::{CommandFactory, FromArgMatches, Parser, Subcommand}; -/// use clap_complete::CompleteCommand; -/// -/// #[derive(Parser, Debug)] -/// #[clap(name = "dynamic", about = "A dynamic command line tool")] -/// struct Cli { -/// /// The subcommand to run complete -/// #[command(subcommand)] -/// complete: Option, -/// -/// /// Input file path -/// #[clap(short, long, value_hint = clap::ValueHint::FilePath)] -/// input: Option, -/// /// Output format -/// #[clap(short = 'F', long, value_parser = ["json", "yaml", "toml"])] -/// format: Option, -/// } -/// -/// fn main() { -/// let cli = Cli::parse(); -/// if let Some(completions) = cli.complete { -/// completions.complete(&mut Cli::command()); -/// } -/// -/// // normal logic continues... -/// } -///``` -#[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), -} - -impl CompleteCommand { - /// Process the completion request and exit - /// - /// **Warning:** `stdout` should not be written to before this has had a - /// chance to run. - 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 - /// - /// **Warning:** `stdout` should not be written to before or after this has run. - pub fn try_complete(&self, cmd: &mut clap::Command) -> clap::error::Result<()> { - debug!("CompleteCommand::try_complete: {self:?}"); - let CompleteCommand::Complete(args) = self; - args.try_complete(cmd) - } -} - -/// A completion subcommand to add to your CLI -/// -/// To customize completions, see -/// - [`ValueHint`][crate::ValueHint] -/// - [`ValueEnum`][clap::ValueEnum] -/// - [`ArgValueCandidates`][crate::ArgValueCandidates] -/// - [`ArgValueCompleter`][crate::ArgValueCompleter] -/// -/// **Warning:** `stdout` should not be written to before [`CompleteArgs::complete`] has had a -/// chance to run. -/// -/// # Examples -/// -/// To integrate completions into an application without subcommands: -/// ```no_run -/// // src/main.rs -/// use clap::{CommandFactory, FromArgMatches, Parser, Subcommand}; -/// use clap_complete::CompleteArgs; -/// -/// #[derive(Parser, Debug)] -/// #[clap(name = "dynamic", about = "A dynamic command line tool")] -/// struct Cli { -/// #[command(subcommand)] -/// complete: Command, -/// } -/// -/// #[derive(Subcommand, Debug)] -/// enum Command { -/// Complete(CompleteArgs), -/// Print, -/// } -/// -/// fn main() { -/// let cli = Cli::parse(); -/// match cli.complete { -/// Command::Complete(completions) => { -/// completions.complete(&mut Cli::command()); -/// }, -/// Command::Print => { -/// println!("Hello world!"); -/// } -/// } -/// } -///``` -#[derive(clap::Args, Clone, Debug)] -#[command(about = None, long_about = None)] -pub struct CompleteArgs { - /// Specify shell to complete for - #[arg(value_name = "NAME")] - shell: Option, - - #[arg(raw = true, value_name = "ARG", hide = true)] - comp_words: Option>, -} - -impl CompleteArgs { - /// Process the completion request and exit - /// - /// **Warning:** `stdout` should not be written to before this has had a - /// chance to run. - 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 - /// - /// **Warning:** `stdout` should not be written to before or after this has run. - pub fn try_complete(&self, cmd: &mut clap::Command) -> clap::error::Result<()> { - debug!("CompleteCommand::try_complete: {self:?}"); - - let shell = self.shell.or_else(Shell::from_env).ok_or_else(|| { - std::io::Error::new( - std::io::ErrorKind::Other, - "unknown shell, please specify the name of your shell", - ) - })?; - - if let Some(comp_words) = self.comp_words.as_ref() { - let current_dir = std::env::current_dir().ok(); - - let mut buf = Vec::new(); - shell.write_complete(cmd, comp_words.clone(), current_dir.as_deref(), &mut buf)?; - std::io::stdout().write_all(&buf)?; - } else { - let name = cmd.get_name(); - let bin = cmd.get_bin_name().unwrap_or_else(|| cmd.get_name()); - - let mut buf = Vec::new(); - shell.write_registration(name, bin, bin, &mut buf)?; - std::io::stdout().write_all(&buf)?; - } - - Ok(()) - } -} - -/// Shell-integration for completions -/// -/// This will generally be called by [`CompleteCommand`] or [`CompleteArgs`]. -/// -/// This handles adapting between the shell and [`completer`][crate::engine::complete()]. -/// A `CommandCompleter` can choose how much of that lives within the registration script and or -/// lives in [`CommandCompleter::write_complete`]. -pub trait CommandCompleter { - /// Register for completions - /// - /// Write the `buf` the logic needed for calling into ` complete`, passing needed - /// arguments to [`CommandCompleter::write_complete`] through the environment. - /// - /// **WARNING:** There are no stability guarantees between the call to - /// [`CommandCompleter::write_complete`] that this generates and actually calling [`CommandCompleter::write_complete`]. - /// Caching the results of this call may result in invalid or no completions to be generated. - fn write_registration( - &self, - name: &str, - bin: &str, - completer: &str, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error>; - /// Complete the given command - /// - /// Adapt information from arguments and [`CommandCompleter::write_registration`]-defined env - /// variables to what is needed for [`completer`][crate::engine::complete()]. - /// - /// Write out the [`CompletionCandidate`][crate::engine::CompletionCandidate]s in a way the shell will understand. - fn write_complete( - &self, - cmd: &mut clap::Command, - args: Vec, - current_dir: Option<&std::path::Path>, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error>; -} diff --git a/clap_complete/src/command/shells.rs b/clap_complete/src/command/shells.rs deleted file mode 100644 index cf1cbdd8099..00000000000 --- a/clap_complete/src/command/shells.rs +++ /dev/null @@ -1,529 +0,0 @@ -use std::ffi::OsString; -use std::fmt::Display; -use std::str::FromStr; - -use clap::builder::PossibleValue; -use clap::ValueEnum; -use unicode_xid::UnicodeXID as _; - -use super::CommandCompleter; - -/// Completion support for built-in shells -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -#[non_exhaustive] -pub enum Shell { - /// Bourne Again `SHell` (bash) - Bash, - /// Elvish shell - Elvish, - /// Friendly Interactive `SHell` (fish) - Fish, - /// `PowerShell` - Powershell, - /// Z `SHell` (zsh) - Zsh, -} - -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(path: impl AsRef) -> Option { - 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 operating systems 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 shell = Shell::from_env(); - /// println!("{shell:?}"); - /// ``` - pub fn from_env() -> Option { - if let Some(env_shell) = std::env::var_os("SHELL") { - Shell::from_shell_path(env_shell) - } else { - None - } - } - - fn completer(&self) -> &dyn CommandCompleter { - match self { - Self::Bash => &Bash, - Self::Elvish => &Elvish, - Self::Fish => &Fish, - Self::Powershell => &Powershell, - Self::Zsh => &Zsh, - } - } -} - -impl CommandCompleter for Shell { - fn write_registration( - &self, - name: &str, - bin: &str, - completer: &str, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - self.completer() - .write_registration(name, bin, completer, buf) - } - fn write_complete( - &self, - cmd: &mut clap::Command, - args: Vec, - current_dir: Option<&std::path::Path>, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - self.completer().write_complete(cmd, args, current_dir, buf) - } -} - -// 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: &std::path::Path) -> Option { - let name = path.file_stem()?.to_str()?; - match name { - "bash" => Some(Shell::Bash), - "elvish" => Some(Shell::Elvish), - "fish" => Some(Shell::Fish), - "powershell" | "powershell_ise" => Some(Shell::Powershell), - "zsh" => Some(Shell::Zsh), - _ => None, - } -} - -impl Display for Shell { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.to_possible_value() - .expect("no values are skipped") - .get_name() - .fmt(f) - } -} - -impl FromStr for Shell { - type Err = String; - - fn from_str(s: &str) -> Result { - for variant in Self::value_variants() { - if variant.to_possible_value().unwrap().matches(s, false) { - return Ok(*variant); - } - } - Err(format!("invalid variant: {s}")) - } -} - -// Hand-rolled so it can work even when `derive` feature is disabled -impl ValueEnum for Shell { - fn value_variants<'a>() -> &'a [Self] { - &[ - Shell::Bash, - Shell::Elvish, - Shell::Fish, - Shell::Powershell, - Shell::Zsh, - ] - } - - fn to_possible_value(&self) -> Option { - Some(match self { - Shell::Bash => PossibleValue::new("bash"), - Shell::Elvish => PossibleValue::new("elvish"), - Shell::Fish => PossibleValue::new("fish"), - Shell::Powershell => PossibleValue::new("powershell"), - Shell::Zsh => PossibleValue::new("zsh"), - }) - } -} - -/// Bash completion adapter -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Bash; - -impl CommandCompleter for Bash { - fn write_registration( - &self, - name: &str, - bin: &str, - completer: &str, - buf: &mut dyn std::io::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 completer = - shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); - - let script = r#" -_clap_complete_NAME() { - local IFS=$'\013' - local _CLAP_COMPLETE_INDEX=${COMP_CWORD} - local _CLAP_COMPLETE_COMP_TYPE=${COMP_TYPE} - if compopt +o nospace 2> /dev/null; then - local _CLAP_COMPLETE_SPACE=false - else - local _CLAP_COMPLETE_SPACE=true - fi - COMPREPLY=( $( \ - IFS="$IFS" \ - _CLAP_COMPLETE_INDEX="$_CLAP_COMPLETE_INDEX" \ - _CLAP_COMPLETE_COMP_TYPE="$_CLAP_COMPLETE_COMP_TYPE" \ - _CLAP_COMPLETE_SPACE="$_CLAP_COMPLETE_SPACE" \ - "COMPLETER" complete bash -- "${COMP_WORDS[@]}" \ - ) ) - if [[ $? != 0 ]]; then - unset COMPREPLY - elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then - compopt -o nospace - fi -} -if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then - complete -o nospace -o bashdefault -o nosort -F _clap_complete_NAME BIN -else - complete -o nospace -o bashdefault -F _clap_complete_NAME BIN -fi -"# - .replace("NAME", &escaped_name) - .replace("BIN", bin) - .replace("COMPLETER", &completer) - .replace("UPPER", &upper_name); - - writeln!(buf, "{script}")?; - Ok(()) - } - fn write_complete( - &self, - cmd: &mut clap::Command, - args: Vec, - current_dir: Option<&std::path::Path>, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let index: usize = std::env::var("_CLAP_COMPLETE_INDEX") - .ok() - .and_then(|i| i.parse().ok()) - .unwrap_or_default(); - let _comp_type: CompType = std::env::var("_CLAP_COMPLETE_COMP_TYPE") - .ok() - .and_then(|i| i.parse().ok()) - .unwrap_or_default(); - let _space: Option = std::env::var("_CLAP_COMPLETE_SPACE") - .ok() - .and_then(|i| i.parse().ok()); - let ifs: Option = std::env::var("IFS").ok().and_then(|i| i.parse().ok()); - let completions = crate::engine::complete(cmd, args, index, current_dir)?; - - for (i, candidate) in completions.iter().enumerate() { - if i != 0 { - write!(buf, "{}", ifs.as_deref().unwrap_or("\n"))?; - } - write!(buf, "{}", candidate.get_value().to_string_lossy())?; - } - Ok(()) - } -} - -/// Type of completion attempted that caused a completion function to be called -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[non_exhaustive] -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 FromStr for CompType { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "9" => Ok(Self::Normal), - "63" => Ok(Self::Successive), - "33" => Ok(Self::Alternatives), - "64" => Ok(Self::Unmodified), - "37" => Ok(Self::Menu), - _ => Err(format!("unsupported COMP_TYPE `{}`", s)), - } - } -} - -impl Default for CompType { - fn default() -> Self { - Self::Normal - } -} - -/// Elvish completion adapter -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Elvish; - -impl CommandCompleter for Elvish { - fn write_registration( - &self, - _name: &str, - bin: &str, - completer: &str, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin)); - let completer = - shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); - - let script = r#" -set edit:completion:arg-completer[BIN] = { |@words| - set E:_CLAP_IFS = "\n" - - var index = (count $words) - set index = (- $index 1) - set E:_CLAP_COMPLETE_INDEX = (to-string $index) - - put (COMPLETER complete elvish -- $@words) | to-lines -} -"# - .replace("COMPLETER", &completer) - .replace("BIN", &bin); - - writeln!(buf, "{script}")?; - Ok(()) - } - fn write_complete( - &self, - cmd: &mut clap::Command, - args: Vec, - current_dir: Option<&std::path::Path>, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let index: usize = std::env::var("_CLAP_COMPLETE_INDEX") - .ok() - .and_then(|i| i.parse().ok()) - .unwrap_or_default(); - let ifs: Option = std::env::var("_CLAP_IFS").ok().and_then(|i| i.parse().ok()); - let completions = crate::engine::complete(cmd, args, index, current_dir)?; - - for (i, candidate) in completions.iter().enumerate() { - if i != 0 { - write!(buf, "{}", ifs.as_deref().unwrap_or("\n"))?; - } - write!(buf, "{}", candidate.get_value().to_string_lossy())?; - } - Ok(()) - } -} - -/// Fish completion adapter -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Fish; - -impl CommandCompleter for Fish { - fn write_registration( - &self, - _name: &str, - bin: &str, - completer: &str, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin)); - let completer = - shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); - - writeln!( - buf, - r#"complete -x -c {bin} -a "("'{completer}'" complete fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))""# - ) - } - fn write_complete( - &self, - cmd: &mut clap::Command, - args: Vec, - current_dir: Option<&std::path::Path>, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let index = args.len() - 1; - let completions = crate::engine::complete(cmd, args, index, current_dir)?; - - for candidate in completions { - write!(buf, "{}", candidate.get_value().to_string_lossy())?; - if let Some(help) = candidate.get_help() { - write!( - buf, - "\t{}", - help.to_string().lines().next().unwrap_or_default() - )?; - } - writeln!(buf)?; - } - Ok(()) - } -} - -/// Powershell completion adapter -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Powershell; - -impl CommandCompleter for Powershell { - fn write_registration( - &self, - _name: &str, - bin: &str, - completer: &str, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin)); - let completer = - shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); - - writeln!( - buf, - r#" -Register-ArgumentCompleter -Native -CommandName {bin} -ScriptBlock {{ - param($wordToComplete, $commandAst, $cursorPosition) - - $results = Invoke-Expression "&{completer} complete powershell -- $($commandAst.ToString())"; - $results | ForEach-Object {{ - $split = $_.Split("`t"); - $cmd = $split[0]; - - if ($split.Length -eq 2) {{ - $help = $split[1]; - }} - else {{ - $help = $split[0]; - }} - - [System.Management.Automation.CompletionResult]::new($cmd, $cmd, 'ParameterValue', $help) - }} -}}; - "# - ) - } - - fn write_complete( - &self, - cmd: &mut clap::Command, - args: Vec, - current_dir: Option<&std::path::Path>, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let index = args.len() - 1; - let completions = crate::engine::complete(cmd, args, index, current_dir)?; - - for candidate in completions { - write!(buf, "{}", candidate.get_value().to_string_lossy())?; - if let Some(help) = candidate.get_help() { - write!( - buf, - "\t{}", - help.to_string().lines().next().unwrap_or_default() - )?; - } - writeln!(buf)?; - } - Ok(()) - } -} - -/// Zsh completion adapter -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct Zsh; - -impl CommandCompleter for Zsh { - fn write_registration( - &self, - _name: &str, - bin: &str, - completer: &str, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin)); - let completer = - shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer)); - - let script = r#"#compdef BIN -function _clap_dynamic_completer() { - local _CLAP_COMPLETE_INDEX=$(expr $CURRENT - 1) - local _CLAP_IFS=$'\n' - - local completions=("${(@f)$( \ - _CLAP_IFS="$_CLAP_IFS" \ - _CLAP_COMPLETE_INDEX="$_CLAP_COMPLETE_INDEX" \ - COMPLETER complete zsh -- ${words} 2>/dev/null \ - )}") - - if [[ -n $completions ]]; then - compadd -a completions - fi -} - -compdef _clap_dynamic_completer BIN"# - .replace("COMPLETER", &completer) - .replace("BIN", &bin); - - writeln!(buf, "{script}")?; - Ok(()) - } - fn write_complete( - &self, - cmd: &mut clap::Command, - args: Vec, - current_dir: Option<&std::path::Path>, - buf: &mut dyn std::io::Write, - ) -> Result<(), std::io::Error> { - let index: usize = std::env::var("_CLAP_COMPLETE_INDEX") - .ok() - .and_then(|i| i.parse().ok()) - .unwrap_or_default(); - let ifs: Option = std::env::var("_CLAP_IFS").ok().and_then(|i| i.parse().ok()); - - // If the current word is empty, add an empty string to the args - let mut args = args.clone(); - if args.len() == index { - args.push("".into()); - } - let completions = crate::engine::complete(cmd, args, index, current_dir)?; - - for (i, candidate) in completions.iter().enumerate() { - if i != 0 { - write!(buf, "{}", ifs.as_deref().unwrap_or("\n"))?; - } - write!(buf, "{}", candidate.get_value().to_string_lossy())?; - } - Ok(()) - } -} diff --git a/clap_complete/src/lib.rs b/clap_complete/src/lib.rs index 099ed6929f2..43feab1efb7 100644 --- a/clap_complete/src/lib.rs +++ b/clap_complete/src/lib.rs @@ -66,18 +66,12 @@ const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a mod macros; pub mod aot; -#[cfg(feature = "unstable-command")] -pub mod command; #[cfg(feature = "unstable-dynamic")] pub mod engine; #[cfg(feature = "unstable-dynamic")] pub mod env; pub use clap::ValueHint; -#[cfg(feature = "unstable-command")] -pub use command::CompleteArgs; -#[cfg(feature = "unstable-command")] -pub use command::CompleteCommand; #[doc(inline)] #[cfg(feature = "unstable-dynamic")] pub use engine::ArgValueCandidates; diff --git a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/bash/.bashrc b/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/bash/.bashrc deleted file mode 100644 index 71a223df5be..00000000000 --- a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/bash/.bashrc +++ /dev/null @@ -1,32 +0,0 @@ -PS1='% ' -. /etc/bash_completion - -_clap_complete_exhaustive() { - local IFS=$'\013' - local _CLAP_COMPLETE_INDEX=${COMP_CWORD} - local _CLAP_COMPLETE_COMP_TYPE=${COMP_TYPE} - if compopt +o nospace 2> /dev/null; then - local _CLAP_COMPLETE_SPACE=false - else - local _CLAP_COMPLETE_SPACE=true - fi - COMPREPLY=( $( \ - IFS="$IFS" \ - _CLAP_COMPLETE_INDEX="$_CLAP_COMPLETE_INDEX" \ - _CLAP_COMPLETE_COMP_TYPE="$_CLAP_COMPLETE_COMP_TYPE" \ - _CLAP_COMPLETE_SPACE="$_CLAP_COMPLETE_SPACE" \ - "exhaustive" complete bash -- "${COMP_WORDS[@]}" \ - ) ) - if [[ $? != 0 ]]; then - unset COMPREPLY - elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then - compopt -o nospace - fi -} -if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then - complete -o nospace -o bashdefault -o nosort -F _clap_complete_exhaustive exhaustive -else - complete -o nospace -o bashdefault -F _clap_complete_exhaustive exhaustive -fi - - diff --git a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/elvish/elvish/rc.elv b/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/elvish/elvish/rc.elv deleted file mode 100644 index 614e4a29534..00000000000 --- a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/elvish/elvish/rc.elv +++ /dev/null @@ -1,14 +0,0 @@ -set edit:rprompt = (constantly "") -set edit:prompt = (constantly "% ") - -set edit:completion:arg-completer[exhaustive] = { |@words| - set E:_CLAP_IFS = "\n" - - var index = (count $words) - set index = (- $index 1) - set E:_CLAP_COMPLETE_INDEX = (to-string $index) - - put (exhaustive complete elvish -- $@words) | to-lines -} - - diff --git a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/fish/fish/completions/exhaustive.fish b/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/fish/fish/completions/exhaustive.fish deleted file mode 100644 index 34301ce985c..00000000000 --- a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/fish/fish/completions/exhaustive.fish +++ /dev/null @@ -1 +0,0 @@ -complete -x -c exhaustive -a "("'exhaustive'" complete fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))" diff --git a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/fish/fish/config.fish b/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/fish/fish/config.fish deleted file mode 100644 index 74bd2f00021..00000000000 --- a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/fish/fish/config.fish +++ /dev/null @@ -1,7 +0,0 @@ -set -U fish_greeting "" -set -U fish_autosuggestion_enabled 0 -function fish_title -end -function fish_prompt - printf '%% ' -end; diff --git a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/zsh/.zshenv b/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/zsh/.zshenv deleted file mode 100644 index 6d309f24b41..00000000000 --- a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/zsh/.zshenv +++ /dev/null @@ -1,5 +0,0 @@ -fpath=($fpath $ZDOTDIR/zsh) -autoload -U +X compinit && compinit -u # bypass compaudit security checking -precmd_functions="" # avoid the prompt being overwritten -PS1='%% ' -PROMPT='%% ' diff --git a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/zsh/zsh/_exhaustive b/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/zsh/zsh/_exhaustive deleted file mode 100644 index fbc8bc36c4d..00000000000 --- a/clap_complete/tests/snapshots/home/dynamic-command/exhaustive/zsh/zsh/_exhaustive +++ /dev/null @@ -1,17 +0,0 @@ -#compdef exhaustive -function _clap_dynamic_completer() { - local _CLAP_COMPLETE_INDEX=$(expr $CURRENT - 1) - local _CLAP_IFS=$'\n' - - local completions=("${(@f)$( \ - _CLAP_IFS="$_CLAP_IFS" \ - _CLAP_COMPLETE_INDEX="$_CLAP_COMPLETE_INDEX" \ - exhaustive complete zsh -- ${words} 2>/dev/null \ - )}") - - if [[ -n $completions ]]; then - compadd -a completions - fi -} - -compdef _clap_dynamic_completer exhaustive diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc b/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc index 68a5a1a16cb..b8ce1da590d 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc +++ b/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc @@ -20,9 +20,6 @@ _exhaustive() { exhaustive,alias) cmd="exhaustive__alias" ;; - exhaustive,complete) - cmd="exhaustive__complete" - ;; exhaustive,help) cmd="exhaustive__help" ;; @@ -47,9 +44,6 @@ _exhaustive() { exhaustive__help,alias) cmd="exhaustive__help__alias" ;; - exhaustive__help,complete) - cmd="exhaustive__help__complete" - ;; exhaustive__help,help) cmd="exhaustive__help__help" ;; @@ -168,7 +162,7 @@ _exhaustive() { case "${cmd}" in exhaustive) - opts="-h -V --global --generate --help --version action quote value pacman last alias hint complete help" + opts="-h -V --global --generate --help --version action quote value pacman last alias hint help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -237,22 +231,8 @@ _exhaustive() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - exhaustive__complete) - opts="-h -V --global --help --version bash elvish fish powershell zsh [ARG]..." - if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; exhaustive__help) - opts="action quote value pacman last alias hint complete help" + opts="action quote value pacman last alias hint help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -293,20 +273,6 @@ _exhaustive() { COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; - exhaustive__help__complete) - opts="" - if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - fi - case "${prev}" in - *) - COMPREPLY=() - ;; - esac - COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) - return 0 - ;; exhaustive__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/elvish/elvish/rc.elv b/clap_complete/tests/snapshots/home/static/exhaustive/elvish/elvish/rc.elv index 2fc8920678b..afde72f4678 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/elvish/elvish/rc.elv +++ b/clap_complete/tests/snapshots/home/static/exhaustive/elvish/elvish/rc.elv @@ -33,7 +33,6 @@ set edit:completion:arg-completer[exhaustive] = {|@words| cand last 'last' cand alias 'alias' cand hint 'hint' - cand complete 'Register shell completions for this program' cand help 'Print this message or the help of the given subcommand(s)' } &'exhaustive;action'= { @@ -238,13 +237,6 @@ set edit:completion:arg-completer[exhaustive] = {|@words| cand -V 'Print version' cand --version 'Print version' } - &'exhaustive;complete'= { - cand --global 'everywhere' - cand -h 'Print help' - cand --help 'Print help' - cand -V 'Print version' - cand --version 'Print version' - } &'exhaustive;help'= { cand action 'action' cand quote 'quote' @@ -253,7 +245,6 @@ set edit:completion:arg-completer[exhaustive] = {|@words| cand last 'last' cand alias 'alias' cand hint 'hint' - cand complete 'Register shell completions for this program' cand help 'Print this message or the help of the given subcommand(s)' } &'exhaustive;help;action'= { @@ -297,8 +288,6 @@ set edit:completion:arg-completer[exhaustive] = {|@words| } &'exhaustive;help;hint'= { } - &'exhaustive;help;complete'= { - } &'exhaustive;help;help'= { } ] diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish b/clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish index 92d6d42e9c3..dd17413c1e7 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish +++ b/clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish @@ -35,7 +35,6 @@ complete -c exhaustive -n "__fish_exhaustive_needs_command" -f -a "pacman" complete -c exhaustive -n "__fish_exhaustive_needs_command" -f -a "last" complete -c exhaustive -n "__fish_exhaustive_needs_command" -f -a "alias" complete -c exhaustive -n "__fish_exhaustive_needs_command" -f -a "hint" -complete -c exhaustive -n "__fish_exhaustive_needs_command" -f -a "complete" -d 'Register shell completions for this program' complete -c exhaustive -n "__fish_exhaustive_needs_command" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c exhaustive -n "__fish_exhaustive_using_subcommand action" -l set -d 'value' -r complete -c exhaustive -n "__fish_exhaustive_using_subcommand action" -l choice -d 'enum' -r -f -a "{first\t'',second\t''}" @@ -136,18 +135,14 @@ complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -l email -r complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -l global -d 'everywhere' complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -s h -l help -d 'Print help' complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -s V -l version -d 'Print version' -complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -l global -d 'everywhere' -complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -s h -l help -d 'Print help' -complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -s V -l version -d 'Print version' -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "action" -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "quote" -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "value" -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "pacman" -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "last" -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "alias" -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "hint" -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "complete" -d 'Register shell completions for this program' -complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint complete help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' +complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint help" -f -a "action" +complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint help" -f -a "quote" +complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint help" -f -a "value" +complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint help" -f -a "pacman" +complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint help" -f -a "last" +complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint help" -f -a "alias" +complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint help" -f -a "hint" +complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and not __fish_seen_subcommand_from action quote value pacman last alias hint help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and __fish_seen_subcommand_from quote" -f -a "cmd-single-quotes" -d 'Can be \'always\', \'auto\', or \'never\'' complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and __fish_seen_subcommand_from quote" -f -a "cmd-double-quotes" -d 'Can be "always", "auto", or "never"' complete -c exhaustive -n "__fish_exhaustive_using_subcommand help; and __fish_seen_subcommand_from quote" -f -a "cmd-backticks" -d 'For more information see `echo test`' diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive b/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive index 73f57fdf860..4ceaca2d9ca 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive +++ b/clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive @@ -323,17 +323,6 @@ _arguments "${_arguments_options[@]}" : \ '*::command_with_args:_cmdambivalent' \ && ret=0 ;; -(complete) -_arguments "${_arguments_options[@]}" : \ -'--global[everywhere]' \ -'-h[Print help]' \ -'--help[Print help]' \ -'-V[Print version]' \ -'--version[Print version]' \ -'::shell -- Specify shell to complete for:(bash elvish fish powershell zsh)' \ -'*::comp_words:' \ -&& ret=0 -;; (help) _arguments "${_arguments_options[@]}" : \ ":: :_exhaustive__help_commands" \ @@ -434,10 +423,6 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ && ret=0 ;; -(complete) -_arguments "${_arguments_options[@]}" : \ -&& ret=0 -;; (help) _arguments "${_arguments_options[@]}" : \ && ret=0 @@ -461,7 +446,6 @@ _exhaustive_commands() { 'last:' \ 'alias:' \ 'hint:' \ -'complete:Register shell completions for this program' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'exhaustive commands' commands "$@" @@ -476,11 +460,6 @@ _exhaustive__alias_commands() { local commands; commands=() _describe -t commands 'exhaustive alias commands' commands "$@" } -(( $+functions[_exhaustive__complete_commands] )) || -_exhaustive__complete_commands() { - local commands; commands=() - _describe -t commands 'exhaustive complete commands' commands "$@" -} (( $+functions[_exhaustive__help_commands] )) || _exhaustive__help_commands() { local commands; commands=( @@ -491,7 +470,6 @@ _exhaustive__help_commands() { 'last:' \ 'alias:' \ 'hint:' \ -'complete:Register shell completions for this program' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'exhaustive help commands' commands "$@" @@ -506,11 +484,6 @@ _exhaustive__help__alias_commands() { local commands; commands=() _describe -t commands 'exhaustive help alias commands' commands "$@" } -(( $+functions[_exhaustive__help__complete_commands] )) || -_exhaustive__help__complete_commands() { - local commands; commands=() - _describe -t commands 'exhaustive help complete commands' commands "$@" -} (( $+functions[_exhaustive__help__help_commands] )) || _exhaustive__help__help_commands() { local commands; commands=() diff --git a/clap_complete/tests/testsuite/bash.rs b/clap_complete/tests/testsuite/bash.rs index 258a13cf2d8..a90b180b3da 100644 --- a/clap_complete/tests/testsuite/bash.rs +++ b/clap_complete/tests/testsuite/bash.rs @@ -111,24 +111,6 @@ fn value_terminator() { ); } -#[cfg(feature = "unstable-command")] -#[test] -fn register_minimal() { - use clap_complete::command::CommandCompleter as _; - - let name = "my-app"; - let bin = name; - let completer = name; - - let mut buf = Vec::new(); - clap_complete::command::Bash - .write_registration(name, bin, completer, &mut buf) - .unwrap(); - snapbox::Assert::new() - .action_env("SNAPSHOTS") - .eq(buf, snapbox::file!["../snapshots/register_minimal.bash"]); -} - #[test] fn two_multi_valued_arguments() { let name = "my-app"; @@ -173,8 +155,8 @@ fn complete() { let input = "exhaustive \t\t"; let expected = snapbox::str![[r#" % --h --global --help action value last hint help --V --generate --version quote pacman alias complete +-h --global --help action value last hint +-V --generate --version quote pacman alias help "#]]; let actual = runtime.complete(input, &term).unwrap(); assert_data_eq!(actual, expected); @@ -287,41 +269,3 @@ fn complete_dynamic_env() { let actual = runtime.complete(input, &term).unwrap(); assert_data_eq!(actual, expected); } - -#[test] -#[cfg(all(unix, feature = "unstable-command"))] -fn register_dynamic_command() { - common::register_example::("dynamic-command", "exhaustive"); -} - -#[test] -#[cfg(all(unix, feature = "unstable-command"))] -fn complete_dynamic_command() { - if !common::has_command("bash") { - return; - } - - let term = completest::Term::new(); - let mut runtime = - common::load_runtime::("dynamic-command", "exhaustive"); - - let input = "exhaustive \t\t"; - let expected = snapbox::str![[r#" -% ---global --help -h action help last quote ---generate --version -V alias hint pacman value -"#]]; - let actual = runtime.complete(input, &term).unwrap(); - assert_data_eq!(actual, expected); - - let input = "exhaustive quote \t\t"; - let expected = snapbox::str![[r#" -% ---single-quotes --brackets --help cmd-backslash cmd-expansions ---double-quotes --expansions --version cmd-backticks cmd-single-quotes ---backticks --choice -h cmd-brackets escape-help ---backslash --global -V cmd-double-quotes help -"#]]; - let actual = runtime.complete(input, &term).unwrap(); - assert_data_eq!(actual, expected); -} diff --git a/clap_complete/tests/testsuite/common.rs b/clap_complete/tests/testsuite/common.rs index 1c6290f8378..d388718dec4 100644 --- a/clap_complete/tests/testsuite/common.rs +++ b/clap_complete/tests/testsuite/common.rs @@ -321,7 +321,6 @@ pub(crate) fn register_example(context: &str, nam // Unconditionally include to avoid completion file tests failing based on the how // `cargo test` is invoked "--features=unstable-dynamic", - "--features=unstable-command", ], ) .unwrap(); @@ -381,7 +380,6 @@ where // Unconditionally include to avoid completion file tests failing based on the how // `cargo test` is invoked "--features=unstable-dynamic", - "--features=unstable-command", ], ) .unwrap(); diff --git a/clap_complete/tests/testsuite/elvish.rs b/clap_complete/tests/testsuite/elvish.rs index 137c2662bf3..8cc49700286 100644 --- a/clap_complete/tests/testsuite/elvish.rs +++ b/clap_complete/tests/testsuite/elvish.rs @@ -163,7 +163,6 @@ fn complete() { -h Print help action action alias alias -complete Register shell completions for this program help Print this message or the help of the given subcommand(s) hint hint last last @@ -214,48 +213,3 @@ fn complete_dynamic_env() { let actual = runtime.complete(input, &term).unwrap(); assert_data_eq!(actual, expected); } - -#[test] -#[cfg(all(unix, feature = "unstable-command"))] -fn register_dynamic_command() { - common::register_example::( - "dynamic-command", - "exhaustive", - ); -} - -#[test] -#[cfg(all(unix, feature = "unstable-command"))] -fn complete_dynamic_command() { - if !common::has_command("elvish") { - return; - } - - let term = completest::Term::new(); - let mut runtime = common::load_runtime::( - "dynamic-command", - "exhaustive", - ); - - let input = "exhaustive \t"; - let expected = snapbox::str![[r#" -% exhaustive --generate - COMPLETING argument ---generate --help -V action help last quote ---global --version -h alias hint pacman value -"#]]; - let actual = runtime.complete(input, &term).unwrap(); - assert_data_eq!(actual, expected); - - let input = "exhaustive quote \t"; - let expected = snapbox::str![[r#" -% exhaustive quote --backslash - COMPLETING argument ---backslash --double-quotes --single-quotes cmd-backslash cmd-expansions ---backticks --expansions --version cmd-backticks cmd-single-quotes ---brackets --global -V cmd-brackets escape-help ---choice --help -h cmd-double-quotes help -"#]]; - let actual = runtime.complete(input, &term).unwrap(); - assert_data_eq!(actual, expected); -} diff --git a/clap_complete/tests/testsuite/fish.rs b/clap_complete/tests/testsuite/fish.rs index 98aac6934f6..04dc559d8b7 100644 --- a/clap_complete/tests/testsuite/fish.rs +++ b/clap_complete/tests/testsuite/fish.rs @@ -154,8 +154,8 @@ fn complete() { let input = "exhaustive \t"; let expected = snapbox::str![[r#" % exhaustive -action complete (Register shell completions for this program) hint pacman value -alias help (Print this message or the help of the given subcommand(s)) last quote +action help (Print this message or the help of the given subcommand(s)) last quote +alias hint pacman value "#]]; let actual = runtime.complete(input, &term).unwrap(); assert_data_eq!(actual, expected); @@ -225,60 +225,3 @@ help (Print this message or the help of the given subcommand(s)) let actual = runtime.complete(input, &term).unwrap(); assert_data_eq!(actual, expected); } - -#[test] -#[cfg(all(unix, feature = "unstable-command"))] -fn register_dynamic_command() { - common::register_example::("dynamic-command", "exhaustive"); -} - -#[test] -#[cfg(all(unix, feature = "unstable-command"))] -fn complete_dynamic_command() { - if !common::has_command("fish") { - return; - } - - let term = completest::Term::new(); - let mut runtime = - common::load_runtime::("dynamic-command", "exhaustive"); - - let input = "exhaustive \t\t"; - let expected = snapbox::str![[r#" -% exhaustive action -action pacman --generate (generate) -alias quote --global (everywhere) -help (Print this message or the help of the given subcommand(s)) value --help (Print help) -hint -h (Print help) --version (Print version) -last -V (Print version) -"#]]; - let actual = runtime.complete(input, &term).unwrap(); - assert_data_eq!(actual, expected); - - let input = "exhaustive quote \t\t"; - let expected = snapbox::str![[r#" -% exhaustive quote -cmd-backslash (Avoid '/n') -cmd-backticks (For more information see `echo test`) -cmd-brackets (List packages [filter]) -cmd-double-quotes (Can be "always", "auto", or "never") -cmd-expansions (Execute the shell command with $SHELL) -cmd-single-quotes (Can be 'always', 'auto', or 'never') -escape-help (/tab "') -help (Print this message or the help of the given subcommand(s)) --h (Print help (see more with '--help')) --V (Print version) ---backslash (Avoid '/n') ---backticks (For more information see `echo test`) ---brackets (List packages [filter]) ---choice ---double-quotes (Can be "always", "auto", or "never") ---expansions (Execute the shell command with $SHELL) ---global (everywhere) ---help (Print help (see more with '--help')) ---single-quotes (Can be 'always', 'auto', or 'never') ---version (Print version) -"#]]; - let actual = runtime.complete(input, &term).unwrap(); - assert_data_eq!(actual, expected); -} diff --git a/clap_complete/tests/testsuite/zsh.rs b/clap_complete/tests/testsuite/zsh.rs index 02e662b2bd8..17a5e347985 100644 --- a/clap_complete/tests/testsuite/zsh.rs +++ b/clap_complete/tests/testsuite/zsh.rs @@ -155,9 +155,8 @@ fn complete() { let input = "exhaustive \t"; let expected = snapbox::str![[r#" % exhaustive -complete -- Register shell completions for this program -help -- Print this message or the help of the given subcommand(s) -pacman action alias value quote hint last -- +help -- Print this message or the help of the given subcommand(s) +pacman action alias value quote hint last -- "#]]; let actual = runtime.complete(input, &term).unwrap(); assert_data_eq!(actual, expected); @@ -200,41 +199,3 @@ fn complete_dynamic_env() { let actual = runtime.complete(input, &term).unwrap(); assert_data_eq!(actual, expected); } - -#[test] -#[cfg(all(unix, feature = "unstable-command"))] -fn register_dynamic_command() { - common::register_example::("dynamic-command", "exhaustive"); -} - -#[test] -#[cfg(all(unix, feature = "unstable-command"))] -fn complete_dynamic_command() { - if !common::has_command("zsh") { - return; - } - - let term = completest::Term::new(); - let mut runtime = - common::load_runtime::("dynamic-command", "exhaustive"); - - let input = "exhaustive \t\t"; - let expected = snapbox::str![[r#" -% exhaustive ---generate --help -V action help last quote ---global --version -h alias hint pacman value -"#]]; - let actual = runtime.complete(input, &term).unwrap(); - assert_data_eq!(actual, expected); - - let input = "exhaustive quote \t\t"; - let expected = snapbox::str![[r#" -% exhaustive quote ---backslash --double-quotes --single-quotes cmd-backslash cmd-expansions ---backticks --expansions --version cmd-backticks cmd-single-quotes ---brackets --global -V cmd-brackets escape-help ---choice --help -h cmd-double-quotes help -"#]]; - let actual = runtime.complete(input, &term).unwrap(); - assert_data_eq!(actual, expected); -}