Introduce internal parameters; better condition for enabling repl

This commit is contained in:
Robert Bendun 2023-03-04 19:00:15 +01:00
parent a7ed7a0d65
commit c0f021e57f
2 changed files with 46 additions and 24 deletions

View File

@ -10,6 +10,7 @@
#include <set> #include <set>
#include <unordered_set> #include <unordered_set>
#include <variant> #include <variant>
#include <utility>
#ifdef _WIN32 #ifdef _WIN32
extern "C" { extern "C" {
@ -60,7 +61,12 @@ static constexpr std::array all_parameters = [] {
Empty_Argument print_version = [] { std::cout << Musique_Version << std::endl; }; Empty_Argument print_version = [] { std::cout << Musique_Version << std::endl; };
Empty_Argument print_help = usage; Empty_Argument print_help = usage;
using Entry = std::pair<std::string_view, Parameter>; struct Entry
{
std::string_view name;
Parameter handler;
bool internal = false;
};
// First entry for given action type should always be it's cannonical name // First entry for given action type should always be it's cannonical name
return std::array { return std::array {
@ -94,7 +100,11 @@ static constexpr std::array all_parameters = [] {
Entry { "version", print_version }, Entry { "version", print_version },
Entry { "v", print_version }, Entry { "v", print_version },
Entry { "ast", set_ast_only_mode }, Entry {
.name = "ast",
.handler = set_ast_only_mode,
.internal = true,
},
}; };
}(); }();
@ -151,8 +161,8 @@ std::optional<std::string_view> cmd::accept_commandline_argument(std::vector<cmd
state.m_value = args[1]; state.m_value = args[1];
} }
for (auto const& [name, handler] : all_parameters) { for (auto const& p : all_parameters) {
if (name != state.name()) { if (p.name != state.name()) {
continue; continue;
} }
std::visit(Overloaded { std::visit(Overloaded {
@ -160,23 +170,23 @@ std::optional<std::string_view> cmd::accept_commandline_argument(std::vector<cmd
state.mark_success(); state.mark_success();
h(); h();
}, },
[&state, name=name](Requires_Argument const& h) { [&state, p](Requires_Argument const& h) {
auto arg = state.value(); auto arg = state.value();
if (!arg) { if (!arg) {
std::cerr << "musique: error: option " << std::quoted(name) << " requires an argument" << std::endl; std::cerr << "musique: error: option " << std::quoted(p.name) << " requires an argument" << std::endl;
std::exit(1); std::exit(1);
} }
h(*arg); h(*arg);
}, },
[&state, &runnables, name=name](Defines_Code const& h) { [&state, &runnables, p](Defines_Code const& h) {
auto arg = state.value(); auto arg = state.value();
if (!arg) { if (!arg) {
std::cerr << "musique: error: option " << std::quoted(name) << " requires an argument" << std::endl; std::cerr << "musique: error: option " << std::quoted(p.name) << " requires an argument" << std::endl;
std::exit(1); std::exit(1);
} }
runnables.push_back(h(*arg)); runnables.push_back(h(*arg));
} }
}, handler); }, p.handler);
return std::nullopt; return std::nullopt;
} }
@ -194,24 +204,39 @@ void cmd::print_close_matches(std::string_view arg)
all_parameters.begin(), all_parameters.end(), all_parameters.begin(), all_parameters.end(),
closest.begin(), closest.end(), closest.begin(), closest.end(),
[&minimum_distance, arg](auto const& lhs, auto const& rhs) { [&minimum_distance, arg](auto const& lhs, auto const& rhs) {
auto const lhs_score = edit_distance(arg, lhs.first); auto const lhs_score = edit_distance(arg, lhs.name);
auto const rhs_score = edit_distance(arg, rhs.first); auto const rhs_score = edit_distance(arg, rhs.name);
minimum_distance = std::min({ minimum_distance, lhs_score, rhs_score }); minimum_distance = std::min({ minimum_distance, lhs_score, rhs_score });
return lhs_score < rhs_score; return lhs_score < rhs_score;
} }
); );
std::cout << "The most similar commands are:\n"; std::vector<std::string> shown;
std::unordered_set<void*> shown;
if (minimum_distance <= 3) { if (minimum_distance <= 3) {
for (auto const& [ name, handler ] : closest) { for (auto const& p : closest) {
auto const handler_p = std::visit([](auto *v) { return reinterpret_cast<void*>(v); }, handler); if (std::find(shown.begin(), shown.end(), std::string(p.name)) == shown.end()) {
if (!shown.contains(handler_p)) { shown.push_back(std::string(p.name));
std::cout << " " << name << std::endl;
shown.insert(handler_p);
} }
} }
} }
if (shown.empty()) {
void *previous = nullptr;
std::cout << "Available subcommands are:\n";
for (auto const& p : all_parameters) {
auto handler_p = std::visit([](auto const& h) { return reinterpret_cast<void*>(h); }, p.handler);
if (std::exchange(previous, handler_p) == handler_p || p.internal) {
continue;
}
std::cout << " " << p.name << '\n';
}
} else {
std::cout << "The most similar commands are:\n";
for (auto const& name : shown) {
std::cout << " " << name << '\n';
}
}
} }
bool cmd::is_tty() bool cmd::is_tty()

View File

@ -368,14 +368,11 @@ static std::optional<Error> Main(std::span<char const*> args)
} }
} }
enable_repl = enable_repl || std::all_of(runnables.begin(), runnables.end(), enable_repl = enable_repl || (!runnables.empty() && std::all_of(runnables.begin(), runnables.end(),
[](cmd::Run const& run) { [](cmd::Run const& run) { return run.type == cmd::Run::Deffered_File; }));
return run.type == cmd::Run::Deffered_File;
});
if (runnables.empty() || enable_repl) { if (enable_repl) {
repl_line_number = 1; repl_line_number = 1;
enable_repl = true;
#ifndef _WIN32 #ifndef _WIN32
bestlineSetCompletionCallback(completion); bestlineSetCompletionCallback(completion);
#else #else