#include "console_input_model.h" #include #include #include namespace dragonx { namespace ui { const std::vector& ConsoleRpcCommandNames() { static const std::vector commands = { "help", "getinfo", "stop", "getnetworkinfo", "getpeerinfo", "getconnectioncount", "addnode", "setban", "listbanned", "clearbanned", "ping", "getblockchaininfo", "getblockcount", "getbestblockhash", "getblock", "getblockhash", "getblockheader", "getdifficulty", "getrawmempool", "gettxout", "coinsupply", "getchaintips", "getmininginfo", "setgenerate", "getgenerate", "getnetworkhashps", "getblocksubsidy", "getbalance", "z_gettotalbalance", "z_getbalances", "getnewaddress", "z_getnewaddress", "listaddresses", "z_listaddresses", "sendtoaddress", "z_sendmany", "listtransactions", "listunspent", "z_listunspent", "z_getoperationstatus", "z_getoperationresult", "getwalletinfo", "backupwallet", "dumpprivkey", "importprivkey", "z_exportkey", "z_importkey", "signmessage", "settxfee", "createrawtransaction", "decoderawtransaction", "getrawtransaction", "sendrawtransaction", "signrawtransaction", "validateaddress", "z_validateaddress", "estimatefee", "clear" }; return commands; } void AppendConsoleHistory(std::vector& history, const std::string& command, std::size_t maxEntries) { if (command.empty()) return; if (history.empty() || history.back() != command) { history.push_back(command); while (history.size() > maxEntries) { history.erase(history.begin()); } } } int NavigateConsoleHistoryIndex(int currentIndex, std::size_t historySize, bool up) { if (historySize == 0) return -1; if (up) { if (currentIndex < 0) return static_cast(historySize) - 1; if (currentIndex > 0) return currentIndex - 1; return currentIndex; } if (currentIndex >= 0) { int next = currentIndex + 1; if (next >= static_cast(historySize)) return -1; return next; } return currentIndex; } std::string ConsoleHistoryEntry(const std::vector& history, int historyIndex) { if (historyIndex < 0 || historyIndex >= static_cast(history.size())) return {}; return history[static_cast(historyIndex)]; } ConsoleCompletionResult CompleteConsoleCommand(const std::string& input) { ConsoleCompletionResult result; if (input.empty()) return result; for (const auto& command : ConsoleRpcCommandNames()) { if (command.compare(0, input.size(), input) == 0) { result.matches.push_back(command); } } if (result.matches.empty()) return result; result.commonPrefix = result.matches.front(); for (std::size_t matchIndex = 1; matchIndex < result.matches.size(); ++matchIndex) { const auto& match = result.matches[matchIndex]; std::size_t prefixLength = 0; while (prefixLength < result.commonPrefix.size() && prefixLength < match.size() && result.commonPrefix[prefixLength] == match[prefixLength]) { ++prefixLength; } result.commonPrefix.resize(prefixLength); } return result; } std::vector FormatConsoleCompletionLines(const std::vector& matches, std::size_t maxLineLength) { std::vector lines; std::string line = " "; for (std::size_t matchIndex = 0; matchIndex < matches.size(); ++matchIndex) { if (matchIndex > 0) line += " "; line += matches[matchIndex]; if (line.length() > maxLineLength) { lines.push_back(line); line = " "; } } if (line.length() > 2) { lines.push_back(line); } return lines; } std::vector ParseConsoleCommandArgs(const std::string& command) { std::vector args; std::size_t index = 0; while (index < command.size()) { while (index < command.size() && (command[index] == ' ' || command[index] == '\t')) { ++index; } if (index >= command.size()) break; std::string token; if (command[index] == '"' || command[index] == '\'') { char quote = command[index++]; while (index < command.size() && command[index] != quote) { token += command[index++]; } if (index < command.size()) ++index; } else if (command[index] == '[' || command[index] == '{') { char open = command[index]; char close = (open == '[') ? ']' : '}'; int depth = 0; while (index < command.size()) { if (command[index] == open) ++depth; else if (command[index] == close) --depth; token += command[index++]; if (depth == 0) break; } } else { while (index < command.size() && command[index] != ' ' && command[index] != '\t') { token += command[index++]; } } if (!token.empty()) args.push_back(token); } return args; } ConsoleRpcCall BuildConsoleRpcCall(const std::string& command) { auto args = ParseConsoleCommandArgs(command); ConsoleRpcCall call; if (args.empty()) return call; call.valid = true; call.method = args.front(); for (std::size_t argIndex = 1; argIndex < args.size(); ++argIndex) { const std::string& arg = args[argIndex]; if (!arg.empty() && (arg[0] == '{' || arg[0] == '[')) { auto parsed = nlohmann::json::parse(arg, nullptr, false); if (!parsed.is_discarded()) { call.params.push_back(parsed); continue; } } if (arg == "true") { call.params.push_back(true); } else if (arg == "false") { call.params.push_back(false); } else { try { if (arg.find('.') != std::string::npos) { call.params.push_back(std::stod(arg)); } else { call.params.push_back(std::stoll(arg)); } } catch (...) { call.params.push_back(arg); } } } return call; } std::vector FormatConsoleRpcResultLines(const std::string& result, bool isError) { if (isError) { return {{"Error: " + result, ConsoleResultLineRole::Error}}; } std::vector lines; std::string normalized = (result == "null") ? "(no result)" : result; bool isJson = !normalized.empty() && (normalized[0] == '{' || normalized[0] == '['); std::istringstream stream(normalized); std::string line; while (std::getline(stream, line)) { ConsoleResultLineRole role = ConsoleResultLineRole::Result; if (isJson && !line.empty()) { std::string trimmed = line; std::size_t first = trimmed.find_first_not_of(" \t"); if (first != std::string::npos) trimmed = trimmed.substr(first); if (!trimmed.empty()) { unsigned char firstChar = static_cast(trimmed[0]); if (trimmed[0] == '{' || trimmed[0] == '}' || trimmed[0] == '[' || trimmed[0] == ']') { role = ConsoleResultLineRole::JsonBrace; } else if (trimmed[0] == '"') { if (trimmed.find("\": ") != std::string::npos || trimmed.find("\":") != std::string::npos) { role = ConsoleResultLineRole::JsonKey; } else { role = ConsoleResultLineRole::JsonString; } } else if (std::isdigit(firstChar) || trimmed[0] == '-') { role = ConsoleResultLineRole::JsonNumber; } else if (trimmed == "true," || trimmed == "false," || trimmed == "true" || trimmed == "false" || trimmed == "null," || trimmed == "null") { role = ConsoleResultLineRole::JsonNumber; } } } lines.push_back({line, role}); } return lines; } } // namespace ui } // namespace dragonx