diff --git a/clap_builder/src/builder/command.rs b/clap_builder/src/builder/command.rs index d050e4943bd..6472071fcee 100644 --- a/clap_builder/src/builder/command.rs +++ b/clap_builder/src/builder/command.rs @@ -11,6 +11,7 @@ use std::path::Path; // Internal use crate::builder::app_settings::{AppFlags, AppSettings}; use crate::builder::arg_settings::ArgSettings; +use crate::builder::ext::Extension; use crate::builder::ext::Extensions; use crate::builder::ArgAction; use crate::builder::IntoResettable; @@ -106,6 +107,8 @@ pub struct Command { external_value_parser: Option, long_help_exists: bool, deferred: Option Command>, + #[cfg(feature = "unstable-ext")] + ext: Extensions, app_ext: Extensions, } @@ -1039,6 +1042,14 @@ impl Command { Usage::new(self).create_usage_with_title(&[]) } + + /// Extend [`Command`] with [`CommandExt`] data + #[cfg(feature = "unstable-ext")] + #[allow(clippy::should_implement_trait)] + pub fn add(mut self, tagged: T) -> Self { + self.ext.set(tagged); + self + } } /// # Application-wide Settings @@ -3964,6 +3975,18 @@ impl Command { pub fn is_multicall_set(&self) -> bool { self.is_set(AppSettings::Multicall) } + + /// Access an [`CommandExt`] + #[cfg(feature = "unstable-ext")] + pub fn get(&self) -> Option<&T> { + self.ext.get::() + } + + /// Remove an [`CommandExt`] + #[cfg(feature = "unstable-ext")] + pub fn remove(mut self) -> Option { + self.ext.remove::() + } } // Internally used only @@ -4883,6 +4906,8 @@ impl Default for Command { external_value_parser: Default::default(), long_help_exists: false, deferred: None, + #[cfg(feature = "unstable-ext")] + ext: Default::default(), app_ext: Default::default(), } } @@ -4908,20 +4933,24 @@ impl fmt::Display for Command { } } +/// User-provided data that can be attached to an [`Arg`] +#[cfg(feature = "unstable-ext")] +pub trait CommandExt: Extension {} + #[allow(dead_code)] // atm dependent on features enabled -pub(crate) trait AppTag: crate::builder::ext::Extension {} +pub(crate) trait AppExt: Extension {} #[allow(dead_code)] // atm dependent on features enabled #[derive(Default, Copy, Clone, Debug)] struct TermWidth(usize); -impl AppTag for TermWidth {} +impl AppExt for TermWidth {} #[allow(dead_code)] // atm dependent on features enabled #[derive(Default, Copy, Clone, Debug)] struct MaxTermWidth(usize); -impl AppTag for MaxTermWidth {} +impl AppExt for MaxTermWidth {} fn two_elements_of(mut iter: I) -> Option<(T, T)> where diff --git a/clap_builder/src/builder/mod.rs b/clap_builder/src/builder/mod.rs index abc0b753689..9f871d7ff7c 100644 --- a/clap_builder/src/builder/mod.rs +++ b/clap_builder/src/builder/mod.rs @@ -33,6 +33,8 @@ pub use arg::ArgExt; pub use arg_group::ArgGroup; pub use arg_predicate::ArgPredicate; pub use command::Command; +#[cfg(feature = "unstable-ext")] +pub use command::CommandExt; pub use os_str::OsStr; pub use possible_value::PossibleValue; pub use range::ValueRange; @@ -41,9 +43,9 @@ pub use resettable::Resettable; pub use styled_str::StyledStr; pub use styling::Styles; pub use value_hint::ValueHint; +pub use value_parser::BoolValueParser; pub use value_parser::_infer_ValueParser_for; pub use value_parser::impl_prelude; -pub use value_parser::BoolValueParser; pub use value_parser::BoolishValueParser; pub use value_parser::EnumValueParser; pub use value_parser::FalseyValueParser; @@ -66,4 +68,4 @@ pub use value_parser::_AnonymousValueParser; pub(crate) use self::str::Inner as StrInner; pub(crate) use action::CountType; pub(crate) use arg_settings::{ArgFlags, ArgSettings}; -pub(crate) use command::AppTag; +pub(crate) use command::AppExt; diff --git a/clap_builder/src/builder/styling.rs b/clap_builder/src/builder/styling.rs index 7834300acdf..b00365adb71 100644 --- a/clap_builder/src/builder/styling.rs +++ b/clap_builder/src/builder/styling.rs @@ -161,7 +161,7 @@ impl Styles { } } -impl super::AppTag for Styles {} +impl super::AppExt for Styles {} impl Default for Styles { fn default() -> Self { diff --git a/clap_complete/src/engine/custom.rs b/clap_complete/src/engine/custom.rs index 51da696fefe..00dde78d67c 100644 --- a/clap_complete/src/engine/custom.rs +++ b/clap_complete/src/engine/custom.rs @@ -7,146 +7,146 @@ use clap_lex::OsStrExt as _; use super::CompletionCandidate; -/// Extend [`Arg`][clap::Arg] with a [`ValueCandidates`] +/// Extend [`Arg`][clap::Arg] with a completer /// /// # Example /// /// ```rust /// use clap::Parser; -/// use clap_complete::engine::{ArgValueCandidates, CompletionCandidate}; +/// use clap_complete::engine::{ArgValueCompleter, CompletionCandidate}; +/// +/// fn custom_completer(current: &std::ffi::OsStr) -> Vec { +/// let mut completions = vec![]; +/// let Some(current) = current.to_str() else { +/// return completions; +/// }; +/// +/// if "foo".starts_with(current) { +/// completions.push(CompletionCandidate::new("foo")); +/// } +/// if "bar".starts_with(current) { +/// completions.push(CompletionCandidate::new("bar")); +/// } +/// if "baz".starts_with(current) { +/// completions.push(CompletionCandidate::new("baz")); +/// } +/// completions +/// } /// /// #[derive(Debug, Parser)] /// struct Cli { -/// #[arg(long, add = ArgValueCandidates::new(|| { vec![ -/// CompletionCandidate::new("foo"), -/// CompletionCandidate::new("bar"), -/// CompletionCandidate::new("baz")] }))] +/// #[arg(long, add = ArgValueCompleter::new(custom_completer))] /// custom: Option, /// } /// ``` #[derive(Clone)] -pub struct ArgValueCandidates(Arc); +pub struct ArgValueCompleter(Arc); -impl ArgValueCandidates { - /// Create a new `ArgValueCandidates` with a custom completer +impl ArgValueCompleter { + /// Create a new `ArgValueCompleter` with a custom completer pub fn new(completer: C) -> Self where - C: ValueCandidates + 'static, + C: ValueCompleter + 'static, { Self(Arc::new(completer)) } - /// All potential candidates for an argument. + /// Candidates that match `current` /// /// See [`CompletionCandidate`] for more information. - pub fn candidates(&self) -> Vec { - self.0.candidates() + pub fn complete(&self, current: &OsStr) -> Vec { + self.0.complete(current) } } -impl std::fmt::Debug for ArgValueCandidates { +impl std::fmt::Debug for ArgValueCompleter { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(type_name::()) } } -impl ArgExt for ArgValueCandidates {} +impl ArgExt for ArgValueCompleter {} -/// User-provided completion candidates for an [`Arg`][clap::Arg], see [`ArgValueCandidates`] +/// User-provided completion candidates for an [`Arg`][clap::Arg], see [`ArgValueCompleter`] /// /// This is useful when predefined value hints are not enough. -pub trait ValueCandidates: Send + Sync { +pub trait ValueCompleter: Send + Sync { /// All potential candidates for an argument. /// /// See [`CompletionCandidate`] for more information. - fn candidates(&self) -> Vec; + fn complete(&self, current: &OsStr) -> Vec; } -impl ValueCandidates for F +impl ValueCompleter for F where - F: Fn() -> Vec + Send + Sync, + F: Fn(&OsStr) -> Vec + Send + Sync, { - fn candidates(&self) -> Vec { - self() + fn complete(&self, current: &OsStr) -> Vec { + self(current) } } -/// Extend [`Arg`][clap::Arg] with a completer +/// Extend [`Arg`][clap::Arg] with a [`ValueCandidates`] /// /// # Example /// /// ```rust /// use clap::Parser; -/// use clap_complete::engine::{ArgValueCompleter, CompletionCandidate}; -/// -/// fn custom_completer(current: &std::ffi::OsStr) -> Vec { -/// let mut completions = vec![]; -/// let Some(current) = current.to_str() else { -/// return completions; -/// }; -/// -/// if "foo".starts_with(current) { -/// completions.push(CompletionCandidate::new("foo")); -/// } -/// if "bar".starts_with(current) { -/// completions.push(CompletionCandidate::new("bar")); -/// } -/// if "baz".starts_with(current) { -/// completions.push(CompletionCandidate::new("baz")); -/// } -/// completions -/// } +/// use clap_complete::engine::{ArgValueCandidates, CompletionCandidate}; /// /// #[derive(Debug, Parser)] /// struct Cli { -/// #[arg(long, add = ArgValueCompleter::new(custom_completer))] +/// #[arg(long, add = ArgValueCandidates::new(|| { vec![ +/// CompletionCandidate::new("foo"), +/// CompletionCandidate::new("bar"), +/// CompletionCandidate::new("baz")] }))] /// custom: Option, /// } /// ``` #[derive(Clone)] -pub struct ArgValueCompleter(Arc); +pub struct ArgValueCandidates(Arc); -impl ArgValueCompleter { - /// Create a new `ArgValueCompleter` with a custom completer +impl ArgValueCandidates { + /// Create a new `ArgValueCandidates` with a custom completer pub fn new(completer: C) -> Self where - C: ValueCompleter + 'static, + C: ValueCandidates + 'static, { Self(Arc::new(completer)) } - /// Candidates that match `current` + /// All potential candidates for an argument. /// /// See [`CompletionCandidate`] for more information. - pub fn complete(&self, current: &OsStr) -> Vec { - self.0.complete(current) + pub fn candidates(&self) -> Vec { + self.0.candidates() } } -impl std::fmt::Debug for ArgValueCompleter { +impl std::fmt::Debug for ArgValueCandidates { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(type_name::()) } } -impl ArgExt for ArgValueCompleter {} +impl ArgExt for ArgValueCandidates {} -/// User-provided completion candidates for an [`Arg`][clap::Arg], see [`ArgValueCompleter`] +/// User-provided completion candidates for an [`Arg`][clap::Arg], see [`ArgValueCandidates`] /// /// This is useful when predefined value hints are not enough. -pub trait ValueCompleter: Send + Sync { +pub trait ValueCandidates: Send + Sync { /// All potential candidates for an argument. /// /// See [`CompletionCandidate`] for more information. - fn complete(&self, current: &OsStr) -> Vec; + fn candidates(&self) -> Vec; } -impl ValueCompleter for F +impl ValueCandidates for F where - F: Fn(&OsStr) -> Vec + Send + Sync, + F: Fn() -> Vec + Send + Sync, { - fn complete(&self, current: &OsStr) -> Vec { - self(current) + fn candidates(&self) -> Vec { + self() } }