1
0
forked from Alepha/Alepha

Online documentation for single-letter options.

It's mostly worked out, but there's a few odd corner cases,
especially around the auto-gen of negation options.  It also
got me to start thinking about "is a required negatable option
still required of its negation?"  Similar questions revolve
around requiring such options.

I'm punting on these for now, but I think it makes sense to
perhaps make those incompatible with such domains.  Or to treat
the two options as a shared-fate unit.  But is `-O -o -O -o` a
violation of exclusivity?  If we wind up returning to the default
state, have we actually passed that option, with respect to
"requirement"?  I have to think about that some more.

A commit message isn't the best place to capture this, but I
didn't want to lose this thought.
This commit is contained in:
2025-09-06 02:36:17 -04:00
parent e41198c294
commit 95e6f1ac04
2 changed files with 61 additions and 7 deletions

View File

@ -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 >