editor_core.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. #pragma once
  2. #include "lumacs/buffer.hpp"
  3. #include "lumacs/window.hpp"
  4. #include "lumacs/kill_ring.hpp"
  5. #include "lumacs/theme.hpp"
  6. #include "lumacs/config.hpp"
  7. #include "lumacs/keybinding.hpp"
  8. #include <memory>
  9. #include <functional>
  10. #include <vector>
  11. #include <list>
  12. #include <unordered_map>
  13. namespace lumacs {
  14. class LuaApi; // Forward declaration
  15. class CommandSystem; // Forward declaration
  16. /// Editor state change events
  17. enum class EditorEvent {
  18. BufferModified,
  19. CursorMoved,
  20. ViewportChanged,
  21. WindowLayoutChanged, // New event
  22. WindowFocused, // New event: a different window gained focus
  23. Message, // New event
  24. CommandMode, // Trigger command mode (minibuffer)
  25. BufferSwitchMode, // Trigger buffer switch mode
  26. KillBufferMode, // Trigger kill buffer mode
  27. FindFileMode, // Trigger find file mode
  28. ThemeSelectionMode, // Trigger theme selection mode
  29. ISearchMode, // Trigger incremental search mode
  30. ISearchBackwardMode, // Trigger incremental search mode (backward)
  31. Quit
  32. };
  33. struct LayoutNode;
  34. /// Core editor logic, independent of UI framework
  35. class EditorCore {
  36. public:
  37. EditorCore();
  38. ~EditorCore();
  39. // Disable copy, allow move
  40. EditorCore(const EditorCore&) = delete;
  41. EditorCore& operator=(const EditorCore&) = delete;
  42. EditorCore(EditorCore&&) noexcept = default;
  43. EditorCore& operator=(EditorCore&&) noexcept = default;
  44. // === Message System ===
  45. void set_message(std::string msg) {
  46. last_message_ = std::move(msg);
  47. emit_event(EditorEvent::Message);
  48. }
  49. const std::string& last_message() const { return last_message_; }
  50. // === Actions ===
  51. void enter_command_mode() {
  52. emit_event(EditorEvent::CommandMode);
  53. }
  54. void enter_buffer_switch_mode() {
  55. emit_event(EditorEvent::BufferSwitchMode);
  56. }
  57. void enter_kill_buffer_mode() {
  58. emit_event(EditorEvent::KillBufferMode);
  59. }
  60. void enter_find_file_mode() {
  61. emit_event(EditorEvent::FindFileMode);
  62. }
  63. void enter_theme_selection_mode() {
  64. emit_event(EditorEvent::ThemeSelectionMode);
  65. }
  66. void enter_isearch_mode() {
  67. emit_event(EditorEvent::ISearchMode);
  68. }
  69. void enter_isearch_backward_mode() {
  70. emit_event(EditorEvent::ISearchBackwardMode);
  71. }
  72. // === Buffer Management ===
  73. /// Get the current buffer (of the active window)
  74. [[nodiscard]] const Buffer& buffer() const noexcept;
  75. [[nodiscard]] Buffer& buffer() noexcept;
  76. /// Load a file into the current window
  77. bool load_file(const std::filesystem::path& path);
  78. /// Create a new empty buffer in current window
  79. void new_buffer(std::string name = "*scratch*");
  80. /// Get list of all buffer names
  81. [[nodiscard]] std::vector<std::string> get_buffer_names() const;
  82. /// Get buffer by name (returns nullptr if not found)
  83. [[nodiscard]] std::shared_ptr<Buffer> get_buffer_by_name(const std::string& name);
  84. /// Switch active window to buffer by name
  85. bool switch_buffer_in_window(const std::string& name);
  86. /// Close buffer by name (returns false if buffer is displayed or doesn't exist)
  87. bool close_buffer(const std::string& name);
  88. /// Buffer information for list display
  89. struct BufferInfo {
  90. std::string name;
  91. size_t size;
  92. bool modified;
  93. std::string mode;
  94. std::optional<std::filesystem::path> filepath;
  95. };
  96. /// Get information about all buffers
  97. [[nodiscard]] std::vector<BufferInfo> get_all_buffer_info() const;
  98. // === Window Management ===
  99. /// Split the current window horizontally (active window becomes top, new one bottom)
  100. void split_horizontally();
  101. /// Split the current window vertically (active window becomes left, new one right)
  102. void split_vertically();
  103. /// Close the current window
  104. void close_active_window();
  105. /// Move focus to the next window
  106. void next_window();
  107. /// Move focus to the next window (only if called intentionally, not during rapid typing)
  108. void next_window_safe();
  109. /// Get the active window
  110. std::shared_ptr<Window> active_window() const { return active_window_; }
  111. /// Set the active window (if it exists in the window tree)
  112. bool set_active_window(std::shared_ptr<Window> window);
  113. /// Get the root of the layout tree (for rendering)
  114. std::shared_ptr<LayoutNode> root_layout() const { return root_node_; }
  115. // === Cursor Management (Proxies to active window) ===
  116. [[nodiscard]] Position cursor() const noexcept;
  117. void set_cursor(Position pos);
  118. // === Cursor Movement (Proxies to active window) ===
  119. void move_up();
  120. void move_down();
  121. void move_left();
  122. void move_right();
  123. void move_to_line_start();
  124. void move_to_line_end();
  125. void move_forward_word();
  126. void move_backward_word();
  127. void page_up();
  128. void page_down();
  129. void goto_beginning();
  130. void goto_end();
  131. void goto_line(size_t line);
  132. // === Viewport Management (Proxies to active window) ===
  133. const Viewport& viewport() const noexcept;
  134. void set_viewport_size(int width, int height);
  135. void adjust_scroll();
  136. std::pair<size_t, size_t> visible_line_range() const;
  137. // === Event Callbacks ===
  138. using EventCallback = std::function<void(EditorEvent)>;
  139. void on_event(EventCallback callback) {
  140. event_callbacks_.push_back(std::move(callback));
  141. }
  142. void clear_event_callbacks() {
  143. event_callbacks_.clear();
  144. }
  145. // === Actions ===
  146. void request_quit() {
  147. emit_event(EditorEvent::Quit);
  148. }
  149. // === Undo/Redo ===
  150. bool undo();
  151. bool redo();
  152. bool can_undo() const;
  153. bool can_redo() const;
  154. // === Kill Ring ===
  155. /// Get the kill ring
  156. [[nodiscard]] KillRing& kill_ring() noexcept { return kill_ring_; }
  157. [[nodiscard]] const KillRing& kill_ring() const noexcept { return kill_ring_; }
  158. // === Registers ===
  159. /// Copy text to register
  160. void copy_to_register(char register_name, const std::string& text);
  161. /// Insert text from register
  162. bool insert_register(char register_name);
  163. /// Save region to register (C-x r s)
  164. void copy_region_to_register(char register_name);
  165. /// Insert register at cursor (C-x r i)
  166. bool yank_from_register(char register_name);
  167. // === Keyboard Macros ===
  168. /// Start recording a keyboard macro (F3)
  169. void start_kbd_macro();
  170. /// End macro recording or call last macro (F4)
  171. void end_kbd_macro_or_call();
  172. /// Add a key sequence to the current macro being recorded
  173. void record_key_sequence(const std::string& key_sequence);
  174. /// Check if currently recording a macro
  175. [[nodiscard]] bool is_recording_macro() const noexcept { return recording_macro_; }
  176. // === Rectangles ===
  177. /// Kill rectangle (C-x r k) - Cut rectangular region
  178. void kill_rectangle();
  179. /// Yank rectangle (C-x r y) - Paste last rectangle
  180. void yank_rectangle();
  181. /// String rectangle (C-x r t) - Fill rectangle with string
  182. void string_rectangle(const std::string& text);
  183. /// Kill (cut) text from position to end of line
  184. void kill_line();
  185. /// Kill (cut) the active region
  186. void kill_region();
  187. /// Copy the active region to kill ring (without deleting)
  188. void copy_region_as_kill();
  189. /// Yank (paste) from kill ring
  190. void yank();
  191. /// Yank and pop to previous kill ring entry
  192. void yank_pop();
  193. /// Kill word forward
  194. void kill_word();
  195. /// Kill word backward
  196. void backward_kill_word();
  197. // === Theme Management ===
  198. /// Get the theme manager
  199. [[nodiscard]] ThemeManager& theme_manager() noexcept { return theme_manager_; }
  200. [[nodiscard]] const ThemeManager& theme_manager() const noexcept { return theme_manager_; }
  201. /// Set active theme
  202. void set_theme(const std::string& name) { theme_manager_.set_active_theme(name); }
  203. /// Get active theme
  204. [[nodiscard]] std::shared_ptr<Theme> active_theme() const { return theme_manager_.active_theme(); }
  205. // === Configuration ===
  206. /// Get the configuration manager
  207. [[nodiscard]] Config& config() noexcept { return config_; }
  208. [[nodiscard]] const Config& config() const noexcept { return config_; }
  209. // === Key Binding System ===
  210. [[nodiscard]] KeyBindingManager& keybinding_manager() noexcept { return keybinding_manager_; }
  211. [[nodiscard]] const KeyBindingManager& keybinding_manager() const noexcept { return keybinding_manager_; }
  212. // === Lua API ===
  213. [[nodiscard]] LuaApi* lua_api() const { return lua_api_.get(); }
  214. // === Command System ===
  215. [[nodiscard]] CommandSystem& command_system() noexcept { return *command_system_; }
  216. [[nodiscard]] const CommandSystem& command_system() const noexcept { return *command_system_; }
  217. private:
  218. // All open buffers
  219. std::list<std::shared_ptr<Buffer>> buffers_;
  220. // Word movement helpers
  221. Position calculate_forward_word_pos(Position start_pos);
  222. Position calculate_backward_word_pos(Position start_pos);
  223. // Window layout
  224. std::shared_ptr<LayoutNode> root_node_;
  225. std::shared_ptr<Window> active_window_;
  226. std::string last_message_;
  227. std::vector<EventCallback> event_callbacks_;
  228. // Kill ring for cut/copy/paste
  229. KillRing kill_ring_;
  230. // Last yank position (for yank-pop)
  231. std::optional<Position> last_yank_start_;
  232. std::optional<Position> last_yank_end_;
  233. // Registers for storing text (a-z, A-Z, 0-9)
  234. std::unordered_map<char, std::string> registers_;
  235. // Keyboard macros
  236. std::vector<std::string> current_macro_;
  237. std::vector<std::string> last_macro_;
  238. bool recording_macro_ = false;
  239. // Rectangle storage (each string is one row of the rectangle)
  240. std::vector<std::string> rectangle_kill_ring_;
  241. // Theme manager
  242. ThemeManager theme_manager_;
  243. // Configuration
  244. Config config_;
  245. // Key binding system
  246. KeyBindingManager keybinding_manager_;
  247. // Lua API
  248. std::unique_ptr<LuaApi> lua_api_;
  249. // Command System
  250. std::unique_ptr<CommandSystem> command_system_;
  251. void emit_event(EditorEvent event);
  252. // Helper to find a node containing the active window
  253. LayoutNode* find_parent_node(LayoutNode* root, std::shared_ptr<Window> target);
  254. // Helper to collect all windows in traversal order
  255. void collect_windows(LayoutNode* node, std::vector<std::shared_ptr<Window>>& windows);
  256. };
  257. struct LayoutNode {
  258. enum class Type { Leaf, HorizontalSplit, VerticalSplit };
  259. Type type;
  260. // If Leaf
  261. std::shared_ptr<Window> window;
  262. // If Split
  263. std::shared_ptr<LayoutNode> child1;
  264. std::shared_ptr<LayoutNode> child2;
  265. float ratio = 0.5f; // For future resizing
  266. LayoutNode(std::shared_ptr<Window> w) : type(Type::Leaf), window(w) {}
  267. LayoutNode(Type t, std::shared_ptr<LayoutNode> c1, std::shared_ptr<LayoutNode> c2)
  268. : type(t), child1(c1), child2(c2) {}
  269. };
  270. } // namespace lumacs