editor_core.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. #pragma once
  2. #include "lumacs/buffer.hpp"
  3. #include "lumacs/window.hpp"
  4. #include "lumacs/kill_ring.hpp"
  5. #include "lumacs/theme.hpp"
  6. #include "lumacs/config.hpp"
  7. #include "lumacs/keybinding.hpp"
  8. #include "lumacs/modeline.hpp"
  9. #include "lumacs/minibuffer_manager.hpp" // Added include
  10. #include "lumacs/completion_system.hpp" // Added include
  11. #include "lumacs/ui_interface.hpp" // Include for EditorEvent
  12. #include "lumacs/i_command_target.hpp" // New include for ICommandTarget
  13. #include <memory>
  14. #include <functional>
  15. #include <vector>
  16. #include <list>
  17. #include <unordered_map>
  18. #include <chrono> // For std::chrono::steady_clock
  19. #include <optional> // For std::optional
  20. namespace lumacs {
  21. class LuaApi; // Forward declaration
  22. class CommandSystem; // Forward declaration
  23. /// @brief Represents a node in the window layout tree.
  24. struct LayoutNode {
  25. enum class Type { Leaf, HorizontalSplit, VerticalSplit };
  26. Type type;
  27. // If Leaf
  28. std::shared_ptr<Window> window;
  29. // If Split
  30. std::shared_ptr<LayoutNode> child1;
  31. std::shared_ptr<LayoutNode> child2;
  32. float ratio = 0.5f; // Split ratio (0.0 to 1.0)
  33. LayoutNode(std::shared_ptr<Window> w) : type(Type::Leaf), window(w) {}
  34. LayoutNode(Type t, std::shared_ptr<LayoutNode> c1, std::shared_ptr<LayoutNode> c2)
  35. : type(t), child1(c1), child2(c2) {}
  36. };
  37. /// @brief Core logic of the Lumacs editor, independent of the UI framework.
  38. ///
  39. /// This class acts as the central controller/facade for the editor's logic.
  40. /// It manages buffers, windows, the kill ring, registers, macros, configuration,
  41. /// and subsystems like the command system and Lua API.
  42. /// It emits events to notify the UI (IEditorView) of state changes.
  43. class EditorCore : public ICommandTarget { // Inherit from ICommandTarget
  44. public:
  45. EditorCore();
  46. ~EditorCore();
  47. // Disable copy, allow move
  48. EditorCore(const EditorCore&) = delete;
  49. EditorCore& operator=(const EditorCore&) = delete;
  50. EditorCore(EditorCore&&) noexcept = default; // Should now be fine due to unique_ptr members
  51. EditorCore& operator=(EditorCore&&) noexcept = default; // Should now be fine due to unique_ptr members
  52. // === ICommandTarget Implementation ===
  53. // These methods implement the ICommandTarget interface.
  54. // Buffer Management
  55. [[nodiscard]] const Buffer& buffer() const noexcept override;
  56. [[nodiscard]] Buffer& buffer() noexcept override;
  57. bool load_file(const std::filesystem::path& path) override;
  58. void new_buffer(std::string name = "*scratch*") override;
  59. [[nodiscard]] std::vector<std::string> get_buffer_names() const override;
  60. [[nodiscard]] std::shared_ptr<Buffer> get_buffer_by_name(const std::string& name) override;
  61. bool switch_buffer_in_window(const std::string& name) override;
  62. bool close_buffer(const std::string& name) override;
  63. // Window Management
  64. [[nodiscard]] std::shared_ptr<Window> active_window() const override { return active_window_; }
  65. bool set_active_window(std::shared_ptr<Window> window) override;
  66. void split_horizontally() override;
  67. void split_vertically() override;
  68. void close_active_window() override;
  69. void next_window() override;
  70. // Cursor Management
  71. [[nodiscard]] Position cursor() const noexcept override;
  72. void set_cursor(Position pos) override;
  73. // Basic Editing
  74. void move_up() override;
  75. void move_down() override;
  76. void move_left() override;
  77. void move_right() override;
  78. void move_to_line_start() override;
  79. void move_to_line_end() override;
  80. void move_forward_word() override;
  81. void move_backward_word() override;
  82. void page_up() override;
  83. void page_down() override;
  84. void goto_beginning() override;
  85. void goto_end() override;
  86. void goto_line(size_t line) override;
  87. void kill_line() override;
  88. void kill_region() override;
  89. void copy_region_as_kill() override;
  90. void yank() override;
  91. void yank_pop() override;
  92. void kill_word() override;
  93. void backward_kill_word() override;
  94. // Message Display
  95. void set_message(std::string msg) override;
  96. // Quit
  97. void request_quit() override;
  98. // Configuration
  99. Config& config() override { return config_; }
  100. const Config& config() const override { return config_; }
  101. // Theme Management
  102. ThemeManager& theme_manager() override { return theme_manager_; }
  103. const ThemeManager& theme_manager() const override { return theme_manager_; }
  104. // === Original EditorCore methods not part of ICommandTarget ===
  105. /// @brief Get the last set message.
  106. const std::string& last_message() const { return last_message_; }
  107. /// @brief Check if a message is set and if its display time has expired.
  108. /// Clears the message if expired.
  109. void check_and_clear_message();
  110. // === Actions ===
  111. // These methods trigger specific input modes in the UI.
  112. void enter_command_mode();
  113. void enter_buffer_switch_mode();
  114. void enter_kill_buffer_mode();
  115. void enter_find_file_mode();
  116. void enter_theme_selection_mode();
  117. void enter_isearch_mode();
  118. void enter_isearch_backward_mode();
  119. /// @brief Structure containing summary information about a buffer.
  120. struct BufferInfo {
  121. std::string name;
  122. size_t size;
  123. bool modified;
  124. std::string mode;
  125. std::optional<std::filesystem::path> filepath;
  126. };
  127. /// @brief Get detailed information about all buffers.
  128. [[nodiscard]] std::vector<BufferInfo> get_all_buffer_info() const;
  129. /// @brief Get the root node of the window layout tree.
  130. std::shared_ptr<LayoutNode> root_layout() const { return root_node_; }
  131. // === Viewport Management (Proxies to active window) ===
  132. const Viewport& viewport() const noexcept;
  133. void set_viewport_size(int width, int height);
  134. void adjust_scroll();
  135. std::pair<size_t, size_t> visible_line_range() const;
  136. // === Event Callbacks ===
  137. using EventCallback = std::function<void(EditorEvent)>;
  138. /// @brief Register a callback to be notified of editor events.
  139. void on_event(EventCallback callback) {
  140. event_callbacks_.push_back(std::move(callback));
  141. }
  142. /// @brief Clear all registered event callbacks.
  143. void clear_event_callbacks() {
  144. event_callbacks_.clear();
  145. }
  146. // === Undo/Redo ===
  147. bool undo();
  148. bool redo();
  149. bool can_undo() const;
  150. bool can_redo() const;
  151. // === Kill Ring ===
  152. /// @brief Access the global Kill Ring (clipboard history).
  153. [[nodiscard]] KillRing& kill_ring() noexcept { return kill_ring_; }
  154. [[nodiscard]] const KillRing& kill_ring() const noexcept { return kill_ring_; }
  155. // === Registers ===
  156. /// @brief Save text to a named register.
  157. void copy_to_register(char register_name, const std::string& text);
  158. /// @brief Insert text from a named register.
  159. bool insert_register(char register_name);
  160. /// @brief Copy the active region to a register (C-x r s).
  161. void copy_region_to_register(char register_name);
  162. /// @brief Insert text from a register (C-x r i).
  163. bool yank_from_register(char register_name);
  164. // === Keyboard Macros ===
  165. /// @brief Start recording a keyboard macro (F3).
  166. void start_kbd_macro();
  167. /// @brief Stop recording or execute the last macro (F4).
  168. void end_kbd_macro_or_call();
  169. /// @brief Record a key sequence if macro recording is active.
  170. void record_key_sequence(const std::string& key_sequence);
  171. /// @brief Check if macro recording is currently active.
  172. [[nodiscard]] bool is_recording_macro() const noexcept { return recording_macro_; }
  173. // === Rectangles ===
  174. /// @brief Kill (cut) a rectangular region (C-x r k).
  175. void kill_rectangle();
  176. /// @brief Yank (paste) the last killed rectangle (C-x r y).
  177. void yank_rectangle();
  178. /// @brief Replace a rectangular region with a string (C-x r t).
  179. void string_rectangle(const std::string& text);
  180. // === Key Binding System ===
  181. [[nodiscard]] KeyBindingManager& keybinding_manager() noexcept { return *keybinding_manager_; }
  182. [[nodiscard]] const KeyBindingManager& keybinding_manager() const noexcept { return *keybinding_manager_; }
  183. // === Lua API ===
  184. [[nodiscard]] LuaApi* lua_api() const { return lua_api_.get(); }
  185. // === Command System ===
  186. [[nodiscard]] CommandSystem& command_system() noexcept { return *command_system_; }
  187. [[nodiscard]] const CommandSystem& command_system() const noexcept { return *command_system_; }
  188. // === Modeline Manager ===
  189. [[nodiscard]] ModelineManager& modeline_manager() noexcept { return modeline_manager_; }
  190. [[nodiscard]] const ModelineManager& modeline_manager() const noexcept { return modeline_manager_; }
  191. // === Minibuffer Manager ===
  192. [[nodiscard]] MinibufferManager& minibuffer_manager() noexcept { return *minibuffer_manager_; }
  193. [[nodiscard]] const MinibufferManager& minibuffer_manager() const noexcept { return *minibuffer_manager_; }
  194. // === Completion System ===
  195. [[nodiscard]] CompletionSystem& completion_system() noexcept { return *completion_system_; }
  196. [[nodiscard]] const CompletionSystem& completion_system() const noexcept { return *completion_system_; }
  197. private:
  198. std::list<std::shared_ptr<Buffer>> buffers_;
  199. // Word movement helpers
  200. Position calculate_forward_word_pos(Position start_pos);
  201. Position calculate_backward_word_pos(Position start_pos);
  202. // Window layout
  203. std::shared_ptr<LayoutNode> root_node_;
  204. std::shared_ptr<Window> active_window_;
  205. std::string last_message_;
  206. std::optional<std::chrono::steady_clock::time_point> message_clear_time_;
  207. std::vector<EventCallback> event_callbacks_;
  208. // Kill ring for cut/copy/paste
  209. KillRing kill_ring_;
  210. // Last yank position (for yank-pop)
  211. std::optional<Position> last_yank_start_;
  212. std::optional<Position> last_yank_end_;
  213. // Registers for storing text (a-z, A-Z, 0-9)
  214. std::unordered_map<char, std::string> registers_;
  215. // Keyboard macros
  216. std::vector<std::string> current_macro_;
  217. std::vector<std::string> last_macro_;
  218. bool recording_macro_ = false;
  219. // Rectangle storage
  220. std::vector<std::string> rectangle_kill_ring_;
  221. // Subsystems
  222. ThemeManager theme_manager_;
  223. Config config_;
  224. std::unique_ptr<CommandSystem> command_system_; // Must be declared before KeyBindingManager
  225. std::unique_ptr<KeyBindingManager> keybinding_manager_; // Changed to unique_ptr
  226. std::unique_ptr<LuaApi> lua_api_;
  227. ModelineManager modeline_manager_;
  228. std::unique_ptr<CompletionSystem> completion_system_; // Added missing member
  229. std::unique_ptr<MinibufferManager> minibuffer_manager_; // Added missing member
  230. void emit_event(EditorEvent event);
  231. // Helper to find a node containing the active window
  232. LayoutNode* find_parent_node(LayoutNode* root, std::shared_ptr<Window> target);
  233. // Helper to collect all windows in traversal order
  234. void collect_windows(LayoutNode* node, std::vector<std::shared_ptr<Window>>& windows);
  235. };
  236. } // namespace lumacs