Skip to content

Conversation

@EnigmaCurry
Copy link
Contributor

@EnigmaCurry EnigmaCurry commented Dec 13, 2025

This fixes #26

This implementation creates a new optional Cargo feature named "completion" and wraps clap_complete. This is specific to the goal of shell completion, and does not have any other refactoring for exposing the clap::Command in general.

The interface here is Conf structure in ---> Shell script out, while hiding all the clap stuff. The one exception is we need to re-export clap_complete::aot::Shell enum so the user can specify the shell language.

Check out the included completion_example.sh script that handles the testing of the Tab completion in Bash.

@cbeck88
Copy link
Owner

cbeck88 commented Dec 14, 2025

this looks great to me! it strikes a good balance of the competing concerns

ideally we'd have our own version of the pub enum Shell rather than re-export the one from clap_completions (but still convert it to the clap_completions API type). but this is a minor detail

@EnigmaCurry
Copy link
Contributor Author

EnigmaCurry commented Dec 14, 2025

Good call. I've wrapped clap_complete::aot::Shell with our own Shell enum. Tomorrow, I will investigate if we can flesh out some of the other completion types, or maybe this is good enough.

@EnigmaCurry
Copy link
Contributor Author

I tried to make a new ValueEnum trait and add the #[conf(value_enum)] decorator to complete on CLI enum variants .. but it didn't quite work and it got pretty hairy - see the alternative branch https://github.com/EnigmaCurry/conf-rs/tree/completion-value-enum-derive - I think it would be far easier to just expose the clap::Command directly if this level of integration was needed, but I'm still in the beginning stage of understanding the proc_macro_options and I feel ill-equipped to continue this path right now. It would be cool though to get the remaining values to complete via conf derive macro, but I'll need to come back to that idea later.

As a hint, this is how you could hard-code the options for the completion_example completion [SHELL] command:


fn possible_values_parser<T: ValueEnum>() -> clap::builder::PossibleValuesParser {
    let vals = T::possible_values()
        .iter()
        .map(|v| {
            let mut pv = clap::builder::PossibleValue::new(v.name);
            for &a in v.aliases {
                pv = pv.alias(a);
            }
            if let Some(h) = v.help {
                pv = pv.help(h);
            }
            pv
        })
        .collect::<Vec<_>>();

    PossibleValuesParser::new(vals)
}

pub fn write_completion<C: Conf, W: std::io::Write>(
    shell: Shell,
    bin_name: Option<&str>,
    out: &mut W,
) -> std::io::Result<()> {
    let mut cmd = get_clap_command::<C>().mut_subcommand("completion", |sc| {
        sc.mut_arg("shell", |a| {
            a.value_parser(possible_values_parser::<Shell>())
        })
    });

    let name: String = match bin_name {
        Some(s) => s.to_string(),
        None => cmd.get_name().to_string(),
    };

    generate(shell.to_clap(), &mut cmd, name, out);
    Ok(())
}

... and then you'll get tab completion for the variants: bash, zsh, powershell etc. But of course, we don't want to hard-code this expansion, we want to derive it via the arg struct's field enum.. so it requires more work still. However, this could be the imperative pattern that the user could apply themselves, if only we returned clap::Command.

On the other hand, the current PR gets you 80% of the way there without a lot of API debt, so I would be happy if this much was merged.

@EnigmaCurry EnigmaCurry marked this pull request as ready for review December 15, 2025 23:04
@cbeck88
Copy link
Owner

cbeck88 commented Dec 17, 2025

this looks great -- there's a CI failure for tests that rely on features but don't have those features active when they run. the way i fixed this for the serde tests was to stick this at the top of the test file:

#![cfg(feature = "serde")]

however that is minor, and i think i'll just merge and fix it after. i think i also need to have a test run that tests with all features enabled, before now we only had default and no-default-features

@cbeck88 cbeck88 merged commit 9b0b572 into cbeck88:develop Dec 17, 2025
2 of 4 checks passed
@cbeck88
Copy link
Owner

cbeck88 commented Dec 17, 2025

i made a PR here where I'm going to iterate on CI

#29

thanks for this, when things are green i'm going to cut 0.4.5 release

@cbeck88 cbeck88 mentioned this pull request Dec 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shell (tab) completion

2 participants