aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavel Belikov <pavel.fuchs.belikov@gmail.com>2017-12-23 20:47:59 +0300
committerPavel Belikov <pavel.fuchs.belikov@gmail.com>2017-12-23 20:47:59 +0300
commit39fb642c4148cc12eefffcef056a4cbfbbfab314 (patch)
treeeac112b231932687a229553a14f550b05e69550c
parentadd completion for flag values (diff)
downloadargs.hxx-39fb642c4148cc12eefffcef056a4cbfbbfab314.tar.xz
fix bash equal sign tokenization
-rw-r--r--args.hxx47
-rw-r--r--test.cxx8
2 files changed, 46 insertions, 9 deletions
diff --git a/args.hxx b/args.hxx
index 91cd368..42934bc 100644
--- a/args.hxx
+++ b/args.hxx
@@ -2209,14 +2209,14 @@ namespace args
Positional
};
- OptionType ParseOption(const std::string &s)
+ OptionType ParseOption(const std::string &s, bool allowEmpty = false)
{
- if (s.find(longprefix) == 0 && s.length() > longprefix.length())
+ if (s.find(longprefix) == 0 && (allowEmpty || s.length() > longprefix.length()))
{
return OptionType::LongFlag;
}
- if (s.find(shortprefix) == 0 && s.length() > shortprefix.length())
+ if (s.find(shortprefix) == 0 && (allowEmpty || s.length() > shortprefix.length()))
{
return OptionType::ShortFlag;
}
@@ -2435,7 +2435,13 @@ namespace args
{
if (cur.empty() || choice.find(cur) == 0)
{
- completion->reply.push_back(choice);
+ if (completion->syntax == "bash" && ParseOption(choice) == OptionType::LongFlag && choice.find(longseparator) != std::string::npos)
+ {
+ completion->reply.push_back(choice.substr(choice.find(longseparator) + 1));
+ } else
+ {
+ completion->reply.push_back(choice);
+ }
return true;
}
@@ -2454,8 +2460,9 @@ namespace args
const auto &chunk = *it;
auto pos = GetNextPositional();
std::vector<Command *> commands = GetCommands();
+ const auto optionType = ParseOption(chunk, true);
- if (!commands.empty() && (chunk.empty() || ParseOption(chunk) == OptionType::Positional))
+ if (!commands.empty() && (chunk.empty() || optionType == OptionType::Positional))
{
for (auto &cmd : commands)
{
@@ -2482,7 +2489,7 @@ namespace args
if ((pos->GetOptions() & Options::HiddenFromCompletion) == Options::None)
{
auto choices = pos->HelpChoices(helpParams);
- hasPositionalCompletion = !choices.empty();
+ hasPositionalCompletion = !choices.empty() || optionType != OptionType::Positional;
for (auto &choice : choices)
{
AddCompletionReply(chunk, choice);
@@ -2513,7 +2520,7 @@ namespace args
}
}
- if (ParseOption(chunk) == OptionType::LongFlag && allowJoinedLongValue)
+ if (optionType == OptionType::LongFlag && allowJoinedLongValue)
{
const auto separator = longseparator.empty() ? chunk.npos : chunk.find(longseparator);
if (separator != chunk.npos)
@@ -2527,7 +2534,7 @@ namespace args
}
}
}
- } else if (ParseOption(chunk) == OptionType::ShortFlag && allowJoinedShortValue)
+ } else if (optionType == OptionType::ShortFlag && allowJoinedShortValue)
{
if (chunk.size() > shortprefix.size() + 1)
{
@@ -2665,6 +2672,30 @@ namespace args
std::vector<std::string> curArgs(++it, end);
curArgs.resize(completion->cword);
+
+ if (completion->syntax == "bash")
+ {
+ // bash tokenizes --flag=value as --flag=value
+ for (size_t idx = 0; idx < curArgs.size(); )
+ {
+ if (idx > 0 && curArgs[idx] == "=")
+ {
+ curArgs[idx - 1] += "=";
+ if (idx + 1 < curArgs.size())
+ {
+ curArgs[idx - 1] += curArgs[idx + 1];
+ curArgs.erase(curArgs.begin() + idx, curArgs.begin() + idx + 2);
+ } else
+ {
+ curArgs.erase(curArgs.begin() + idx);
+ }
+ } else
+ {
+ ++idx;
+ }
+ }
+
+ }
#ifndef ARGS_NOEXCEPT
try
{
diff --git a/test.cxx b/test.cxx
index 4768cde..94defee 100644
--- a/test.cxx
+++ b/test.cxx
@@ -1260,8 +1260,14 @@ TEST_CASE("Completion works as expected", "[args]")
args::MapFlag<std::string, int> m(p, "mappos", "mappos", {'m', "map"}, {{"1",1}, {"2", 2}});
REQUIRE_THROWS_WITH(p.ParseArgs(std::vector<std::string>{"--completion", "bash", "2", "test", "-m", ""}), Equals("1\n2"));
- REQUIRE_THROWS_WITH(p.ParseArgs(std::vector<std::string>{"--completion", "bash", "1", "test", "--map="}), Equals("--map=1\n--map=2"));
+ REQUIRE_THROWS_WITH(p.ParseArgs(std::vector<std::string>{"--completion", "bash", "1", "test", "--map="}), Equals("1\n2"));
+ REQUIRE_THROWS_WITH(p.ParseArgs(std::vector<std::string>{"--completion", "bash", "2", "test", "--map", "="}), Equals("1\n2"));
REQUIRE_THROWS_WITH(p.ParseArgs(std::vector<std::string>{"--completion", "bash", "1", "test", "-m1"}), Equals("-m1"));
+
+ args::Positional<std::string> pos(p, "name", "desc");
+ REQUIRE_THROWS_WITH(p.ParseArgs(std::vector<std::string>{"--completion", "bash", "1", "test", ""}), Equals(""));
+ REQUIRE_THROWS_WITH(p.ParseArgs(std::vector<std::string>{"--completion", "bash", "1", "test", "-"}), Equals("-f\n-b\n-m"));
+ REQUIRE_THROWS_WITH(p.ParseArgs(std::vector<std::string>{"--completion", "bash", "1", "test", "--"}), Equals("--foo\n--bar\n--map"));
}
#undef ARGS_HXX