From f7e81802f2fd3996983376dc2c3d638fdf35f396 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 20 Jul 2022 15:15:51 -0400 Subject: cmArgumentParser: Offer binding for list of parsed keywords Some clients ask for this list in their `Parse()` call. Offer them a way to express this request as a binding. --- Source/cmArgumentParser.cxx | 3 +++ Source/cmArgumentParser.h | 24 ++++++++++++++++++++++++ Tests/CMakeLib/testArgumentParser.cxx | 23 +++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/Source/cmArgumentParser.cxx b/Source/cmArgumentParser.cxx index fafae13..d4a3c8a 100644 --- a/Source/cmArgumentParser.cxx +++ b/Source/cmArgumentParser.cxx @@ -86,6 +86,9 @@ void Instance::Consume(cm::string_view arg) if (this->ParsedKeywords != nullptr) { this->ParsedKeywords->emplace_back(it->first); } + if (this->Bindings.ParsedKeyword) { + this->Bindings.ParsedKeyword(*this, it->first); + } it->second(*this); return; } diff --git a/Source/cmArgumentParser.h b/Source/cmArgumentParser.h index 70deaa6..7e219ae 100644 --- a/Source/cmArgumentParser.h +++ b/Source/cmArgumentParser.h @@ -81,6 +81,7 @@ class ActionMap public: KeywordActionMap Keywords; KeywordNameAction KeywordMissingValue; + KeywordNameAction ParsedKeyword; }; class Base @@ -103,6 +104,12 @@ public: static_cast(inserted); } + void BindParsedKeyword(KeywordNameAction action) + { + assert(!this->Bindings.ParsedKeyword); + this->Bindings.ParsedKeyword = std::move(action); + } + void BindKeywordMissingValue(KeywordNameAction action) { assert(!this->Bindings.KeywordMissingValue); @@ -187,6 +194,16 @@ public: return *this; } + cmArgumentParser& BindParsedKeywords( + std::vector Result::*member) + { + this->Base::BindParsedKeyword( + [member](Instance& instance, cm::string_view arg) { + (static_cast(instance.Result)->*member).emplace_back(arg); + }); + return *this; + } + template bool Parse(Result& result, Range const& args, std::vector* unparsedArguments, @@ -221,6 +238,13 @@ public: return *this; } + cmArgumentParser& BindParsedKeywords(std::vector& ref) + { + this->Base::BindParsedKeyword( + [&ref](Instance&, cm::string_view arg) { ref.emplace_back(arg); }); + return *this; + } + template ParseResult Parse( Range const& args, std::vector* unparsedArguments, diff --git a/Tests/CMakeLib/testArgumentParser.cxx b/Tests/CMakeLib/testArgumentParser.cxx index 9db7936..5460356 100644 --- a/Tests/CMakeLib/testArgumentParser.cxx +++ b/Tests/CMakeLib/testArgumentParser.cxx @@ -38,6 +38,8 @@ struct Result : public ArgumentParser::ParseResult std::vector> Multi2; cm::optional>> Multi3; cm::optional>> Multi4; + + std::vector ParsedKeywords; }; std::initializer_list const args = { @@ -67,6 +69,23 @@ bool verifyResult(Result const& result, { static std::vector const foobar = { "foo", "bar" }; static std::vector const barfoo = { "bar", "foo" }; + static std::vector const parsedKeywords = { + /* clang-format off */ + "OPTION_1", + "STRING_1", + "STRING_2", + "STRING_4", + "LIST_1", + "LIST_2", + "LIST_3", + "LIST_3", + "LIST_4", + "LIST_6", + "MULTI_2", + "MULTI_3", + "MULTI_3", + /* clang-format on */ + }; static std::map const keywordErrors = { { "STRING_1"_s, " missing required value\n" }, { "LIST_1"_s, " missing required value\n" }, @@ -114,6 +133,8 @@ bool verifyResult(Result const& result, ASSERT_TRUE(unparsedArguments.size() == 1); ASSERT_TRUE(unparsedArguments[0] == "bar"); + ASSERT_TRUE(result.ParsedKeywords == parsedKeywords); + ASSERT_TRUE(result.GetKeywordErrors().size() == keywordErrors.size()); for (auto const& ke : result.GetKeywordErrors()) { auto const ki = keywordErrors.find(ke.first); @@ -147,6 +168,7 @@ bool testArgumentParserDynamic() .Bind("MULTI_2"_s, result.Multi2) .Bind("MULTI_3"_s, result.Multi3) .Bind("MULTI_4"_s, result.Multi4) + .BindParsedKeywords(result.ParsedKeywords) .Parse(args, &unparsedArguments); return verifyResult(result, unparsedArguments); @@ -170,6 +192,7 @@ static auto const parserStatic = // .Bind("MULTI_2"_s, &Result::Multi2) .Bind("MULTI_3"_s, &Result::Multi3) .Bind("MULTI_4"_s, &Result::Multi4) + .BindParsedKeywords(&Result::ParsedKeywords) /* keep semicolon on own line */; bool testArgumentParserStatic() -- cgit v0.12