console: handleEvent dispatch a handleTextInput/HistoryUp/Down/Tab
This commit is contained in:
+82
-72
@@ -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<unsigned char>(event.text.text[0]) < 32) { return; }
|
||||
if (static_cast<int>(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<int>(history_.size()) - 1) { return; }
|
||||
if (history_index_ == -1) { saved_input_ = input_line_; }
|
||||
++history_index_;
|
||||
input_line_ = history_[static_cast<size_t>(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<size_t>(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<char>(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<int>(tab_matches_.size());
|
||||
std::string result = tab_matches_[static_cast<size_t>(tab_index_)];
|
||||
std::ranges::transform(result, result.begin(), [](char c) { return static_cast<char>(std::tolower(static_cast<unsigned char>(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<unsigned char>(event.text.text[0]) < 32) { return; }
|
||||
if (static_cast<int>(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<int>(history_.size()) - 1) {
|
||||
if (history_index_ == -1) { saved_input_ = input_line_; }
|
||||
++history_index_;
|
||||
input_line_ = history_[static_cast<size_t>(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<size_t>(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<char>(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<int>(tab_matches_.size());
|
||||
std::string result = tab_matches_[static_cast<size_t>(tab_index_)];
|
||||
std::ranges::transform(result, result.begin(), [](char c) { return static_cast<char>(std::tolower(static_cast<unsigned char>(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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> text_;
|
||||
std::shared_ptr<Surface> surface_;
|
||||
|
||||
Reference in New Issue
Block a user