aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/args.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil/args.hh')
-rw-r--r--src/libutil/args.hh119
1 files changed, 82 insertions, 37 deletions
diff --git a/src/libutil/args.hh b/src/libutil/args.hh
index b55f1d238..77f7ff2a8 100644
--- a/src/libutil/args.hh
+++ b/src/libutil/args.hh
@@ -15,17 +15,15 @@ enum HashType : char;
class MultiCommand;
+class RootArgs;
+
+class AddCompletions;
+
class Args
{
public:
/**
- * Parse the command line, throwing a UsageError if something goes
- * wrong.
- */
- void parseCmdline(const Strings & cmdline);
-
- /**
* Return a short one-line description of the command.
*/
virtual std::string description() { return ""; }
@@ -124,6 +122,25 @@ protected:
};
/**
+ * The basic function type of the completion callback.
+ *
+ * Used to define `CompleterClosure` and some common case completers
+ * that individual flags/arguments can use.
+ *
+ * The `AddCompletions` that is passed is an interface to the state
+ * stored as part of the root command
+ */
+ typedef void CompleterFun(AddCompletions &, size_t, std::string_view);
+
+ /**
+ * The closure type of the completion callback.
+ *
+ * This is what is actually stored as part of each Flag / Expected
+ * Arg.
+ */
+ typedef std::function<CompleterFun> CompleterClosure;
+
+ /**
* Description of flags / options
*
* These are arguments like `-s` or `--long` that can (mostly)
@@ -140,7 +157,7 @@ protected:
std::string category;
Strings labels;
Handler handler;
- std::function<void(size_t, std::string_view)> completer;
+ CompleterClosure completer;
std::optional<ExperimentalFeature> experimentalFeature;
@@ -177,19 +194,31 @@ protected:
std::string label;
bool optional = false;
Handler handler;
- std::function<void(size_t, std::string_view)> completer;
+ CompleterClosure completer;
};
/**
* Queue of expected positional argument forms.
*
- * Positional arugment descriptions are inserted on the back.
+ * Positional argument descriptions are inserted on the back.
*
* As positional arguments are passed, these are popped from the
* front, until there are hopefully none left as all args that were
* expected in fact were passed.
*/
std::list<ExpectedArg> expectedArgs;
+ /**
+ * List of processed positional argument forms.
+ *
+ * All items removed from `expectedArgs` are added here. After all
+ * arguments were processed, this list should be exactly the same as
+ * `expectedArgs` was before.
+ *
+ * This list is used to extend the lifetime of the argument forms.
+ * If this is not done, some closures that reference the command
+ * itself will segfault.
+ */
+ std::list<ExpectedArg> processedArgs;
/**
* Process some positional arugments
@@ -211,13 +240,6 @@ protected:
*/
virtual void initialFlagsProcessed() {}
- /**
- * Called after the command line has been processed if we need to generate
- * completions. Useful for commands that need to know the whole command line
- * in order to know what completions to generate.
- */
- virtual void completionHook() { }
-
public:
void addFlag(Flag && flag);
@@ -252,24 +274,30 @@ public:
});
}
+ static CompleterFun completePath;
+
+ static CompleterFun completeDir;
+
virtual nlohmann::json toJSON();
friend class MultiCommand;
/**
* The parent command, used if this is a subcommand.
+ *
+ * Invariant: An Args with a null parent must also be a RootArgs
+ *
+ * \todo this would probably be better in the CommandClass.
+ * getRoot() could be an abstract method that peels off at most one
+ * layer before recuring.
*/
MultiCommand * parent = nullptr;
-private:
-
/**
- * Experimental features needed when parsing args. These are checked
- * after flag parsing is completed in order to support enabling
- * experimental features coming after the flag that needs the
- * experimental feature.
+ * Traverse parent pointers until we find the \ref RootArgs "root
+ * arguments" object.
*/
- std::set<ExperimentalFeature> flagExperimentalFeatures;
+ RootArgs & getRoot();
};
/**
@@ -320,8 +348,6 @@ public:
bool processArgs(const Strings & args, bool finish) override;
- void completionHook() override;
-
nlohmann::json toJSON() override;
};
@@ -333,21 +359,40 @@ struct Completion {
bool operator<(const Completion & other) const;
};
-class Completions : public std::set<Completion> {
+
+/**
+ * The abstract interface for completions callbacks
+ *
+ * The idea is to restrict the callback so it can only add additional
+ * completions to the collection, or set the completion type. By making
+ * it go through this interface, the callback cannot make any other
+ * changes, or even view the completions / completion type that have
+ * been set so far.
+ */
+class AddCompletions
+{
public:
- void add(std::string completion, std::string description = "");
-};
-extern std::shared_ptr<Completions> completions;
-enum CompletionType {
- ctNormal,
- ctFilenames,
- ctAttrs
-};
-extern CompletionType completionType;
+ /**
+ * The type of completion we are collecting.
+ */
+ enum class Type {
+ Normal,
+ Filenames,
+ Attrs,
+ };
-void completePath(size_t, std::string_view prefix);
+ /**
+ * Set the type of the completions being collected
+ *
+ * \todo it should not be possible to change the type after it has been set.
+ */
+ virtual void setType(Type type) = 0;
-void completeDir(size_t, std::string_view prefix);
+ /**
+ * Add a single completion to the collection
+ */
+ virtual void add(std::string completion, std::string description = "") = 0;
+};
}