Ensure the completion marker is not processed beyond completion

I was surprised to see an error mentioning ___COMPLETE___ when trying to
complete a flag argument that had no completer implemented
This commit is contained in:
Naïm Favier 2022-02-18 13:24:39 +01:00
parent 5f06a91bf7
commit a6d7cd4183
No known key found for this signature in database
GPG key ID: 49B07322580B7EE2

View file

@ -127,11 +127,11 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
if (flag.handler.arity == ArityAny) break; if (flag.handler.arity == ArityAny) break;
throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity); throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
} }
if (flag.completer) if (auto prefix = needsCompletion(*pos)) {
if (auto prefix = needsCompletion(*pos)) { anyCompleted = true;
anyCompleted = true; if (flag.completer)
flag.completer(n, *prefix); flag.completer(n, *prefix);
} }
args.push_back(*pos++); args.push_back(*pos++);
} }
if (!anyCompleted) if (!anyCompleted)
@ -146,6 +146,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
&& hasPrefix(name, std::string(*prefix, 2))) && hasPrefix(name, std::string(*prefix, 2)))
completions->add("--" + name, flag->description); completions->add("--" + name, flag->description);
} }
return false;
} }
auto i = longFlags.find(std::string(*pos, 2)); auto i = longFlags.find(std::string(*pos, 2));
if (i == longFlags.end()) return false; if (i == longFlags.end()) return false;
@ -187,10 +188,12 @@ bool Args::processArgs(const Strings & args, bool finish)
{ {
std::vector<std::string> ss; std::vector<std::string> ss;
for (const auto &[n, s] : enumerate(args)) { for (const auto &[n, s] : enumerate(args)) {
ss.push_back(s); if (auto prefix = needsCompletion(s)) {
if (exp.completer) ss.push_back(*prefix);
if (auto prefix = needsCompletion(s)) if (exp.completer)
exp.completer(n, *prefix); exp.completer(n, *prefix);
} else
ss.push_back(s);
} }
exp.handler.fun(ss); exp.handler.fun(ss);
expectedArgs.pop_front(); expectedArgs.pop_front();
@ -322,16 +325,16 @@ MultiCommand::MultiCommand(const Commands & commands_)
.optional = true, .optional = true,
.handler = {[=](std::string s) { .handler = {[=](std::string s) {
assert(!command); assert(!command);
if (auto prefix = needsCompletion(s)) {
for (auto & [name, command] : commands)
if (hasPrefix(name, *prefix))
completions->add(name);
}
auto i = commands.find(s); auto i = commands.find(s);
if (i == commands.end()) if (i == commands.end())
throw UsageError("'%s' is not a recognised command", s); throw UsageError("'%s' is not a recognised command", s);
command = {s, i->second()}; command = {s, i->second()};
command->second->parent = this; command->second->parent = this;
}},
.completer = {[&](size_t, std::string_view prefix) {
for (auto & [name, command] : commands)
if (hasPrefix(name, prefix))
completions->add(name);
}} }}
}); });