diff options
Diffstat (limited to 'src/libutil/args.hh')
-rw-r--r-- | src/libutil/args.hh | 143 |
1 files changed, 88 insertions, 55 deletions
diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 433d26bba..f41242e17 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -4,12 +4,12 @@ #include <map> #include <memory> +#include <nlohmann/json_fwd.hpp> + #include "util.hh" namespace nix { -MakeError(UsageError, Error); - enum HashType : char; class Args @@ -22,67 +22,74 @@ public: virtual void printHelp(const string & programName, std::ostream & out); + /* Return a short one-line description of the command. */ virtual std::string description() { return ""; } 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; std::string category; Strings labels; Handler handler; + std::function<void(size_t, std::string_view)> completer; static Flag mkHashTypeFlag(std::string && longName, HashType * ht); static Flag mkHashTypeOptFlag(std::string && longName, std::optional<HashType> * oht); @@ -99,9 +106,9 @@ protected: struct ExpectedArg { std::string label; - size_t arity; // 0 = any - bool optional; - std::function<void(std::vector<std::string>)> handler; + bool optional = false; + Handler handler; + std::function<void(size_t, std::string_view)> completer; }; std::list<ExpectedArg> expectedArgs; @@ -175,22 +182,32 @@ 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 = optional, + .handler = {dest} + }); } /* 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} + }); } + virtual nlohmann::json toJSON(); + friend class MultiCommand; }; @@ -205,6 +222,9 @@ struct Command : virtual Args virtual void prepare() { }; virtual void run() = 0; + /* Return documentation about this command, in Markdown format. */ + virtual std::string doc() { return ""; } + struct Example { std::string description; @@ -222,6 +242,8 @@ struct Command : virtual Args virtual Category category() { return catDefault; } void printHelp(const string & programName, std::ostream & out) override; + + nlohmann::json toJSON() override; }; typedef std::map<std::string, std::function<ref<Command>()>> Commands; @@ -247,6 +269,8 @@ public: bool processFlag(Strings::iterator & pos, Strings::iterator end) override; bool processArgs(const Strings & args, bool finish) override; + + nlohmann::json toJSON() override; }; Strings argvToStrings(int argc, char * * argv); @@ -259,4 +283,13 @@ typedef std::vector<std::pair<std::string, std::string>> Table2; void printTable(std::ostream & out, const Table2 & table); +extern std::shared_ptr<std::set<std::string>> completions; +extern bool pathCompletions; + +std::optional<std::string> needsCompletion(std::string_view s); + +void completePath(size_t, std::string_view prefix); + +void completeDir(size_t, std::string_view prefix); + } |