Skip to content

Commit

Permalink
refactor(complete): Put most general completer first
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Oct 2, 2024
1 parent 81b9db2 commit f89afeb
Showing 1 changed file with 59 additions and 59 deletions.
118 changes: 59 additions & 59 deletions clap_complete/src/engine/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<CompletionCandidate> {
/// 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<String>,
/// }
/// ```
#[derive(Clone)]
pub struct ArgValueCandidates(Arc<dyn ValueCandidates>);
pub struct ArgValueCompleter(Arc<dyn ValueCompleter>);

impl ArgValueCandidates {
/// Create a new `ArgValueCandidates` with a custom completer
impl ArgValueCompleter {
/// Create a new `ArgValueCompleter` with a custom completer
pub fn new<C>(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<CompletionCandidate> {
self.0.candidates()
pub fn complete(&self, current: &OsStr) -> Vec<CompletionCandidate> {
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::<Self>())
}
}

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<CompletionCandidate>;
fn complete(&self, current: &OsStr) -> Vec<CompletionCandidate>;
}

impl<F> ValueCandidates for F
impl<F> ValueCompleter for F
where
F: Fn() -> Vec<CompletionCandidate> + Send + Sync,
F: Fn(&OsStr) -> Vec<CompletionCandidate> + Send + Sync,
{
fn candidates(&self) -> Vec<CompletionCandidate> {
self()
fn complete(&self, current: &OsStr) -> Vec<CompletionCandidate> {
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<CompletionCandidate> {
/// 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<String>,
/// }
/// ```
#[derive(Clone)]
pub struct ArgValueCompleter(Arc<dyn ValueCompleter>);
pub struct ArgValueCandidates(Arc<dyn ValueCandidates>);

impl ArgValueCompleter {
/// Create a new `ArgValueCompleter` with a custom completer
impl ArgValueCandidates {
/// Create a new `ArgValueCandidates` with a custom completer
pub fn new<C>(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<CompletionCandidate> {
self.0.complete(current)
pub fn candidates(&self) -> Vec<CompletionCandidate> {
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::<Self>())
}
}

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<CompletionCandidate>;
fn candidates(&self) -> Vec<CompletionCandidate>;
}

impl<F> ValueCompleter for F
impl<F> ValueCandidates for F
where
F: Fn(&OsStr) -> Vec<CompletionCandidate> + Send + Sync,
F: Fn() -> Vec<CompletionCandidate> + Send + Sync,
{
fn complete(&self, current: &OsStr) -> Vec<CompletionCandidate> {
self(current)
fn candidates(&self) -> Vec<CompletionCandidate> {
self()
}
}

Expand Down

0 comments on commit f89afeb

Please sign in to comment.