#include "lumacs/minibuffer_manager.hpp" #include "lumacs/editor_core.hpp" // For EditorCore interaction #include "lumacs/lua_api.hpp" // For LuaApi interaction #include "lumacs/minibuffer_mode_hash.hpp" // New include for MinibufferMode hash #include "lumacs/completion_system.hpp" // Include for CompletionSystem #include "lumacs/command_system.hpp" // For Command and CommandSystem #include // Required for std::function #include // For parsing command line #include // TODO: Replace with proper logging namespace lumacs { MinibufferManager::MinibufferManager(EditorCore& core, LuaApi& lua_api, CompletionSystem& completion_system) : core_(core), lua_api_(lua_api), completion_system_(completion_system) { // Initialize history managers for each mode histories_[MinibufferMode::Command] = HistoryManager(); histories_[MinibufferMode::FilePath] = HistoryManager(); histories_[MinibufferMode::BufferName] = HistoryManager(); histories_[MinibufferMode::ThemeName] = HistoryManager(); histories_[MinibufferMode::ISearch] = HistoryManager(); histories_[MinibufferMode::ystring] = HistoryManager(); histories_[MinibufferMode::y_or_n_p] = HistoryManager(); } void MinibufferManager::activate_minibuffer(MinibufferMode mode, const std::string& prompt, std::function on_submit, std::function on_cancel) { current_mode_ = mode; prompt_text_ = prompt; input_buffer_ = ""; // Clear previous input on_submit_callback_ = on_submit; on_cancel_callback_ = on_cancel; cursor_position_ = 0; // Initialize cursor position // Set current history manager based on mode current_history_ = &histories_[mode]; update_completion_candidates(); } void MinibufferManager::deactivate_minibuffer() { current_mode_ = MinibufferMode::None; prompt_text_ = ""; input_buffer_ = ""; on_submit_callback_ = nullptr; on_cancel_callback_ = nullptr; current_history_ = nullptr; // Clear current history pointer completion_candidates_.clear(); completion_index_ = 0; cursor_position_ = 0; // Reset cursor position } bool MinibufferManager::handle_key_event(const std::string& key_name) { if (current_mode_ == MinibufferMode::None) { return false; // Minibuffer not active } if (key_name == "Return") { add_to_history(); if (on_submit_callback_) { on_submit_callback_(input_buffer_); } deactivate_minibuffer(); return true; } else if (key_name == "Escape") { if (on_cancel_callback_) { on_cancel_callback_(); } deactivate_minibuffer(); return true; } else if (key_name == "BackSpace") { if (cursor_position_ > 0) { input_buffer_.erase(cursor_position_ - 1, 1); cursor_position_--; update_completion_candidates(); // Update completions on backspace } return true; } else if (key_name == "Delete") { if (cursor_position_ < input_buffer_.length()) { input_buffer_.erase(cursor_position_, 1); update_completion_candidates(); // Update completions on delete } return true; } else if (key_name == "Left" || key_name == "ArrowLeft") { if (cursor_position_ > 0) { cursor_position_--; } return true; } else if (key_name == "Right" || key_name == "ArrowRight") { if (cursor_position_ < input_buffer_.length()) { cursor_position_++; } return true; } else if (key_name == "Home") { cursor_position_ = 0; return true; } else if (key_name == "End") { cursor_position_ = input_buffer_.length(); return true; } else if (key_name == "Tab") { complete(); return true; } else if (key_name == "C-p" || key_name == "ArrowUp") { // Previous history history_previous(); return true; } else if (key_name == "C-n" || key_name == "ArrowDown") { // Next history history_next(); return true; } else if (key_name.length() == 1) { // Regular character input input_buffer_.insert(cursor_position_, key_name); cursor_position_++; update_completion_candidates(); // Update completions on new input return true; } return false; } std::string MinibufferManager::get_prompt() const { return prompt_text_; } std::string MinibufferManager::get_input_buffer() const { return input_buffer_; } size_t MinibufferManager::get_cursor_position() const { return cursor_position_; } MinibufferMode MinibufferManager::get_current_mode() const { return current_mode_; } void MinibufferManager::set_input_buffer(const std::string& input) { input_buffer_ = input; cursor_position_ = input_buffer_.length(); update_completion_candidates(); } void MinibufferManager::add_to_history() { if (current_history_) { current_history_->add_item(input_buffer_); } } void MinibufferManager::history_previous() { if (current_history_) { input_buffer_ = current_history_->previous(); cursor_position_ = input_buffer_.length(); // Move cursor to end of history item update_completion_candidates(); } } void MinibufferManager::history_next() { if (current_history_) { input_buffer_ = current_history_->next(); cursor_position_ = input_buffer_.length(); // Move cursor to end of history item update_completion_candidates(); } } void MinibufferManager::update_completion_candidates() { completion_candidates_.clear(); completion_index_ = 0; if (input_buffer_.empty()) { return; } completion_candidates_ = completion_system_.get_candidates_for_mode(current_mode_, input_buffer_); } std::vector MinibufferManager::get_completion_candidates() const { return completion_candidates_; } std::optional MinibufferManager::get_current_completion() const { if (!completion_candidates_.empty()) { return completion_candidates_[completion_index_].text; } return std::nullopt; } void MinibufferManager::complete() { if (!completion_candidates_.empty()) { input_buffer_ = completion_candidates_[completion_index_].text; completion_index_ = (completion_index_ + 1) % completion_candidates_.size(); // If we cycle, reset the index so next tab starts from the top. // Or, more Emacs-like, cycle through the list and if we get back to original, // stay there until new input. For now, simple cycle. } } CommandResult MinibufferManager::parse_and_execute_command_string(const std::string& command_line) { std::string command_name; std::vector args; std::stringstream ss(command_line); ss >> command_name; // Extract command name std::string arg; while (ss >> arg) { // Extract arguments args.push_back(arg); } // Directly execute the command. If the command is interactive and needs more arguments, // the execute method will return PendingInput. This assumes the caller (e.g., Lua API) // will know how to handle CommandStatus::PendingInput if it tries to execute an // interactive command that requires more input than provided in the string. // However, for typical Lua API calls, commands are expected to be fully specified. return core_.command_system().execute(command_name, args); } } // namespace lumacs