diff --git a/ProgramOptions.cc b/ProgramOptions.cc index aeebd2b..13eabcd 100644 --- a/ProgramOptions.cc +++ b/ProgramOptions.cc @@ -46,6 +46,8 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m std::map< std::type_index, std::set< const DomainBase * > > domains; ArgumentStance argumentStance; + + std::set< char > shortAliases; }; namespace @@ -62,6 +64,8 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m struct ExclusivityEntry { + // This gets used during the parsing process to indicate which previous entry from this domain + // has been seen, if any. std::optional< std::string > previous; }; @@ -157,6 +161,20 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m incompatibles.erase( name ); if( incompatibles.empty() ) return; + std::set< std::string > incompatibleAliases; + for( const auto &incompat: incompatibles ) + { + const auto &aliases= programOptions().at( incompat ).shortAliases; + for( const auto alias: aliases ) + { + incompatibleAliases.insert( "-"s + alias ); + } + } + for( const auto &alias: incompatibleAliases ) + { + incompatibles.insert( alias ); + } + out << "\nIncompatible with: \n\n"; bool first= true; for( const auto &incompat: incompatibles ) @@ -168,6 +186,19 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m out << std::endl; } + void + aliasHelpText( std::ostream &out, const std::string &name ) + { + const auto &aliases= programOptions().at( name ).shortAliases; + + if( aliases.empty() ) return; + + for( const auto &alias: aliases ) + { + out << "-" << alias << ":" << std::endl; + } + } + void printAllOptionsHelp( const std::optional< std::string > canonicalProgramName ) { @@ -200,9 +231,10 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m { // When turning off wrapping, here, we also emit a newline between entries. AutoRAII endline{ []{}, []{ std::cout << std::endl; } }; + aliasHelpText( std::cout, name ); auto wrapping= adaptStream( StartWrap{ width, alignmentWidth }, std::cout ); - const auto &[ _, helpText, defaultBuilder, domains, argumentStance ]= def; + const auto &[ _, helpText, defaultBuilder, domains, argumentStance, aliases ]= def; VariableMap substitutions= { @@ -244,6 +276,7 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m } std::cout << std::endl; + std::cout << EndWrap; } } } @@ -307,7 +340,8 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m throw std::logic_error{ "Short form alias mapping of `-"s + key + "` for option `--" + name + "` is invalid, because the long name doesn't exist." }; } - const auto &[ _, help, builder, domains, stance ]= programOptions().at( "--" + name ); + + const auto &stance= programOptions().at( "--" + name ).argumentStance; if( stance == ArgumentStance::Required ) { throw std::logic_error{ "Short form alias mapping of `-"s + key + "` for option `--" @@ -322,7 +356,21 @@ namespace Alepha::Hydrogen ::detail:: ProgramOptions_m { validateShortAliases( shortAliases ); - // TODO: Incorporate short aliases into the help... + for( const auto &[ alias, option ]: shortAliases ) + { + programOptions().at( "--"s + option ).shortAliases.insert( alias ); + + const auto &domainMap= programOptions().at( "--"s + option ).domains; + for( const auto &[ requirement, domains ]: domainMap ) + { + if( requirement != typeid( RequirementDomain ) ) continue; + + for( const auto &domain: domains ) + { + requiredOptions()[ domain ].push_back( "-"s + alias ); + } + } + } } std::vector< std::string > diff --git a/example.cc b/example.cc index 273ebd8..ae23c2c 100644 --- a/example.cc +++ b/example.cc @@ -16,11 +16,16 @@ namespace bool optionC= false; + const Alepha::RequirementDomain need; + const Alepha::ExclusivityDomain block; + //const Alepha::detail::ProgramOptions_m::Domain< nil > need; + //const Alepha::detail::ProgramOptions_m::Domain< nil > block; + auto init= enroll <=[] { - --"set-a"_option << optionA << "The option is an integer. !default!"; - --"set-b"_option << optionB << "The option is a string, no defaults."; - --"set-c"_option << optionC << "This sets the 'C' flag."; + --"set-a"_option << need << optionA << "The option is an integer. !default!"; + --"set-b"_option << block << optionB << "The option is a string, no defaults."; + --"set-c"_option << block << need << optionC << "This sets the 'C' flag."; }; } @@ -28,7 +33,8 @@ int main( const int argcnt, const char *const *const argvec ) try { - const auto args= Alepha::handleOptions( argcnt, argvec, { { 'c', "set-c" }, { 'C', "no-set-c" } } ); + const auto args= Alepha::handleOptions( argcnt, argvec, { { 'c', "set-c" }, { 'C', "no-set-c" }, { 'D', "dump-color-env-var" }, + { 'L', "list-color-variables" }, } ); std::cout << "A is set to: " << optionA << std::endl; std::cout << "B is set to: " << ( optionB.has_value() ? optionB.value() : "nullopt"s ) << std::endl;