aboutsummaryrefslogtreecommitdiffstats
path: root/nihil.cli/command_tree.ccm
blob: 7297af72b0741f8d3eadb7037726eb05716a316a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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_view;

	/*
	 * 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