#include "command_registry.hpp" #include "config.hpp" #include "utils/utils.hpp" #include "service_runner.hpp" #include "utils/directories.hpp" #include "standard_autocomplete.hpp" #include #include #include #include #include #include namespace dropshell { void edit_autocomplete(const CommandContext& ctx); int edit_handler(const CommandContext& ctx); static std::vector edit_name_list={"edit"}; // Static registration struct EditCommandRegister { EditCommandRegister() { CommandRegistry::instance().register_command({ edit_name_list, edit_handler, edit_autocomplete, false, // hidden false, // requires_config 0, // min_args (after command) 2, // max_args (after command) "edit [SERVER] [SERVICE]", "Edit dropshell, server or service configuration", // heredoc R"( Edit dropshell, server or service configuration. edit edit the dropshell config. edit edit the server config. edit edit the service config. )" }); } } edit_command_register; // ------------------------------------------------------------------------------------------------ // edit command implementation // ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------ // utility function to edit a file // ------------------------------------------------------------------------------------------------ bool edit_file(const std::string &file_path) { // make sure parent directory exists. std::string parent_dir = get_parent(file_path); std::filesystem::create_directories(parent_dir); std::string editor_cmd; const char* editor_env = std::getenv("EDITOR"); if (editor_env && std::strlen(editor_env) > 0) { editor_cmd = std::string(editor_env) + " " + quote(file_path); } else if (isatty(STDIN_FILENO)) { // Check if stdin is connected to a terminal if EDITOR is not set editor_cmd = "nano -w " + quote(file_path); } else { std::cerr << "Error: Standard input is not a terminal and EDITOR environment variable is not set." << std::endl; std::cerr << "Try setting the EDITOR environment variable (e.g., export EDITOR=nano) or run in an interactive terminal." << std::endl; std::cerr << "You can manually edit the file at: " << file_path << std::endl; return false; } std::cout << "Editing file: " << file_path << std::endl; return execute_local_command(editor_cmd, nullptr, cMode::Interactive | cMode::RawCommand); } // ------------------------------------------------------------------------------------------------ // edit config // ------------------------------------------------------------------------------------------------ int edit_config() { if (!gConfig().is_config_set()) gConfig().save_config(false); // save defaults. std::string config_file = localfile::dropshell_json(); if (!edit_file(config_file) || !std::filesystem::exists(config_file)) return die("Error: Failed to edit config file."); gConfig().load_config(); if (!gConfig().is_config_set()) return die("Error: Failed to load and parse edited config file!"); gConfig().save_config(true); std::cout << "Successfully edited config file at " << config_file << std::endl; return 0; } // ------------------------------------------------------------------------------------------------ // edit server // ------------------------------------------------------------------------------------------------ int edit_server(const std::string &server_name) { std::string serverpath = localpath::server(server_name); if (serverpath.empty()) { std::cerr << "Error: Server not found: " << server_name << std::endl; return -1; } std::ostringstream aftertext; aftertext << "If you have changed DROPSHELL_DIR, you should manually move the files to the new location NOW.\n" << "You can ssh in to the remote server with: dropshell ssh "<