Don't split by list delimiter in positional lists

This commit is contained in:
Alexander Galanin 2023-03-11 16:21:08 +04:00
parent a526762eb8
commit 8774fded36
2 changed files with 78 additions and 5 deletions

View File

@ -360,6 +360,9 @@ class Value : public std::enable_shared_from_this<Value>
std::shared_ptr<Value> std::shared_ptr<Value>
clone() const = 0; clone() const = 0;
virtual void
add(const std::string& text) const = 0;
virtual void virtual void
parse(const std::string& text) const = 0; parse(const std::string& text) const = 0;
@ -1056,6 +1059,22 @@ parse_value(const std::string& text, std::vector<T>& value)
} }
} }
template <typename T>
void
add_value(const std::string& text, T& value)
{
parse_value(text, value);
}
template <typename T>
void
add_value(const std::string& text, std::vector<T>& value)
{
T v;
add_value(text, v);
value.emplace_back(std::move(v));
}
#ifdef CXXOPTS_HAS_OPTIONAL #ifdef CXXOPTS_HAS_OPTIONAL
template <typename T> template <typename T>
void void
@ -1129,6 +1148,12 @@ class abstract_value : public Value
m_implicit_value = rhs.m_implicit_value; m_implicit_value = rhs.m_implicit_value;
} }
void
add(const std::string& text) const override
{
add_value(text, *m_store);
}
void void
parse(const std::string& text) const override parse(const std::string& text) const override
{ {
@ -1414,6 +1439,19 @@ struct HelpGroupDetails
class OptionValue class OptionValue
{ {
public: public:
void
add
(
const std::shared_ptr<const OptionDetails>& details,
const std::string& text
)
{
ensure_value(details);
++m_count;
m_value->add(text);
m_long_names = &details->long_names();
}
void void
parse parse
( (
@ -1784,7 +1822,7 @@ class OptionParser
); );
void void
add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg); add_to_option(const std::shared_ptr<OptionDetails>& value, const std::string& arg);
void void
parse_option parse_option
@ -2330,9 +2368,13 @@ OptionParser::checked_parse_arg
inline inline
void void
OptionParser::add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg) OptionParser::add_to_option(const std::shared_ptr<OptionDetails>& value, const std::string& arg)
{ {
parse_option(iter->second, option, arg); auto hash = value->hash();
auto& result = m_parsed[hash];
result.add(value, arg);
m_sequential.emplace_back(value->essential_name(), arg);
} }
inline inline
@ -2349,14 +2391,14 @@ OptionParser::consume_positional(const std::string& a, PositionalListIterator& n
auto& result = m_parsed[iter->second->hash()]; auto& result = m_parsed[iter->second->hash()];
if (result.count() == 0) if (result.count() == 0)
{ {
add_to_option(iter, *next, a); add_to_option(iter->second, a);
++next; ++next;
return true; return true;
} }
++next; ++next;
continue; continue;
} }
add_to_option(iter, *next, a); add_to_option(iter->second, a);
return true; return true;
} }
throw_or_mimic<exceptions::no_such_option>(*next); throw_or_mimic<exceptions::no_such_option>(*next);

View File

@ -288,6 +288,37 @@ TEST_CASE("Positional with empty arguments", "[positional]") {
REQUIRE(actual == expected); REQUIRE(actual == expected);
} }
TEST_CASE("Positional with list delimiter", "[positional]") {
std::string single;
std::vector<std::string> positional;
cxxopts::Options options("test_all_positional_list_delimiter", " - test all positional with list delimiters");
options.add_options()
("single", "Single positional param",
cxxopts::value<std::string>(single))
("positional", "Positional parameters vector",
cxxopts::value<std::vector<std::string>>(positional))
;
Argv av({"tester", "a,b", "c,d", "e"});
auto argc = av.argc();
auto argv = av.argv();
std::vector<std::string> pos_names = {"single", "positional"};
options.parse_positional(pos_names.begin(), pos_names.end());
auto result = options.parse(argc, argv);
CHECK(result.unmatched().size() == 0);
REQUIRE(positional.size() == 2);
CHECK(single == "a,b");
CHECK(positional[0] == "c,d");
CHECK(positional[1] == "e");
}
TEST_CASE("Empty with implicit value", "[implicit]") TEST_CASE("Empty with implicit value", "[implicit]")
{ {
cxxopts::Options options("empty_implicit", "doesn't handle empty"); cxxopts::Options options("empty_implicit", "doesn't handle empty");