Fix autocomplete bugs.
Some checks failed
Dropshell Test / Build_and_Test (push) Failing after 20s

This commit is contained in:
Your Name 2025-05-11 19:26:25 +12:00
parent 7e95779d98
commit a2340dcb80
7 changed files with 79 additions and 38 deletions

View File

@ -1,4 +1,7 @@
#include "command_registry.hpp" #include "command_registry.hpp"
#include "utils/utils.hpp"
namespace dropshell {
CommandRegistry& CommandRegistry::instance() { CommandRegistry& CommandRegistry::instance() {
static CommandRegistry reg; static CommandRegistry reg;
@ -41,18 +44,25 @@ std::vector<std::string> CommandRegistry::list_primary_commands(bool include_hid
} }
void CommandRegistry::autocomplete(const std::vector<std::string>& args) const { void CommandRegistry::autocomplete(const CommandContext& ctx) const {
// dropshell autocomplete <command> <arg> <arg> ... // dropshell autocomplete <command> <arg> <arg> ...
if (args.size() < 3) { if (ctx.args.size() < 1) {
for (const auto& name : list_primary_commands(false)) { for (const auto& name : list_primary_commands(false)) {
std::cout << name << std::endl; std::cout << name << std::endl;
} }
return; return;
} }
std::string cmd = args[2];
auto* info = find_command(cmd); // ctx command is autocomplete, so recreate ctx with the first arg removed
CommandContext childcontext = {
ctx.exename,
ctx.args[0],
std::vector<std::string>(ctx.args.begin() + 1, ctx.args.end())
};
auto* info = find_command(childcontext.command);
if (info && info->autocomplete) { if (info && info->autocomplete) {
CommandContext ctx{args[0], cmd, std::vector<std::string>(args.begin() + 2, args.end())}; info->autocomplete(childcontext);
info->autocomplete(ctx);
} }
} }
} // namespace dropshell

View File

@ -1,4 +1,6 @@
#pragma once #ifndef COMMAND_REGISTRY_HPP
#define COMMAND_REGISTRY_HPP
#include <string> #include <string>
#include <vector> #include <vector>
#include <functional> #include <functional>
@ -7,6 +9,8 @@
#include <memory> #include <memory>
#include <iostream> #include <iostream>
namespace dropshell {
struct CommandContext { struct CommandContext {
std::string exename; std::string exename;
std::string command; std::string command;
@ -42,10 +46,14 @@ public:
std::vector<std::string> list_primary_commands(bool include_hidden = false) const; std::vector<std::string> list_primary_commands(bool include_hidden = false) const;
// For autocomplete // For autocomplete
void autocomplete(const std::vector<std::string>& args) const; void autocomplete(const CommandContext& ctx) const;
private: private:
CommandRegistry() = default; CommandRegistry() = default;
std::map<std::string, std::shared_ptr<CommandInfo>> command_map_; std::map<std::string, std::shared_ptr<CommandInfo>> command_map_;
std::vector<std::shared_ptr<CommandInfo>> all_commands_; std::vector<std::shared_ptr<CommandInfo>> all_commands_;
}; };
} // namespace dropshell
#endif // COMMAND_REGISTRY_HPP

View File

@ -2,11 +2,11 @@
#include "config.hpp" #include "config.hpp"
#include "utils/utils.hpp" #include "utils/utils.hpp"
#include "utils/directories.hpp" #include "utils/directories.hpp"
#include "templates.hpp"
#include "shared_commands.hpp" #include "shared_commands.hpp"
#include "server_env_manager.hpp" #include "server_env_manager.hpp"
#include "services.hpp" #include "services.hpp"
#include "servers.hpp" #include "servers.hpp"
#include "transwarp.hpp"
namespace dropshell namespace dropshell
{ {
@ -118,13 +118,18 @@ namespace dropshell
if (ctx.args.size() == 1) { if (ctx.args.size() == 1) {
// get all services on server // get all services on server
std::vector<LocalServiceInfo> services = get_server_services_info(server); std::vector<LocalServiceInfo> services = get_server_services_info(server);
for (const auto& service : services) { transwarp::parallel exec{services.size()};
std::cout << service.service_name << " " << healthtick(server, service.service_name) << std::endl; auto task = transwarp::for_each(exec, services.begin(), services.end(), [&](const LocalServiceInfo& service) {
} std::string status = healthtick(server, service.service_name);
std::cout << status << " " << service.service_name << " (" << service.template_name << ")" << std::endl << std::flush;
});
task->wait();
return 0;
} else { } else {
// get service status // get service status
std::string service = safearg(ctx.args, 1); std::string service = safearg(ctx.args, 1);
std::cout << service << " " << healthtick(server, service) << std::endl; LocalServiceInfo service_info = get_service_info(server, service);
std::cout << healthtick(server, service) << " " << service << " (" << service_info.template_name << ")" << std::endl << std::flush;
} }
return 0; return 0;
} }

View File

@ -10,17 +10,16 @@ namespace dropshell {
void std_autocomplete(const CommandContext &ctx) void std_autocomplete(const CommandContext &ctx)
{ {
ASSERT(ctx.args.size() > 0); if (ctx.args.size() == 0) { // just the command health.
if (ctx.args.size() == 1) {
// list servers // list servers
std::vector<ServerInfo> servers = get_configured_servers(); std::vector<ServerInfo> servers = get_configured_servers();
for (const auto& server : servers) { for (const auto& server : servers) {
std::cout << server.name << std::endl; std::cout << server.name << std::endl;
} }
} }
else if (ctx.args.size() == 2) { else if (ctx.args.size() == 1) {
// list services // list services
std::vector<LocalServiceInfo> services = get_server_services_info(ctx.args[2]); std::vector<LocalServiceInfo> services = get_server_services_info(ctx.args[0]);
for (const auto& service : services) { for (const auto& service : services) {
std::cout << service.service_name << std::endl; std::cout << service.service_name << std::endl;
} }

View File

@ -41,34 +41,34 @@ int main(int argc, char* argv[]) {
if (args.size() < 2) if (args.size() < 2)
args.push_back("help"); args.push_back("help");
ASSERT(args.size() > 1, "No command provided, logic error.");
std::string cmd = args[1]; CommandContext ctx{args[0], args[1], std::vector<std::string>(args.begin() + 2, args.end())};
if (cmd == "autocomplete") { if (ctx.command == "autocomplete") {
CommandRegistry::instance().autocomplete(args); CommandRegistry::instance().autocomplete(ctx);
return 0; return 0;
} }
const CommandInfo* info = CommandRegistry::instance().find_command(cmd); const CommandInfo* info = CommandRegistry::instance().find_command(ctx.command);
if (!info) { if (!info) {
std::cerr << "Unknown command: " << cmd << std::endl; std::cerr << "Unknown command: " << ctx.command << std::endl;
return 1; return 1;
} }
if (info->requires_config && !gConfig().is_config_set()) { if (info->requires_config && !gConfig().is_config_set()) {
std::cerr << "Configuration required for command: " << cmd << std::endl; std::cerr << "Valid dropshell configuration required for command: " << ctx.command << std::endl;
std::cerr << "Please run 'dropshell edit' to set up the dropshell configuration." << std::endl; std::cerr << "Please run 'dropshell edit' to set up the dropshell configuration." << std::endl;
return 1; return 1;
} }
int arg_count = args.size() - 2; int arg_count = ctx.args.size();
if (arg_count < info->min_args || (info->max_args != -1 && arg_count > info->max_args)) { if (arg_count < info->min_args || (info->max_args != -1 && arg_count > info->max_args)) {
std::cerr << "Invalid number of arguments for command: " << cmd << std::endl; std::cerr << "Invalid number of arguments for command: " << ctx.command << std::endl;
std::cerr << "Usage: " << std::endl; std::cerr << "Usage: " << std::endl;
std::cout << " "; std::cout << " ";
print_left_aligned(info->help_usage,30); print_left_aligned(info->help_usage,30);
std::cout << info->help_description << std::endl; std::cout << info->help_description << std::endl;
return 1; return 1;
} }
CommandContext ctx{args[0], cmd, std::vector<std::string>(args.begin() + 2, args.end())};
return info->handler(ctx); return info->handler(ctx);
} }

View File

@ -336,22 +336,37 @@ std::string safearg(int argc, char *argv[], int index)
void print_left_aligned(const std::string & str, int width) { void print_left_aligned(const std::string & str, int width) {
std::cout << str; std::cout << left_align(str, width);
if (static_cast<int>(str.size()) < width)
std::cout << std::string(width - str.size(), ' ');
} }
void print_centered(const std::string & str, int width) { void print_centered(const std::string & str, int width) {
int pad = width - static_cast<int>(str.size()); std::cout << center_align(str, width);
int pad_left = pad > 0 ? pad / 2 : 0;
int pad_right = pad > 0 ? pad - pad_left : 0;
std::cout << std::string(pad_left, ' ') << str << std::string(pad_right, ' ');
} }
void print_right_aligned(const std::string & str, int width) { void print_right_aligned(const std::string & str, int width) {
if (static_cast<int>(str.size()) < width) std::cout << right_align(str, width);
std::cout << std::string(width - str.size(), ' '); }
std::cout << str;
std::string left_align(const std::string & str, int width) {
if (static_cast<int>(str.size()) >= width)
return str;
return str + std::string(width - str.size(), ' ');
}
std::string right_align(const std::string & str, int width) {
if (static_cast<int>(str.size()) >= width)
return str;
return std::string(width - str.size(), ' ') + str;
}
std::string center_align(const std::string & str, int width) {
int pad = width - static_cast<int>(str.size());
if (pad <= 0)
return str;
int pad_left = pad / 2;
int pad_right = pad - pad_left;
return std::string(pad_left, ' ') + str + std::string(pad_right, ' ');
} }

View File

@ -49,4 +49,8 @@ void print_left_aligned(const std::string & str, int width);
void print_centered(const std::string & str, int width); void print_centered(const std::string & str, int width);
void print_right_aligned(const std::string & str, int width); void print_right_aligned(const std::string & str, int width);
std::string left_align(const std::string & str, int width);
std::string right_align(const std::string & str, int width);
std::string center_align(const std::string & str, int width);
} // namespace dropshell } // namespace dropshell