diff --git a/src/cli/tui/autocomplete_ui.cc b/src/cli/tui/autocomplete_ui.cc new file mode 100644 index 00000000..038c42a3 --- /dev/null +++ b/src/cli/tui/autocomplete_ui.cc @@ -0,0 +1,127 @@ +#include +#include +#include "cli/util/autocomplete.h" +#include "cli/tui.h" + +namespace yaze { +namespace cli { + +using namespace ftxui; + +Component CreateAutocompleteInput(std::string* input_str, + AutocompleteEngine* engine) { + auto input = Input(input_str, "Type command..."); + + return Renderer(input, [=] { + auto suggestions = engine->GetSuggestions(*input_str); + + Elements suggestion_list; + for (size_t i = 0; i < std::min(suggestions.size(), size_t(5)); ++i) { + const auto& s = suggestions[i]; + suggestion_list.push_back( + hbox({ + text("→ ") | color(Color::Cyan), + text(s.text) | bold, + text(" ") | flex, + text(s.description) | dim, + }) + ); + } + + return vbox({ + hbox({ + text("āÆ ") | color(Color::GreenLight), + input->Render() | flex, + }), + + (suggestions.empty() ? text("") : + vbox({ + separator(), + text("Suggestions:") | dim, + vbox(suggestion_list), + }) | size(HEIGHT, LESS_THAN, 8) + ), + }); + }); +} + +Component CreateQuickActionMenu(ScreenInteractive& screen) { + static int selected = 0; + static const std::vector actions = { + "šŸ“– Read hex at address", + "šŸŽØ View palette colors", + "šŸ” Search hex pattern", + "šŸ“Š Analyze palette", + "šŸ’¾ ROM info", + "ā¬…ļø Back", + }; + + auto menu = Menu(&actions, &selected); + + return CatchEvent(menu, [&](Event e) { + if (e == Event::Return) { + switch (selected) { + case 0: { + // Quick hex read + std::cout << "\nšŸ“– Quick Hex Read\n"; + std::cout << "Address (hex): "; + std::string addr; + std::getline(std::cin, addr); + if (!addr.empty()) { + agent::HandleHexRead({"--address=" + addr, "--length=16", "--format=both"}, + &app_context.rom); + } + break; + } + case 1: { + std::cout << "\nšŸŽØ Quick Palette View\n"; + std::cout << "Group (0-7): "; + std::string group; + std::getline(std::cin, group); + std::cout << "Palette (0-7): "; + std::string pal; + std::getline(std::cin, pal); + agent::HandlePaletteGetColors({"--group=" + group, "--palette=" + pal, "--format=hex"}, + &app_context.rom); + break; + } + case 2: { + std::cout << "\nšŸ” Hex Pattern Search\n"; + std::cout << "Pattern (e.g. FF 00 ?? 12): "; + std::string pattern; + std::getline(std::cin, pattern); + agent::HandleHexSearch({"--pattern=" + pattern}, &app_context.rom); + break; + } + case 3: { + std::cout << "\nšŸ“Š Palette Analysis\n"; + std::cout << "Group/Palette (e.g. 0/0): "; + std::string id; + std::getline(std::cin, id); + agent::HandlePaletteAnalyze({"--type=palette", "--id=" + id}, &app_context.rom); + break; + } + case 4: { + if (app_context.rom.is_loaded()) { + std::cout << "\nšŸ’¾ ROM Information\n"; + std::cout << "Title: " << app_context.rom.title() << "\n"; + std::cout << "Size: " << app_context.rom.size() << " bytes\n"; + } else { + std::cout << "\nāš ļø No ROM loaded\n"; + } + std::cout << "\nPress Enter to continue..."; + std::cin.get(); + break; + } + case 5: + app_context.current_layout = LayoutID::kMainMenu; + screen.ExitLoopClosure()(); + return true; + } + } + return false; + }); +} + +} // namespace cli +} // namespace yaze diff --git a/src/cli/util/autocomplete.cc b/src/cli/util/autocomplete.cc new file mode 100644 index 00000000..33b5e593 --- /dev/null +++ b/src/cli/util/autocomplete.cc @@ -0,0 +1,92 @@ +#include "cli/util/autocomplete.h" + +#include +#include + +namespace yaze { +namespace cli { + +void AutocompleteEngine::RegisterCommand(const std::string& cmd, const std::string& desc, + const std::vector& examples) { + CommandDef def; + def.name = cmd; + def.description = desc; + def.examples = examples; + commands_.push_back(def); +} + +void AutocompleteEngine::RegisterParameter(const std::string& param, const std::string& desc, + const std::vector& values) { + // TODO: Store parameter definitions +} + +int AutocompleteEngine::FuzzyScore(const std::string& text, const std::string& query) { + if (query.empty()) return 0; + + std::string t = text, q = query; + std::transform(t.begin(), t.end(), t.begin(), ::tolower); + std::transform(q.begin(), q.end(), q.begin(), ::tolower); + + if (t == q) return 1000; + if (t.find(q) == 0) return 500; + if (t.find(q) != std::string::npos) return 250; + + // Fuzzy char matching + size_t ti = 0, qi = 0; + int score = 0; + while (ti < t.length() && qi < q.length()) { + if (t[ti] == q[qi]) { + score += 10; + qi++; + } + ti++; + } + + return (qi == q.length()) ? score : 0; +} + +std::vector AutocompleteEngine::GetSuggestions(const std::string& input) { + std::vector results; + + for (const auto& cmd : commands_) { + int score = FuzzyScore(cmd.name, input); + if (score > 0) { + Suggestion s; + s.text = cmd.name; + s.description = cmd.description; + s.example = cmd.examples.empty() ? "" : cmd.examples[0]; + s.score = score; + results.push_back(s); + } + } + + std::sort(results.begin(), results.end(), + [](const Suggestion& a, const Suggestion& b) { + return a.score > b.score; + }); + + return results; +} + +std::vector AutocompleteEngine::GetContextualHelp(const std::string& partial_cmd) { + std::vector help; + + // Parse command and suggest parameters + if (partial_cmd.find("hex-") == 0) { + help.push_back({"--address=0xXXXXXX", "ROM address in hex", ""}); + help.push_back({"--length=16", "Number of bytes", ""}); + help.push_back({"--format=both", "Output format (hex/ascii/both)", ""}); + } else if (partial_cmd.find("palette-") == 0) { + help.push_back({"--group=0", "Palette group (0-7)", ""}); + help.push_back({"--palette=0", "Palette index (0-7)", ""}); + help.push_back({"--format=hex", "Color format (snes/rgb/hex)", ""}); + } else if (partial_cmd.find("dungeon-") == 0) { + help.push_back({"--room_id=5", "Room ID (0-296)", ""}); + help.push_back({"--include_sprites=true", "Include sprite data", ""}); + } + + return help; +} + +} // namespace cli +} // namespace yaze diff --git a/src/cli/util/autocomplete.h b/src/cli/util/autocomplete.h new file mode 100644 index 00000000..fe435a6b --- /dev/null +++ b/src/cli/util/autocomplete.h @@ -0,0 +1,49 @@ +#ifndef YAZE_CLI_UTIL_AUTOCOMPLETE_H_ +#define YAZE_CLI_UTIL_AUTOCOMPLETE_H_ + +#include +#include +#include + +namespace yaze { +namespace cli { + +struct Suggestion { + std::string text; + std::string description; + std::string example; + int score; +}; + +class AutocompleteEngine { + public: + void RegisterCommand(const std::string& cmd, const std::string& desc, + const std::vector& examples = {}); + + void RegisterParameter(const std::string& param, const std::string& desc, + const std::vector& values = {}); + + std::vector GetSuggestions(const std::string& input); + + std::vector GetContextualHelp(const std::string& partial_cmd); + + void SetRomContext(bool has_rom) { has_rom_ = has_rom; } + + private: + struct CommandDef { + std::string name; + std::string description; + std::vector params; + std::vector examples; + }; + + std::vector commands_; + bool has_rom_ = false; + + int FuzzyScore(const std::string& text, const std::string& query); +}; + +} // namespace cli +} // namespace yaze + +#endif // YAZE_CLI_UTIL_AUTOCOMPLETE_H_