cmArgumentParser: support storing a context value with parsing

This allows for parsing of contextual keywords. For example:

```
some_command(
  ARG_WITH_CONTEXT foo
  CONTEXT bar
  ARG_WITH_CONTEXT quux)
```

will be able to store that `foo` happened without context (or, rather,
its default value) and `quux` was provided in a `bar` context.
This commit is contained in:
Ben Boeckel 2023-07-19 16:44:59 -04:00
parent c9ca5f6326
commit 93993c7ad4

View File

@ -7,6 +7,7 @@
#include <cassert>
#include <cstddef>
#include <functional>
#include <iterator>
#include <map>
#include <string>
#include <utility>
@ -176,6 +177,17 @@ public:
void Bind(MaybeEmpty<std::vector<std::string>>& val);
void Bind(NonEmpty<std::vector<std::string>>& val);
void Bind(std::vector<std::vector<std::string>>& val);
template <typename U>
void Bind(NonEmpty<std::vector<std::pair<std::string, U>>>& val,
U const& context)
{
this->Bind(
[&val, &context](cm::string_view arg) -> Continue {
val.emplace_back(std::string(arg), context);
return Continue::Yes;
},
ExpectAtLeast{ 1 });
}
// cm::optional<> records the presence the keyword to which it binds.
template <typename T>
@ -187,6 +199,15 @@ public:
this->Bind(*optVal);
}
template <typename T, typename U>
void Bind(cm::optional<T>& optVal, U const& context)
{
if (!optVal) {
optVal.emplace();
}
this->Bind(*optVal, context);
}
template <typename Range>
void Parse(Range const& args, std::size_t pos = 0)
{
@ -232,6 +253,17 @@ public:
return *this;
}
template <typename T, typename U>
cmArgumentParser& BindWithContext(cm::static_string_view name,
T Result::*member, U Result::*context)
{
this->Base::Bind(name, [member, context](Instance& instance) {
auto* result = static_cast<Result*>(instance.Result);
instance.Bind(result->*member, result->*context);
});
return *this;
}
cmArgumentParser& Bind(cm::static_string_view name,
Continue (Result::*member)(cm::string_view),
ExpectAtLeast expect = { 1 })