12 using std::vector, std::string, std::map;
13 namespace fs = std::filesystem;
18 fs::create_directories(path.parent_path());
19 std::ofstream out(path);
20 if (!out)
return false;
29 const char* shell = std::getenv(
"SHELL");
30 if (!shell)
return "";
33 if (s.find(
"bash") != std::string::npos)
return "bash";
34 if (s.find(
"zsh") != std::string::npos)
return "zsh";
40 const char* home = std::getenv(
"HOME");
42 std::cerr <<
"Cannot determine HOME directory\n";
48 std::cerr <<
"Could not detect your shell. Supported: bash, zsh\n";
52 fs::path home_path(home);
54 if (shell ==
"bash") {
55 fs::path path = home_path /
".local/share/bash-completion/completions/mach3";
57 std::cout <<
"Installed bash completions → " << path <<
"\n";
62 fs::path path = home_path /
".local/share/zsh/site-functions/_mach3";
64 std::cout <<
"Installed zsh completions → " << path <<
"\n";
72 if (cmd.rfind(prefix, 0) == 0)
73 std::cout << cmd <<
"\n";
106 this->add_subparser(*parser);
117 const char* env = std::getenv(
"MACH3_PLUGINS");
123 std::stringstream ss(env);
126 while (std::getline(ss, path,
':')) {
129 std::unique_ptr<DynamicPlugin> dlplugin = std::make_unique<DynamicPlugin>(sofile);
132 std::cerr <<
"Plugin " << sofile <<
" did not provide a valid parser.\n";
136 this->add_subparser(*parser);
140 catch (
const std::exception& e) {
141 std::cerr <<
"Failed to load plugin from " << sofile <<
": " << e.what() <<
"\n";
145 std::cerr <<
"Failed to load plugin from " << sofile <<
": unknown error\n";
171 return plugin_itr->second->Run();
175 return dplugin_itr->second->Run();
190 std::vector<std::string> result;
194 if (!fs::exists(p)) {
195 std::cerr <<
"Plugin path does not exist: " << path <<
"\n";
199 if (fs::is_regular_file(p)) {
201 result.push_back(path);
203 else if (fs::is_directory(p)) {
205 for (
auto& entry : fs::directory_iterator(p)) {
206 if (entry.is_regular_file() && entry.path().extension() ==
".so") {
207 result.push_back(entry.path().string());
212 std::cerr <<
"Invalid plugin path (not file or directory): " << path <<
"\n";
MaCh3 Logging utilities built on top of SPDLOG.
Core program class for the MaCh3 command-line interface.
Interface for MaCh3 plugins and modules.
virtual MaCh3ArgumentParser * get_parser()=0
Get the argument parser for this plugin.
Extended ArgumentParser with MaCh3-specific functionality.
const std::string name() const
Get the name of this parser/subcommand.
const MaCh3ArgumentParser & get_subcommand_used() const
Get the subcommand that was used in parsing.
void add_core_module(IModule &module)
Add a core module to the program.
void unload_dynamic_plugins()
Unload all dynamically loaded plugins.
bool write_file(const fs::path &path, std::string_view content) const
Write content to a file, creating parent directories if needed.
static constexpr std::string_view ZSH_COMPLETION
std::vector< std::string > m_subcommands
List of registered subcommand names.
void install_completions() const
Install shell completion scripts for bash and zsh.
static constexpr std::string_view BASH_COMPLETION
int Run()
Run the selected subcommand.
std::map< const MaCh3ArgumentParser *, IModule * > m_module_map
Map of parsers to core modules (non-owning)
void completions(const std::string &prefix) const
Generate completion suggestions for the given prefix.
std::map< const MaCh3ArgumentParser *, std::unique_ptr< DynamicPlugin > > m_dynamic_plugin_map
Map of parsers to dynamic plugins (owning)
std::string detect_shell() const
Detect the user's shell from the SHELL environment variable.
void load_dynamic_plugins()
Load dynamic plugins from the MACH3_PLUGINS environment variable.
std::vector< std::string > expand_plugin_path(const std::string &path) const
Expand a plugin path (file or directory) into a list of .so files.
Main namespace for MaCh3 software.