diff --git a/source/game/ui/console.cpp b/source/game/ui/console.cpp index 5c1db75..0a6d461 100644 --- a/source/game/ui/console.cpp +++ b/source/game/ui/console.cpp @@ -295,84 +295,94 @@ void Console::toggle() { } // Procesa el evento SDL: entrada de texto, Backspace, Enter -void Console::handleEvent(const SDL_Event& event) { // NOLINT(readability-function-cognitive-complexity) +// Insereix caràcters imprimibles a input_line_ +void Console::handleTextInput(const SDL_Event& event) { + // Filtrar caràcters de control (tab, newline, etc.) + if (static_cast(event.text.text[0]) < 32) { return; } + if (static_cast(input_line_.size()) < MAX_LINE_CHARS) { + input_line_ += event.text.text; + } + tab_matches_.clear(); +} + +// Navega enrere a l'historial (cap a comandes més antigues) +void Console::handleHistoryUp() { + tab_matches_.clear(); + if (history_index_ >= static_cast(history_.size()) - 1) { return; } + if (history_index_ == -1) { saved_input_ = input_line_; } + ++history_index_; + input_line_ = history_[static_cast(history_index_)]; +} + +// Navega cap al present a l'historial (cap a comandes més recents) +void Console::handleHistoryDown() { + tab_matches_.clear(); + if (history_index_ < 0) { return; } + --history_index_; + input_line_ = (history_index_ == -1) ? saved_input_ : history_[static_cast(history_index_)]; +} + +// Autocompletat per TAB: calcula candidats si cal i cicla +void Console::handleTab() { + if (tab_matches_.empty()) { + std::string upper; + for (const unsigned char C : input_line_) { upper += static_cast(std::toupper(C)); } + + const size_t SPACE_POS = upper.rfind(' '); + if (SPACE_POS == std::string::npos) { + // Mode comanda: cicla keywords visibles que comencen pel prefix + const auto KEYWORDS = registry_.getVisibleKeywords(); + std::ranges::copy_if(KEYWORDS, std::back_inserter(tab_matches_), [&upper](const auto& kw) { return upper.empty() || kw.starts_with(upper); }); + } else { + const std::string BASE_CMD = upper.substr(0, SPACE_POS); + const std::string SUB_PREFIX = upper.substr(SPACE_POS + 1); + const auto OPTS = registry_.getCompletions(BASE_CMD); + for (const auto& arg : OPTS) { + if (!SUB_PREFIX.empty() && !std::string_view{arg}.starts_with(SUB_PREFIX)) { continue; } + std::string match = BASE_CMD; + match += ' '; + match += arg; + tab_matches_.push_back(std::move(match)); + } + } + tab_index_ = -1; + } + if (tab_matches_.empty()) { return; } + tab_index_ = (tab_index_ + 1) % static_cast(tab_matches_.size()); + std::string result = tab_matches_[static_cast(tab_index_)]; + std::ranges::transform(result, result.begin(), [](char c) { return static_cast(std::tolower(static_cast(c))); }); + input_line_ = result; +} + +void Console::handleEvent(const SDL_Event& event) { if (status_ != Status::ACTIVE) { return; } if (event.type == SDL_EVENT_TEXT_INPUT) { - // Filtrar caracteres de control (tab, newline, etc.) - if (static_cast(event.text.text[0]) < 32) { return; } - if (static_cast(input_line_.size()) < MAX_LINE_CHARS) { - input_line_ += event.text.text; - } - tab_matches_.clear(); + handleTextInput(event); return; } + if (event.type != SDL_EVENT_KEY_DOWN) { return; } - if (event.type == SDL_EVENT_KEY_DOWN) { - switch (event.key.scancode) { - case SDL_SCANCODE_BACKSPACE: - tab_matches_.clear(); - if (!input_line_.empty()) { input_line_.pop_back(); } - break; - case SDL_SCANCODE_RETURN: - case SDL_SCANCODE_KP_ENTER: - processCommand(); - break; - case SDL_SCANCODE_UP: - // Navegar hacia atrás en el historial - tab_matches_.clear(); - if (history_index_ < static_cast(history_.size()) - 1) { - if (history_index_ == -1) { saved_input_ = input_line_; } - ++history_index_; - input_line_ = history_[static_cast(history_index_)]; - } - break; - case SDL_SCANCODE_DOWN: - // Navegar hacia el presente en el historial - tab_matches_.clear(); - if (history_index_ >= 0) { - --history_index_; - input_line_ = (history_index_ == -1) - ? saved_input_ - : history_[static_cast(history_index_)]; - } - break; - case SDL_SCANCODE_TAB: { - if (tab_matches_.empty()) { - // Calcular el input actual en mayúsculas - std::string upper; - for (unsigned char c : input_line_) { upper += static_cast(std::toupper(c)); } - - const size_t SPACE_POS = upper.rfind(' '); - if (SPACE_POS == std::string::npos) { - // Modo comando: ciclar keywords visibles que empiecen por el prefijo - const auto KEYWORDS = registry_.getVisibleKeywords(); - std::ranges::copy_if(KEYWORDS, std::back_inserter(tab_matches_), [&upper](const auto& kw) { return upper.empty() || kw.starts_with(upper); }); - } else { - const std::string BASE_CMD = upper.substr(0, SPACE_POS); - const std::string SUB_PREFIX = upper.substr(SPACE_POS + 1); - const auto OPTS = registry_.getCompletions(BASE_CMD); - for (const auto& arg : OPTS) { - if (SUB_PREFIX.empty() || std::string_view{arg}.starts_with(SUB_PREFIX)) { - std::string match = BASE_CMD; - match += ' '; - match += arg; - tab_matches_.push_back(std::move(match)); - } - } - } - tab_index_ = -1; - } - if (tab_matches_.empty()) { break; } - tab_index_ = (tab_index_ + 1) % static_cast(tab_matches_.size()); - std::string result = tab_matches_[static_cast(tab_index_)]; - std::ranges::transform(result, result.begin(), [](char c) { return static_cast(std::tolower(static_cast(c))); }); - input_line_ = result; - break; - } - default: - break; - } + switch (event.key.scancode) { + case SDL_SCANCODE_BACKSPACE: + tab_matches_.clear(); + if (!input_line_.empty()) { input_line_.pop_back(); } + break; + case SDL_SCANCODE_RETURN: + case SDL_SCANCODE_KP_ENTER: + processCommand(); + break; + case SDL_SCANCODE_UP: + handleHistoryUp(); + break; + case SDL_SCANCODE_DOWN: + handleHistoryDown(); + break; + case SDL_SCANCODE_TAB: + handleTab(); + break; + default: + break; } } diff --git a/source/game/ui/console.hpp b/source/game/ui/console.hpp index e0644a7..06289cb 100644 --- a/source/game/ui/console.hpp +++ b/source/game/ui/console.hpp @@ -85,6 +85,12 @@ class Console { void updateResizeAnimation(float delta_time); // Animació d'altura quan msg_lines_ canvia void updateOpenCloseAnimation(float delta_time); // Animació RISING/VANISHING + // Sub-pasos de handleEvent() (extrets per reduir complexitat cognitiva) + void handleTextInput(const SDL_Event& event); // Insereix caràcters imprimibles a input_line_ + void handleHistoryUp(); // Navegar enrere a l'historial + void handleHistoryDown(); // Navegar cap al present a l'historial + void handleTab(); // Autocompletat per TAB (comandes o sub-args) + // Objetos de renderizado std::shared_ptr text_; std::shared_ptr surface_;