#pragma once #include "lumacs/buffer.hpp" #include "lumacs/window.hpp" #include "lumacs/kill_ring.hpp" #include "lumacs/theme.hpp" #include "lumacs/config.hpp" #include "lumacs/keybinding.hpp" #include #include #include #include #include namespace lumacs { class LuaApi; // Forward declaration class CommandSystem; // Forward declaration /// 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) BufferSwitchMode, // Trigger buffer switch mode KillBufferMode, // Trigger kill buffer mode FindFileMode, // Trigger find file mode ThemeSelectionMode, // Trigger theme selection mode ISearchMode, // Trigger incremental search mode ISearchBackwardMode, // Trigger incremental search mode (backward) Quit }; struct LayoutNode; /// Core editor logic, independent of UI framework class EditorCore { public: EditorCore(); ~EditorCore(); // 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); } void enter_buffer_switch_mode() { emit_event(EditorEvent::BufferSwitchMode); } void enter_kill_buffer_mode() { emit_event(EditorEvent::KillBufferMode); } void enter_find_file_mode() { emit_event(EditorEvent::FindFileMode); } void enter_theme_selection_mode() { emit_event(EditorEvent::ThemeSelectionMode); } void enter_isearch_mode() { emit_event(EditorEvent::ISearchMode); } void enter_isearch_backward_mode() { emit_event(EditorEvent::ISearchBackwardMode); } // === 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*"); /// Get list of all buffer names [[nodiscard]] std::vector get_buffer_names() const; /// Get buffer by name (returns nullptr if not found) [[nodiscard]] std::shared_ptr get_buffer_by_name(const std::string& name); /// Switch active window to buffer by name bool switch_buffer_in_window(const std::string& name); /// Close buffer by name (returns false if buffer is displayed or doesn't exist) bool close_buffer(const std::string& name); /// Buffer information for list display struct BufferInfo { std::string name; size_t size; bool modified; std::string mode; std::optional filepath; }; /// Get information about all buffers [[nodiscard]] std::vector get_all_buffer_info() const; // === 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(); /// Move focus to the next window (only if called intentionally, not during rapid typing) void next_window_safe(); /// Get the active window std::shared_ptr active_window() const { return active_window_; } /// Set the active window (if it exists in the window tree) bool set_active_window(std::shared_ptr 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(); void move_forward_word(); void move_backward_word(); void page_up(); void page_down(); void goto_beginning(); void goto_end(); void goto_line(size_t line); // === 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)); } void clear_event_callbacks() { event_callbacks_.clear(); } // === Actions === void request_quit() { emit_event(EditorEvent::Quit); } // === Undo/Redo === bool undo(); bool redo(); bool can_undo() const; bool can_redo() const; // === Kill Ring === /// Get the kill ring [[nodiscard]] KillRing& kill_ring() noexcept { return kill_ring_; } [[nodiscard]] const KillRing& kill_ring() const noexcept { return kill_ring_; } // === Registers === /// Copy text to register void copy_to_register(char register_name, const std::string& text); /// Insert text from register bool insert_register(char register_name); /// Save region to register (C-x r s) void copy_region_to_register(char register_name); /// Insert register at cursor (C-x r i) bool yank_from_register(char register_name); // === Keyboard Macros === /// Start recording a keyboard macro (F3) void start_kbd_macro(); /// End macro recording or call last macro (F4) void end_kbd_macro_or_call(); /// Add a key sequence to the current macro being recorded void record_key_sequence(const std::string& key_sequence); /// Check if currently recording a macro [[nodiscard]] bool is_recording_macro() const noexcept { return recording_macro_; } // === Rectangles === /// Kill rectangle (C-x r k) - Cut rectangular region void kill_rectangle(); /// Yank rectangle (C-x r y) - Paste last rectangle void yank_rectangle(); /// String rectangle (C-x r t) - Fill rectangle with string void string_rectangle(const std::string& text); /// Kill (cut) text from position to end of line void kill_line(); /// Kill (cut) the active region void kill_region(); /// Copy the active region to kill ring (without deleting) void copy_region_as_kill(); /// Yank (paste) from kill ring void yank(); /// Yank and pop to previous kill ring entry void yank_pop(); /// Kill word forward void kill_word(); /// Kill word backward void backward_kill_word(); // === Theme Management === /// Get the theme manager [[nodiscard]] ThemeManager& theme_manager() noexcept { return theme_manager_; } [[nodiscard]] const ThemeManager& theme_manager() const noexcept { return theme_manager_; } /// Set active theme void set_theme(const std::string& name) { theme_manager_.set_active_theme(name); } /// Get active theme [[nodiscard]] std::shared_ptr active_theme() const { return theme_manager_.active_theme(); } // === Configuration === /// Get the configuration manager [[nodiscard]] Config& config() noexcept { return config_; } [[nodiscard]] const Config& config() const noexcept { return config_; } // === Key Binding System === [[nodiscard]] KeyBindingManager& keybinding_manager() noexcept { return keybinding_manager_; } [[nodiscard]] const KeyBindingManager& keybinding_manager() const noexcept { return keybinding_manager_; } // === Lua API === [[nodiscard]] LuaApi* lua_api() const { return lua_api_.get(); } // === Command System === [[nodiscard]] CommandSystem& command_system() noexcept { return *command_system_; } [[nodiscard]] const CommandSystem& command_system() const noexcept { return *command_system_; } private: // All open buffers std::list> buffers_; // Word movement helpers Position calculate_forward_word_pos(Position start_pos); Position calculate_backward_word_pos(Position start_pos); // Window layout std::shared_ptr root_node_; std::shared_ptr active_window_; std::string last_message_; std::vector event_callbacks_; // Kill ring for cut/copy/paste KillRing kill_ring_; // Last yank position (for yank-pop) std::optional last_yank_start_; std::optional last_yank_end_; // Registers for storing text (a-z, A-Z, 0-9) std::unordered_map registers_; // Keyboard macros std::vector current_macro_; std::vector last_macro_; bool recording_macro_ = false; // Rectangle storage (each string is one row of the rectangle) std::vector rectangle_kill_ring_; // Theme manager ThemeManager theme_manager_; // Configuration Config config_; // Key binding system KeyBindingManager keybinding_manager_; // Lua API std::unique_ptr lua_api_; // Command System std::unique_ptr command_system_; 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