aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.cli/command_tree.ccm
diff options
context:
space:
mode:
authorLexi Winter <lexi@le-fay.org>2025-06-29 00:42:31 +0100
committerLexi Winter <lexi@le-fay.org>2025-06-29 00:42:31 +0100
commitd24315268c11d435bb9accbce87b7f46dda6ed3e (patch)
tree66589cb6a15fa74d4b09683105c583e4a5c222b4 /nihil.cli/command_tree.ccm
parent7741a9698d29f79aca3e47495dcdf87c7a712f42 (diff)
downloadnihil-d24315268c11d435bb9accbce87b7f46dda6ed3e.tar.gz
nihil-d24315268c11d435bb9accbce87b7f46dda6ed3e.tar.bz2
cli: improve command dispatch a bit
Diffstat (limited to 'nihil.cli/command_tree.ccm')
-rw-r--r--nihil.cli/command_tree.ccm107
1 files changed, 107 insertions, 0 deletions
diff --git a/nihil.cli/command_tree.ccm b/nihil.cli/command_tree.ccm
new file mode 100644
index 0000000..f52b768
--- /dev/null
+++ b/nihil.cli/command_tree.ccm
@@ -0,0 +1,107 @@
+/*
+ * This source code is released into the public domain.
+ */
+
+module;
+
+#include <map>
+#include <memory>
+#include <optional>
+#include <ranges>
+#include <vector>
+
+export module nihil.cli:command_tree;
+
+import :command;
+
+namespace nihil {
+
+/*
+ * command_tree_node represents a possibly-empty node in the command tree.
+ * For example, if two commands "add foo" and "add bar" are defined,
+ * then "add" will be implicitly created as an empty node.
+ */
+struct command_tree_node final {
+ command_tree_node();
+
+ command_tree_node(command_tree_node *parent,
+ std::string_view this_word);
+
+ command_tree_node(command_tree_node *parent,
+ std::string_view this_word,
+ std::shared_ptr<command_node> command);
+
+ /*
+ * Return a child node, or NULL if the child doesn't exist.
+ */
+ [[nodiscard]] auto get_child(this command_tree_node const &self,
+ std::string_view child)
+ -> command_tree_node const *;
+
+ [[nodiscard]] auto get_child(this command_tree_node &self,
+ std::string_view child)
+ -> command_tree_node *;
+
+ /*
+ * Return a child node if it exists, or insert a new empty node.
+ */
+ [[nodiscard]] auto get_or_create_child(this command_tree_node &self,
+ std::string_view child)
+ -> command_tree_node *;
+
+ /*
+ * Set or get this node's command.
+ */
+ [[nodiscard]] auto command(this command_tree_node const &self)
+ -> std::shared_ptr<command_node> const &;
+ auto command(this command_tree_node &self,
+ std::shared_ptr<command_node>)
+ -> void;
+
+ /*
+ * Get the path of this command_node.
+ */
+ [[nodiscard]] auto path(this command_tree_node const &self)
+ -> std::string;
+
+ /*
+ * Print this node's children in a form useful to humans.
+ */
+ auto print_commands(this command_tree_node const &self) -> void;
+
+private:
+ command_tree_node *m_parent = nullptr;
+ std::string m_this_word;
+ std::shared_ptr<command_node> m_command;
+ std::map<std::string, command_tree_node>
+ m_children;
+};
+
+/*
+ * The command tree stores commands in a tree structure suitable for searching.
+ */
+struct command_tree {
+ /*
+ * Add a node to the tree. Returns false if the node already exists.
+ */
+ auto insert(this command_tree &self,
+ std::vector<std::string_view> const &path,
+ std::shared_ptr<command_node> command)
+ -> void;
+
+ /*
+ * Find a node in the tree.
+ */
+ auto find(this command_tree const &self, int &argc, char **&argv)
+ -> command_tree_node const *;
+
+private:
+ command_tree_node m_root_node;
+};
+
+/*
+ * Build a command tree from the registry.
+ */
+[[nodiscard]] auto build_command_tree() -> command_tree;
+
+} // namespace nihil