aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libutil/args.cc90
-rw-r--r--src/libutil/args.hh123
-rw-r--r--src/nix/cat.cc12
-rw-r--r--src/nix/command.hh5
-rw-r--r--src/nix/hash.cc6
-rw-r--r--src/nix/installables.cc8
-rw-r--r--src/nix/ls.cc12
-rw-r--r--src/nix/repl.cc6
-rw-r--r--src/nix/run.cc6
9 files changed, 145 insertions, 123 deletions
diff --git a/src/libutil/args.cc b/src/libutil/args.cc
index 257b4b6c4..c389090ae 100644
--- a/src/libutil/args.cc
+++ b/src/libutil/args.cc
@@ -86,7 +86,7 @@ void Args::printHelp(const string & programName, std::ostream & out)
for (auto & exp : expectedArgs) {
std::cout << renderLabels({exp.label});
// FIXME: handle arity > 1
- if (exp.arity == 0) std::cout << "...";
+ if (exp.handler.arity == ArityAny) std::cout << "...";
if (exp.optional) std::cout << "?";
}
std::cout << "\n";
@@ -127,8 +127,8 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
if (flag.handler.arity == ArityAny) break;
throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
}
- if (auto prefix = needsCompletion(*pos))
- if (flag.completer)
+ if (flag.completer)
+ if (auto prefix = needsCompletion(*pos))
flag.completer(n, *prefix);
args.push_back(*pos++);
}
@@ -179,12 +179,17 @@ bool Args::processArgs(const Strings & args, bool finish)
bool res = false;
- if ((exp.arity == 0 && finish) ||
- (exp.arity > 0 && args.size() == exp.arity))
+ if ((exp.handler.arity == ArityAny && finish) ||
+ (exp.handler.arity != ArityAny && args.size() == exp.handler.arity))
{
std::vector<std::string> ss;
- for (auto & s : args) ss.push_back(s);
- exp.handler(std::move(ss));
+ for (const auto &[n, s] : enumerate(args)) {
+ ss.push_back(s);
+ if (exp.completer)
+ if (auto prefix = needsCompletion(s))
+ exp.completer(n, *prefix);
+ }
+ exp.handler.fun(ss);
expectedArgs.pop_front();
res = true;
}
@@ -214,46 +219,17 @@ Args::Flag Args::Flag::mkHashTypeFlag(std::string && longName, HashType * ht)
};
}
-void completePath(size_t, std::string_view s)
+void completePath(size_t, std::string_view prefix)
{
- if (auto prefix = needsCompletion(s)) {
- pathCompletions = true;
- glob_t globbuf;
- if (glob((*prefix + "*").c_str(), GLOB_NOESCAPE | GLOB_TILDE, nullptr, &globbuf) == 0) {
- for (size_t i = 0; i < globbuf.gl_pathc; ++i)
- completions->insert(globbuf.gl_pathv[i]);
- globfree(&globbuf);
- }
+ pathCompletions = true;
+ glob_t globbuf;
+ if (glob((std::string(prefix) + "*").c_str(), GLOB_NOESCAPE | GLOB_TILDE, nullptr, &globbuf) == 0) {
+ for (size_t i = 0; i < globbuf.gl_pathc; ++i)
+ completions->insert(globbuf.gl_pathv[i]);
+ globfree(&globbuf);
}
}
-void Args::expectPathArg(const std::string & label, string * dest, bool optional)
-{
- expectedArgs.push_back({
- .label = label,
- .arity = 1,
- .optional = optional,
- .handler = {[=](std::vector<std::string> ss) {
- completePath(0, ss[0]);
- *dest = ss[0];
- }}
- });
-}
-
-void Args::expectPathArgs(const std::string & label, std::vector<std::string> * dest)
-{
- expectedArgs.push_back({
- .label = label,
- .arity = 0,
- .optional = false,
- .handler = {[=](std::vector<std::string> ss) {
- for (auto & s : ss)
- completePath(0, s);
- *dest = std::move(ss);
- }}
- });
-}
-
Strings argvToStrings(int argc, char * * argv)
{
Strings args;
@@ -301,18 +277,22 @@ void Command::printHelp(const string & programName, std::ostream & out)
MultiCommand::MultiCommand(const Commands & commands)
: commands(commands)
{
- expectedArgs.push_back(ExpectedArg{"command", 1, true, [=](std::vector<std::string> ss) {
- assert(!command);
- if (auto prefix = needsCompletion(ss[0])) {
- for (auto & [name, command] : commands)
- if (hasPrefix(name, *prefix))
- completions->insert(name);
- }
- auto i = commands.find(ss[0]);
- if (i == commands.end())
- throw UsageError("'%s' is not a recognised command", ss[0]);
- command = {ss[0], i->second()};
- }});
+ expectArgs({
+ .label = "command",
+ .optional = true,
+ .handler = {[=](std::string s) {
+ assert(!command);
+ if (auto prefix = needsCompletion(s)) {
+ for (auto & [name, command] : commands)
+ if (hasPrefix(name, *prefix))
+ completions->insert(name);
+ }
+ auto i = commands.find(s);
+ if (i == commands.end())
+ throw UsageError("'%s' is not a recognised command", s);
+ command = {s, i->second()};
+ }}
+ });
categories[Command::catDefault] = "Available commands";
}
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index f93459c96..250244162 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -28,55 +28,60 @@ protected:
static const size_t ArityAny = std::numeric_limits<size_t>::max();
+ struct Handler
+ {
+ std::function<void(std::vector<std::string>)> fun;
+ size_t arity;
+
+ Handler() {}
+
+ Handler(std::function<void(std::vector<std::string>)> && fun)
+ : fun(std::move(fun))
+ , arity(ArityAny)
+ { }
+
+ Handler(std::function<void()> && handler)
+ : fun([handler{std::move(handler)}](std::vector<std::string>) { handler(); })
+ , arity(0)
+ { }
+
+ Handler(std::function<void(std::string)> && handler)
+ : fun([handler{std::move(handler)}](std::vector<std::string> ss) {
+ handler(std::move(ss[0]));
+ })
+ , arity(1)
+ { }
+
+ Handler(std::function<void(std::string, std::string)> && handler)
+ : fun([handler{std::move(handler)}](std::vector<std::string> ss) {
+ handler(std::move(ss[0]), std::move(ss[1]));
+ })
+ , arity(2)
+ { }
+
+ Handler(std::vector<std::string> * dest)
+ : fun([=](std::vector<std::string> ss) { *dest = ss; })
+ , arity(ArityAny)
+ { }
+
+ template<class T>
+ Handler(T * dest)
+ : fun([=](std::vector<std::string> ss) { *dest = ss[0]; })
+ , arity(1)
+ { }
+
+ template<class T>
+ Handler(T * dest, const T & val)
+ : fun([=](std::vector<std::string> ss) { *dest = val; })
+ , arity(0)
+ { }
+ };
+
/* Flags. */
struct Flag
{
typedef std::shared_ptr<Flag> ptr;
- struct Handler
- {
- std::function<void(std::vector<std::string>)> fun;
- size_t arity;
-
- Handler() {}
-
- Handler(std::function<void(std::vector<std::string>)> && fun)
- : fun(std::move(fun))
- , arity(ArityAny)
- { }
-
- Handler(std::function<void()> && handler)
- : fun([handler{std::move(handler)}](std::vector<std::string>) { handler(); })
- , arity(0)
- { }
-
- Handler(std::function<void(std::string)> && handler)
- : fun([handler{std::move(handler)}](std::vector<std::string> ss) {
- handler(std::move(ss[0]));
- })
- , arity(1)
- { }
-
- Handler(std::function<void(std::string, std::string)> && handler)
- : fun([handler{std::move(handler)}](std::vector<std::string> ss) {
- handler(std::move(ss[0]), std::move(ss[1]));
- })
- , arity(2)
- { }
-
- template<class T>
- Handler(T * dest)
- : fun([=](std::vector<std::string> ss) { *dest = ss[0]; })
- , arity(1)
- { }
-
- template<class T>
- Handler(T * dest, const T & val)
- : fun([=](std::vector<std::string> ss) { *dest = val; })
- , arity(0)
- { }
- };
-
std::string longName;
char shortName = 0;
std::string description;
@@ -99,9 +104,9 @@ protected:
struct ExpectedArg
{
std::string label;
- size_t arity = 0; // 0 = any
bool optional = false;
- std::function<void(std::vector<std::string>)> handler;
+ Handler handler;
+ std::function<void(size_t, std::string_view)> completer;
};
std::list<ExpectedArg> expectedArgs;
@@ -175,26 +180,30 @@ public:
});
}
+ void expectArgs(ExpectedArg && arg)
+ {
+ expectedArgs.emplace_back(std::move(arg));
+ }
+
/* Expect a string argument. */
void expectArg(const std::string & label, string * dest, bool optional = false)
{
- expectedArgs.push_back(ExpectedArg{label, 1, optional, [=](std::vector<std::string> ss) {
- *dest = ss[0];
- }});
+ expectArgs({
+ .label = label,
+ .optional = true,
+ .handler = {dest}
+ });
}
- void expectPathArg(const std::string & label, string * dest, bool optional = false);
-
/* Expect 0 or more arguments. */
void expectArgs(const std::string & label, std::vector<std::string> * dest)
{
- expectedArgs.push_back(ExpectedArg{label, 0, false, [=](std::vector<std::string> ss) {
- *dest = std::move(ss);
- }});
+ expectArgs({
+ .label = label,
+ .handler = {dest}
+ });
}
- void expectPathArgs(const std::string & label, std::vector<std::string> * dest);
-
friend class MultiCommand;
};
@@ -266,6 +275,6 @@ extern bool pathCompletions;
std::optional<std::string> needsCompletion(std::string_view s);
-void completePath(size_t, std::string_view s);
+void completePath(size_t, std::string_view prefix);
}
diff --git a/src/nix/cat.cc b/src/nix/cat.cc
index eeee1e529..b528a0507 100644
--- a/src/nix/cat.cc
+++ b/src/nix/cat.cc
@@ -25,7 +25,11 @@ struct CmdCatStore : StoreCommand, MixCat
{
CmdCatStore()
{
- expectPathArg("path", &path);
+ expectArgs({
+ .label = "path",
+ .handler = {&path},
+ .completer = completePath
+ });
}
std::string description() override
@@ -47,7 +51,11 @@ struct CmdCatNar : StoreCommand, MixCat
CmdCatNar()
{
- expectPathArg("nar", &narPath);
+ expectArgs({
+ .label = "nar",
+ .handler = {&narPath},
+ .completer = completePath
+ });
expectArg("path", &path);
}
diff --git a/src/nix/command.hh b/src/nix/command.hh
index 6b4781303..0738c0f91 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -73,10 +73,7 @@ struct InstallablesCommand : virtual Args, SourceExprCommand
{
std::vector<std::shared_ptr<Installable>> installables;
- InstallablesCommand()
- {
- expectArgs("installables", &_installables);
- }
+ InstallablesCommand();
void prepare() override;
diff --git a/src/nix/hash.cc b/src/nix/hash.cc
index 0f460c668..d5636eb47 100644
--- a/src/nix/hash.cc
+++ b/src/nix/hash.cc
@@ -31,7 +31,11 @@ struct CmdHash : Command
.labels({"modulus"})
.dest(&modulus);
#endif
- expectPathArgs("paths", &paths);
+ expectArgs({
+ .label = "paths",
+ .handler = {&paths},
+ .completer = completePath
+ });
}
std::string description() override
diff --git a/src/nix/installables.cc b/src/nix/installables.cc
index c144a7e70..abc642e11 100644
--- a/src/nix/installables.cc
+++ b/src/nix/installables.cc
@@ -571,6 +571,14 @@ StorePathSet toDerivations(ref<Store> store,
return drvPaths;
}
+InstallablesCommand::InstallablesCommand()
+{
+ expectArgs({
+ .label = "installables",
+ .handler = {&_installables},
+ });
+}
+
void InstallablesCommand::prepare()
{
if (_installables.empty() && useDefaultInstallables())
diff --git a/src/nix/ls.cc b/src/nix/ls.cc
index aac082422..dc7e370b9 100644
--- a/src/nix/ls.cc
+++ b/src/nix/ls.cc
@@ -85,7 +85,11 @@ struct CmdLsStore : StoreCommand, MixLs
{
CmdLsStore()
{
- expectPathArg("path", &path);
+ expectArgs({
+ .label = "path",
+ .handler = {&path},
+ .completer = completePath
+ });
}
Examples examples() override
@@ -117,7 +121,11 @@ struct CmdLsNar : Command, MixLs
CmdLsNar()
{
- expectPathArg("nar", &narPath);
+ expectArgs({
+ .label = "nar",
+ .handler = {&narPath},
+ .completer = completePath
+ });
expectArg("path", &path);
}
diff --git a/src/nix/repl.cc b/src/nix/repl.cc
index 2e7b14d08..c936f9cc2 100644
--- a/src/nix/repl.cc
+++ b/src/nix/repl.cc
@@ -767,7 +767,11 @@ struct CmdRepl : StoreCommand, MixEvalArgs
CmdRepl()
{
- expectPathArgs("files", &files);
+ expectArgs({
+ .label = "files",
+ .handler = {&files},
+ .completer = completePath
+ });
}
std::string description() override
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 3701ffe3d..f9b1298f1 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -149,7 +149,11 @@ struct CmdRun : InstallableCommand, RunCommon
CmdRun()
{
- expectPathArgs("args", &args);
+ expectArgs({
+ .label = "args",
+ .handler = {&args},
+ .completer = completePath
+ });
}
std::string description() override