minibuffer_manager.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #include "lumacs/minibuffer_manager.hpp"
  2. #include "lumacs/editor_core.hpp" // For EditorCore interaction
  3. #include "lumacs/lua_api.hpp" // For LuaApi interaction
  4. #include "lumacs/minibuffer_mode_hash.hpp" // New include for MinibufferMode hash
  5. #include "lumacs/completion_system.hpp" // Include for CompletionSystem
  6. #include "lumacs/command_system.hpp" // For Command and CommandSystem
  7. #include <functional> // Required for std::function
  8. #include <sstream> // For parsing command line
  9. #include <iostream> // TODO: Replace with proper logging
  10. namespace lumacs {
  11. MinibufferManager::MinibufferManager(EditorCore& core, LuaApi& lua_api, CompletionSystem& completion_system)
  12. : core_(core), lua_api_(lua_api), completion_system_(completion_system) {
  13. // Initialize history managers for each mode
  14. histories_[MinibufferMode::Command] = HistoryManager();
  15. histories_[MinibufferMode::FilePath] = HistoryManager();
  16. histories_[MinibufferMode::BufferName] = HistoryManager();
  17. histories_[MinibufferMode::ThemeName] = HistoryManager();
  18. histories_[MinibufferMode::ISearch] = HistoryManager();
  19. histories_[MinibufferMode::ystring] = HistoryManager();
  20. histories_[MinibufferMode::y_or_n_p] = HistoryManager();
  21. }
  22. void MinibufferManager::activate_minibuffer(MinibufferMode mode, const std::string& prompt,
  23. std::function<void(const std::string&)> on_submit,
  24. std::function<void()> on_cancel) {
  25. current_mode_ = mode;
  26. prompt_text_ = prompt;
  27. input_buffer_ = ""; // Clear previous input
  28. on_submit_callback_ = on_submit;
  29. on_cancel_callback_ = on_cancel;
  30. cursor_position_ = 0; // Initialize cursor position
  31. // Set current history manager based on mode
  32. current_history_ = &histories_[mode];
  33. update_completion_candidates();
  34. }
  35. void MinibufferManager::deactivate_minibuffer() {
  36. current_mode_ = MinibufferMode::None;
  37. prompt_text_ = "";
  38. input_buffer_ = "";
  39. on_submit_callback_ = nullptr;
  40. on_cancel_callback_ = nullptr;
  41. current_history_ = nullptr; // Clear current history pointer
  42. completion_candidates_.clear();
  43. completion_index_ = 0;
  44. cursor_position_ = 0; // Reset cursor position
  45. }
  46. bool MinibufferManager::handle_key_event(const std::string& key_name) {
  47. if (current_mode_ == MinibufferMode::None) {
  48. return false; // Minibuffer not active
  49. }
  50. if (key_name == "Return") {
  51. add_to_history();
  52. if (on_submit_callback_) {
  53. on_submit_callback_(input_buffer_);
  54. }
  55. deactivate_minibuffer();
  56. return true;
  57. } else if (key_name == "Escape") {
  58. if (on_cancel_callback_) {
  59. on_cancel_callback_();
  60. }
  61. deactivate_minibuffer();
  62. return true;
  63. } else if (key_name == "BackSpace") {
  64. if (cursor_position_ > 0) {
  65. input_buffer_.erase(cursor_position_ - 1, 1);
  66. cursor_position_--;
  67. update_completion_candidates(); // Update completions on backspace
  68. }
  69. return true;
  70. } else if (key_name == "Delete") {
  71. if (cursor_position_ < input_buffer_.length()) {
  72. input_buffer_.erase(cursor_position_, 1);
  73. update_completion_candidates(); // Update completions on delete
  74. }
  75. return true;
  76. } else if (key_name == "Left" || key_name == "ArrowLeft") {
  77. if (cursor_position_ > 0) {
  78. cursor_position_--;
  79. }
  80. return true;
  81. } else if (key_name == "Right" || key_name == "ArrowRight") {
  82. if (cursor_position_ < input_buffer_.length()) {
  83. cursor_position_++;
  84. }
  85. return true;
  86. } else if (key_name == "Home") {
  87. cursor_position_ = 0;
  88. return true;
  89. } else if (key_name == "End") {
  90. cursor_position_ = input_buffer_.length();
  91. return true;
  92. } else if (key_name == "Tab") {
  93. complete();
  94. return true;
  95. } else if (key_name == "C-p" || key_name == "ArrowUp") { // Previous history
  96. history_previous();
  97. return true;
  98. } else if (key_name == "C-n" || key_name == "ArrowDown") { // Next history
  99. history_next();
  100. return true;
  101. } else if (key_name.length() == 1) { // Regular character input
  102. input_buffer_.insert(cursor_position_, key_name);
  103. cursor_position_++;
  104. update_completion_candidates(); // Update completions on new input
  105. return true;
  106. }
  107. return false;
  108. }
  109. std::string MinibufferManager::get_prompt() const {
  110. return prompt_text_;
  111. }
  112. std::string MinibufferManager::get_input_buffer() const {
  113. return input_buffer_;
  114. }
  115. size_t MinibufferManager::get_cursor_position() const {
  116. return cursor_position_;
  117. }
  118. MinibufferMode MinibufferManager::get_current_mode() const { return current_mode_; }
  119. void MinibufferManager::set_input_buffer(const std::string& input) {
  120. input_buffer_ = input;
  121. cursor_position_ = input_buffer_.length();
  122. update_completion_candidates();
  123. }
  124. void MinibufferManager::add_to_history() {
  125. if (current_history_) {
  126. current_history_->add_item(input_buffer_);
  127. }
  128. }
  129. void MinibufferManager::history_previous() {
  130. if (current_history_) {
  131. input_buffer_ = current_history_->previous();
  132. cursor_position_ = input_buffer_.length(); // Move cursor to end of history item
  133. update_completion_candidates();
  134. }
  135. }
  136. void MinibufferManager::history_next() {
  137. if (current_history_) {
  138. input_buffer_ = current_history_->next();
  139. cursor_position_ = input_buffer_.length(); // Move cursor to end of history item
  140. update_completion_candidates();
  141. }
  142. }
  143. void MinibufferManager::update_completion_candidates() {
  144. completion_candidates_.clear();
  145. completion_index_ = 0;
  146. if (input_buffer_.empty()) {
  147. return;
  148. }
  149. completion_candidates_ = completion_system_.get_candidates_for_mode(current_mode_, input_buffer_);
  150. }
  151. std::vector<CompletionCandidate> MinibufferManager::get_completion_candidates() const {
  152. return completion_candidates_;
  153. }
  154. std::optional<std::string> MinibufferManager::get_current_completion() const {
  155. if (!completion_candidates_.empty()) {
  156. return completion_candidates_[completion_index_].text;
  157. }
  158. return std::nullopt;
  159. }
  160. void MinibufferManager::complete() {
  161. if (!completion_candidates_.empty()) {
  162. input_buffer_ = completion_candidates_[completion_index_].text;
  163. completion_index_ = (completion_index_ + 1) % completion_candidates_.size();
  164. // If we cycle, reset the index so next tab starts from the top.
  165. // Or, more Emacs-like, cycle through the list and if we get back to original,
  166. // stay there until new input. For now, simple cycle.
  167. }
  168. }
  169. CommandResult MinibufferManager::parse_and_execute_command_string(const std::string& command_line) {
  170. std::string command_name;
  171. std::vector<std::string> args;
  172. std::stringstream ss(command_line);
  173. ss >> command_name; // Extract command name
  174. std::string arg;
  175. while (ss >> arg) { // Extract arguments
  176. args.push_back(arg);
  177. }
  178. // Directly execute the command. If the command is interactive and needs more arguments,
  179. // the execute method will return PendingInput. This assumes the caller (e.g., Lua API)
  180. // will know how to handle CommandStatus::PendingInput if it tries to execute an
  181. // interactive command that requires more input than provided in the string.
  182. // However, for typical Lua API calls, commands are expected to be fully specified.
  183. return core_.command_system().execute(command_name, args);
  184. }
  185. } // namespace lumacs