editor_core.hpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. #pragma once
  2. #include "lumacs/buffer.hpp"
  3. #include "lumacs/window.hpp"
  4. #include <memory>
  5. #include <functional>
  6. #include <vector>
  7. #include <list>
  8. namespace lumacs {
  9. /// Editor state change events
  10. enum class EditorEvent {
  11. BufferModified,
  12. CursorMoved,
  13. ViewportChanged,
  14. WindowLayoutChanged, // New event
  15. Message, // New event
  16. CommandMode, // Trigger command mode (minibuffer)
  17. Quit
  18. };
  19. struct LayoutNode;
  20. /// Core editor logic, independent of UI framework
  21. class EditorCore {
  22. public:
  23. EditorCore();
  24. ~EditorCore() = default;
  25. // Disable copy, allow move
  26. EditorCore(const EditorCore&) = delete;
  27. EditorCore& operator=(const EditorCore&) = delete;
  28. EditorCore(EditorCore&&) noexcept = default;
  29. EditorCore& operator=(EditorCore&&) noexcept = default;
  30. // === Message System ===
  31. void set_message(std::string msg) {
  32. last_message_ = std::move(msg);
  33. emit_event(EditorEvent::Message);
  34. }
  35. const std::string& last_message() const { return last_message_; }
  36. // === Actions ===
  37. void enter_command_mode() {
  38. emit_event(EditorEvent::CommandMode);
  39. }
  40. // === Buffer Management ===
  41. /// Get the current buffer (of the active window)
  42. [[nodiscard]] const Buffer& buffer() const noexcept;
  43. [[nodiscard]] Buffer& buffer() noexcept;
  44. /// Load a file into the current window
  45. bool load_file(const std::filesystem::path& path);
  46. /// Create a new empty buffer in current window
  47. void new_buffer(std::string name = "*scratch*");
  48. // === Window Management ===
  49. /// Split the current window horizontally (active window becomes top, new one bottom)
  50. void split_horizontally();
  51. /// Split the current window vertically (active window becomes left, new one right)
  52. void split_vertically();
  53. /// Close the current window
  54. void close_active_window();
  55. /// Move focus to the next window
  56. void next_window();
  57. /// Get the active window
  58. std::shared_ptr<Window> active_window() const { return active_window_; }
  59. /// Get the root of the layout tree (for rendering)
  60. std::shared_ptr<LayoutNode> root_layout() const { return root_node_; }
  61. // === Cursor Management (Proxies to active window) ===
  62. [[nodiscard]] Position cursor() const noexcept;
  63. void set_cursor(Position pos);
  64. // === Cursor Movement (Proxies to active window) ===
  65. void move_up();
  66. void move_down();
  67. void move_left();
  68. void move_right();
  69. void move_to_line_start();
  70. void move_to_line_end();
  71. // === Viewport Management (Proxies to active window) ===
  72. const Viewport& viewport() const noexcept;
  73. void set_viewport_size(int width, int height);
  74. void adjust_scroll();
  75. std::pair<size_t, size_t> visible_line_range() const;
  76. // === Event Callbacks ===
  77. using EventCallback = std::function<void(EditorEvent)>;
  78. void on_event(EventCallback callback) {
  79. event_callbacks_.push_back(std::move(callback));
  80. }
  81. // === Actions ===
  82. void request_quit() {
  83. emit_event(EditorEvent::Quit);
  84. }
  85. // === Undo/Redo ===
  86. bool undo();
  87. bool redo();
  88. bool can_undo() const;
  89. bool can_redo() const;
  90. private:
  91. // All open buffers
  92. std::list<std::shared_ptr<Buffer>> buffers_;
  93. // Window layout
  94. std::shared_ptr<LayoutNode> root_node_;
  95. std::shared_ptr<Window> active_window_;
  96. std::string last_message_;
  97. std::vector<EventCallback> event_callbacks_;
  98. void emit_event(EditorEvent event);
  99. // Helper to find a node containing the active window
  100. LayoutNode* find_parent_node(LayoutNode* root, std::shared_ptr<Window> target);
  101. // Helper to collect all windows in traversal order
  102. void collect_windows(LayoutNode* node, std::vector<std::shared_ptr<Window>>& windows);
  103. };
  104. struct LayoutNode {
  105. enum class Type { Leaf, HorizontalSplit, VerticalSplit };
  106. Type type;
  107. // If Leaf
  108. std::shared_ptr<Window> window;
  109. // If Split
  110. std::shared_ptr<LayoutNode> child1;
  111. std::shared_ptr<LayoutNode> child2;
  112. float ratio = 0.5f; // For future resizing
  113. LayoutNode(std::shared_ptr<Window> w) : type(Type::Leaf), window(w) {}
  114. LayoutNode(Type t, std::shared_ptr<LayoutNode> c1, std::shared_ptr<LayoutNode> c2)
  115. : type(t), child1(c1), child2(c2) {}
  116. };
  117. } // namespace lumacs