feat: add shell completion generation (bash, fish, zsh)#8
Open
johanvx wants to merge 8 commits into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
Add
Shellenum,completions::Commandsnapshot, and three shell-completion generators (bash, fish, zsh) that produce native completion scripts for acmdline::App. The implementation is stripped-down fromclap_complete, matching what our data model (App/Option/Arg) actually supports: no aliases, no possible-values, no value-hints, no conflict annotations.Problem
mcpplibs.cmdlinehad no built-in mechanism to generate shell completions. Users who wanted tab-completion had to hand-write scripts for each shell (fishcomplete -c, bashcomplete -F, zsh_arguments), duplicating the option definitions already present in theirAppsetup.Approach
Port the three completion generators from
clap_complete(fish.rs,bash.rs,zsh.rs), stripping features thatcmdlinedoes not support. The stripping logic follows the pattern already established in our existing fish generator: only primary short/long names, bare file completion for value-taking options, global re-offer with dedup under subcommands.A
completions::Commandstruct captures a snapshot of theApptree (names, descriptions, options, args, subcommands) including auto-added--helpand--version. All three generators receive(const Command&, std::ostream&).Implementation
src/completions.cppmShellenum,Commandstruct,shell_from_string/to_string/shell_supportedhelperssrc/completions/bash.cppmcomplete -Fgenerator withcompgen -Wword-list matching and acase "${cmd}"dispatch switchclap_complete::bash.rssrc/completions/fish.cppmcomplete -cgenerator with-nconditions and helper functionssrc/completions/zsh.cppm#compdefgenerator with_argumentsspecs, recursivecase $statedispatch,_commands()helpersclap_complete::zsh.rssrc/cmdline.cppmsnapshot(), fourgenerate_completions()overloads,App::completions()App→Command→ shell outputtests/completions_test.cppdocs/api.mdexamples/completions/completionssubcommandArchitecture comparison (clap → cmdline)
Fishgeneratorgen_fish_innerrecursive walkgen_innerwithstd::span<Option>for root globalsBashgeneratorformat!template with placeholdersgenerate()without <<streaming, 7 helpers in anonymous namespaceZshgeneratorget_args_of/get_subcommands_of/subcommand_detailswalk_commandvs zsh identifiersget_short_and_visible_aliases(), subcommand aliasesshort_andlong_namepossible_values/ValueHintcompgen -W/_files/_command_namesetc._default(zsh) orcompgen -f(bash)(-x --y)prefix on specsCommand::build()root_globalsspan + dedupTrade-offs
completions::Commandis built eagerly viasnapshot(), copying vectors. For command trees with hundreds of subcommands this could be noticeable, but the typical case is negligible.walk_commandreturns a rawconst Command*. Callers must not hold it past the lifetime of the rootCommand.walk_command/flatten_subcommands/has_optionrather than sharing a utility module. This keeps each.cppmself-contained, matchingfish.cppm.Validation
All three generators produce valid output:
How to test
mcpp build(orxmake)xmake run cmdline_testcd examples/completions && mcpp build && ./target/*/bin/completions completions --shell bash