editor_core.hpp 4.4 KB

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