Consolix
Loading...
Searching...
No Matches
CliComponent.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef _CONSOLIX_CLI_COMPONENT_HPP_INCLUDED
3#define _CONSOLIX_CLI_COMPONENT_HPP_INCLUDED
4
8
9#if CONSOLIX_USE_CXXOPTS == 1
10
11#include <cxxopts.hpp>
12#include <string>
13#include <memory>
14
15namespace consolix {
16
22 class CliComponent : public IAppComponent {
23 public:
24
29 CliComponent(
30 const std::string& name,
31 const std::string& description,
32 std::function<void(CliOptions&)> creator)
33 : m_creator(std::move(creator)) {
34 register_options_service(name, description);
35 }
36
43 CliComponent(
44 const std::string& name,
45 const std::string& description,
46 std::function<void(CliOptions&)> creator,
47 int argc,
48 const char* argv[])
49 : m_creator(std::move(creator)) {
50 register_options_service(name, description);
51 store_argv(argc, argv);
52 }
53
60 CliComponent(
61 const std::string& name,
62 const std::string& description,
63 std::function<void(CliOptions&)> creator,
64 int argc,
65 char* argv[])
66 : m_creator(std::move(creator)) {
67 register_options_service(name, description);
68 store_argv(argc, argv);
69 }
70
75 template <typename T>
76 void add_option(const std::string& key, const std::string& description) {
77 get_service<CliOptions>().add_options()(key, description, cxxopts::value<T>());
78 }
79
85 template <typename T>
86 void add_option(const std::string& key, const std::string& description, T default_value) {
87 get_service<CliOptions>().add_options()(key, description, cxxopts::value<T>()->default_value(std::to_string(default_value)));
88 }
89
95 template <typename T>
96 void add_option_implicit(const std::string& key, const std::string& description, T implicit_value) {
97 get_service<CliOptions>().add_options()(key, description, cxxopts::value<T>()->implicit_value(std::to_string(implicit_value)));
98 }
99
103 void parse(int argc, const char* argv[]) {
104 try {
105 auto result = get_service<CliOptions>().parse(argc, argv);
106 register_service<CliArguments>([&result](){
107 return std::make_shared<CliArguments>(result);
108 });
109 } catch (const std::exception& e) {
110 CONSOLIX_STREAM() << "Error parsing command-line arguments: " << e.what() << std::endl;
111# if CONSOLIX_USE_LOGIT == 1
112 LOGIT_PRINT_ERROR("Error parsing command-line arguments: ", e.what());
113# endif
114 throw;
115 }
116 }
117
123 template <typename T>
124 T get(const std::string& key) const {
125 if (!get_service<CliArguments>().count(key)) {
126# if CONSOLIX_USE_LOGIT == 1
127 LOGIT_PRINT_ERROR("Option not found: ", key);
128# endif
129 throw std::runtime_error("Option not found: " + key);
130 }
131 return get_service<CliArguments>()[key].as<T>();
132 }
133
134 protected:
135
138 bool initialize() override {
139 try {
140 auto &options = get_service<CliOptions>();
141 if (!m_creator) {
142 throw std::runtime_error("CLI options creator function is null. Ensure you provide a valid function to initialize CLI options.");
143 }
144 m_creator(options);
145# if defined(_WIN32) || defined(_WIN64)
146 parse_windows();
147# else
148 if (m_argc) {
149 parse(m_argc, m_argv_c.data());
150 }
151# endif
152 } catch (const std::exception& e) {
153# if CONSOLIX_USE_LOGIT == 1
154 LOGIT_PRINT_ERROR("CLI component initialization failed: ", e.what());
155 throw;
156# else
157 CONSOLIX_STREAM() << "Error initializing CLI component: " << e.what() << std::endl;
158 throw;
159# endif
160 }
161 m_is_init = true;
162 return true;
163 }
164
167 bool is_initialized() const override {
168 return m_is_init;
169 }
170
172 void process() override {}
173
174 private:
175 int m_argc = 0;
176 std::vector<const char*> m_argv_c;
177 std::function<void(CliOptions&)> m_creator;
178 std::atomic<bool> m_is_init{false};
179
181 void register_options_service(const std::string& name, const std::string& description) {
182 register_service<CliOptions>([&name, &description]() {
183 return std::make_shared<CliOptions>(name, description);
184 });
185 }
186
188 template <typename ArgvEntry>
189 void store_argv(int argc, ArgvEntry argv[]) {
190 m_argc = argc;
191 for (int i = 0; i < argc; ++i) {
192 m_argv_c.push_back(argv[i]);
193 }
194 }
195
196# if defined(_WIN32) || defined(_WIN64)
198 void parse_windows() {
199 int argc = 0;
200 LPWSTR* argv_w = CommandLineToArgvW(GetCommandLineW(), &argc);
201
202 std::vector<std::string> args;
203 for (int i = 0; i < argc; ++i) {
204 args.push_back(utf16_to_utf8(argv_w[i]));
205 }
206
207 // Convert to standard `char*` for cxxopts
208 std::vector<const char*> argv_c;
209 for (const auto& arg : args) {
210 argv_c.push_back(arg.c_str());
211 }
212
213 parse(argc, argv_c.data());
214 }
215# endif
216
217 }; // CliComponent
218
219}; // namespace consolix
220
221#endif // #if CONSOLIX_USE_CXXOPTS == 1
222
223#endif // _CONSOLIX_CLI_COMPONENT_HPP_INCLUDED
#define CONSOLIX_STREAM()
Fallback for general logging.
< Utility modules and helpers.