editor_core.hpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #pragma once
  2. #include "lumacs/buffer.hpp"
  3. #include "lumacs/window.hpp"
  4. #include "lumacs/kill_ring.hpp"
  5. #include <memory>
  6. #include <functional>
  7. #include <vector>
  8. #include <list>
  9. namespace lumacs {
  10. /// Editor state change events
  11. enum class EditorEvent {
  12. BufferModified,
  13. CursorMoved,
  14. ViewportChanged,
  15. WindowLayoutChanged, // New event
  16. WindowFocused, // New event: a different window gained focus
  17. Message, // New event
  18. CommandMode, // Trigger command mode (minibuffer)
  19. BufferSwitchMode, // Trigger buffer switch mode
  20. KillBufferMode, // Trigger kill buffer mode
  21. Quit
  22. };
  23. struct LayoutNode;
  24. /// Core editor logic, independent of UI framework
  25. class EditorCore {
  26. public:
  27. EditorCore();
  28. ~EditorCore() = default;
  29. // Disable copy, allow move
  30. EditorCore(const EditorCore&) = delete;
  31. EditorCore& operator=(const EditorCore&) = delete;
  32. EditorCore(EditorCore&&) noexcept = default;
  33. EditorCore& operator=(EditorCore&&) noexcept = default;
  34. // === Message System ===
  35. void set_message(std::string msg) {
  36. last_message_ = std::move(msg);
  37. emit_event(EditorEvent::Message);
  38. }
  39. const std::string& last_message() const { return last_message_; }
  40. // === Actions ===
  41. void enter_command_mode() {
  42. emit_event(EditorEvent::CommandMode);
  43. }
  44. void enter_buffer_switch_mode() {
  45. emit_event(EditorEvent::BufferSwitchMode);
  46. }
  47. void enter_kill_buffer_mode() {
  48. emit_event(EditorEvent::KillBufferMode);
  49. }
  50. // === Buffer Management ===
  51. /// Get the current buffer (of the active window)
  52. [[nodiscard]] const Buffer& buffer() const noexcept;
  53. [[nodiscard]] Buffer& buffer() noexcept;
  54. /// Load a file into the current window
  55. bool load_file(const std::filesystem::path& path);
  56. /// Create a new empty buffer in current window
  57. void new_buffer(std::string name = "*scratch*");
  58. /// Get list of all buffer names
  59. [[nodiscard]] std::vector<std::string> get_buffer_names() const;
  60. /// Get buffer by name (returns nullptr if not found)
  61. [[nodiscard]] std::shared_ptr<Buffer> get_buffer_by_name(const std::string& name);
  62. /// Switch active window to buffer by name
  63. bool switch_buffer_in_window(const std::string& name);
  64. /// Close buffer by name (returns false if buffer is displayed or doesn't exist)
  65. bool close_buffer(const std::string& name);
  66. /// Buffer information for list display
  67. struct BufferInfo {
  68. std::string name;
  69. size_t size;
  70. bool modified;
  71. std::string mode;
  72. std::optional<std::filesystem::path> filepath;
  73. };
  74. /// Get information about all buffers
  75. [[nodiscard]] std::vector<BufferInfo> get_all_buffer_info() const;
  76. // === Window Management ===
  77. /// Split the current window horizontally (active window becomes top, new one bottom)
  78. void split_horizontally();
  79. /// Split the current window vertically (active window becomes left, new one right)
  80. void split_vertically();
  81. /// Close the current window
  82. void close_active_window();
  83. /// Move focus to the next window
  84. void next_window();
  85. /// Get the active window
  86. std::shared_ptr<Window> active_window() const { return active_window_; }
  87. /// Get the root of the layout tree (for rendering)
  88. std::shared_ptr<LayoutNode> root_layout() const { return root_node_; }
  89. // === Cursor Management (Proxies to active window) ===
  90. [[nodiscard]] Position cursor() const noexcept;
  91. void set_cursor(Position pos);
  92. // === Cursor Movement (Proxies to active window) ===
  93. void move_up();
  94. void move_down();
  95. void move_left();
  96. void move_right();
  97. void move_to_line_start();
  98. void move_to_line_end();
  99. void move_forward_word();
  100. void move_backward_word();
  101. void page_up();
  102. void page_down();
  103. void goto_beginning();
  104. void goto_end();
  105. void goto_line(size_t line);
  106. // === Viewport Management (Proxies to active window) ===
  107. const Viewport& viewport() const noexcept;
  108. void set_viewport_size(int width, int height);
  109. void adjust_scroll();
  110. std::pair<size_t, size_t> visible_line_range() const;
  111. // === Event Callbacks ===
  112. using EventCallback = std::function<void(EditorEvent)>;
  113. void on_event(EventCallback callback) {
  114. event_callbacks_.push_back(std::move(callback));
  115. }
  116. // === Actions ===
  117. void request_quit() {
  118. emit_event(EditorEvent::Quit);
  119. }
  120. // === Undo/Redo ===
  121. bool undo();
  122. bool redo();
  123. bool can_undo() const;
  124. bool can_redo() const;
  125. // === Kill Ring ===
  126. /// Get the kill ring
  127. [[nodiscard]] KillRing& kill_ring() noexcept { return kill_ring_; }
  128. [[nodiscard]] const KillRing& kill_ring() const noexcept { return kill_ring_; }
  129. /// Kill (cut) text from position to end of line
  130. void kill_line();
  131. /// Kill (cut) the active region
  132. void kill_region();
  133. /// Copy the active region to kill ring (without deleting)
  134. void copy_region_as_kill();
  135. /// Yank (paste) from kill ring
  136. void yank();
  137. /// Yank and pop to previous kill ring entry
  138. void yank_pop();
  139. private:
  140. // All open buffers
  141. std::list<std::shared_ptr<Buffer>> buffers_;
  142. // Window layout
  143. std::shared_ptr<LayoutNode> root_node_;
  144. std::shared_ptr<Window> active_window_;
  145. std::string last_message_;
  146. std::vector<EventCallback> event_callbacks_;
  147. // Kill ring for cut/copy/paste
  148. KillRing kill_ring_;
  149. // Last yank position (for yank-pop)
  150. std::optional<Position> last_yank_start_;
  151. std::optional<Position> last_yank_end_;
  152. void emit_event(EditorEvent event);
  153. // Helper to find a node containing the active window
  154. LayoutNode* find_parent_node(LayoutNode* root, std::shared_ptr<Window> target);
  155. // Helper to collect all windows in traversal order
  156. void collect_windows(LayoutNode* node, std::vector<std::shared_ptr<Window>>& windows);
  157. };
  158. struct LayoutNode {
  159. enum class Type { Leaf, HorizontalSplit, VerticalSplit };
  160. Type type;
  161. // If Leaf
  162. std::shared_ptr<Window> window;
  163. // If Split
  164. std::shared_ptr<LayoutNode> child1;
  165. std::shared_ptr<LayoutNode> child2;
  166. float ratio = 0.5f; // For future resizing
  167. LayoutNode(std::shared_ptr<Window> w) : type(Type::Leaf), window(w) {}
  168. LayoutNode(Type t, std::shared_ptr<LayoutNode> c1, std::shared_ptr<LayoutNode> c2)
  169. : type(t), child1(c1), child2(c2) {}
  170. };
  171. } // namespace lumacs