#pragma once #include "lumacs/buffer.hpp" #include "lumacs/window.hpp" #include #include #include #include namespace lumacs { /// Editor state change events enum class EditorEvent { BufferModified, CursorMoved, ViewportChanged, WindowLayoutChanged, // New event WindowFocused, // New event: a different window gained focus Message, // New event CommandMode, // Trigger command mode (minibuffer) Quit }; struct LayoutNode; /// Core editor logic, independent of UI framework class EditorCore { public: EditorCore(); ~EditorCore() = default; // Disable copy, allow move EditorCore(const EditorCore&) = delete; EditorCore& operator=(const EditorCore&) = delete; EditorCore(EditorCore&&) noexcept = default; EditorCore& operator=(EditorCore&&) noexcept = default; // === Message System === void set_message(std::string msg) { last_message_ = std::move(msg); emit_event(EditorEvent::Message); } const std::string& last_message() const { return last_message_; } // === Actions === void enter_command_mode() { emit_event(EditorEvent::CommandMode); } // === Buffer Management === /// Get the current buffer (of the active window) [[nodiscard]] const Buffer& buffer() const noexcept; [[nodiscard]] Buffer& buffer() noexcept; /// Load a file into the current window bool load_file(const std::filesystem::path& path); /// Create a new empty buffer in current window void new_buffer(std::string name = "*scratch*"); // === Window Management === /// Split the current window horizontally (active window becomes top, new one bottom) void split_horizontally(); /// Split the current window vertically (active window becomes left, new one right) void split_vertically(); /// Close the current window void close_active_window(); /// Move focus to the next window void next_window(); /// Get the active window std::shared_ptr active_window() const { return active_window_; } /// Get the root of the layout tree (for rendering) std::shared_ptr root_layout() const { return root_node_; } // === Cursor Management (Proxies to active window) === [[nodiscard]] Position cursor() const noexcept; void set_cursor(Position pos); // === Cursor Movement (Proxies to active window) === void move_up(); void move_down(); void move_left(); void move_right(); void move_to_line_start(); void move_to_line_end(); // === Viewport Management (Proxies to active window) === const Viewport& viewport() const noexcept; void set_viewport_size(int width, int height); void adjust_scroll(); std::pair visible_line_range() const; // === Event Callbacks === using EventCallback = std::function; void on_event(EventCallback callback) { event_callbacks_.push_back(std::move(callback)); } // === Actions === void request_quit() { emit_event(EditorEvent::Quit); } // === Undo/Redo === bool undo(); bool redo(); bool can_undo() const; bool can_redo() const; private: // All open buffers std::list> buffers_; // Window layout std::shared_ptr root_node_; std::shared_ptr active_window_; std::string last_message_; std::vector event_callbacks_; void emit_event(EditorEvent event); // Helper to find a node containing the active window LayoutNode* find_parent_node(LayoutNode* root, std::shared_ptr target); // Helper to collect all windows in traversal order void collect_windows(LayoutNode* node, std::vector>& windows); }; struct LayoutNode { enum class Type { Leaf, HorizontalSplit, VerticalSplit }; Type type; // If Leaf std::shared_ptr window; // If Split std::shared_ptr child1; std::shared_ptr child2; float ratio = 0.5f; // For future resizing LayoutNode(std::shared_ptr w) : type(Type::Leaf), window(w) {} LayoutNode(Type t, std::shared_ptr c1, std::shared_ptr c2) : type(t), child1(c1), child2(c2) {} }; } // namespace lumacs