buffer.hpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #pragma once
  2. #include <string>
  3. #include <vector>
  4. #include <optional>
  5. #include <filesystem>
  6. #include <memory>
  7. namespace lumacs {
  8. /// Represents a cursor position in a buffer
  9. struct Position {
  10. size_t line;
  11. size_t column;
  12. auto operator<=>(const Position&) const = default;
  13. };
  14. /// Represents a range in the buffer
  15. struct Range {
  16. Position start;
  17. Position end;
  18. auto operator<=>(const Range&) const = default;
  19. };
  20. /// Buffer events for hooks/callbacks
  21. enum class BufferEvent {
  22. // Lifecycle events
  23. Created, // Buffer was created
  24. Loaded, // File was loaded into buffer
  25. Closed, // Buffer is being closed
  26. // Modification events
  27. BeforeChange, // About to modify buffer (can be used to save state for undo)
  28. AfterChange, // Buffer content was modified
  29. LineChanged, // Specific line was modified
  30. // File operations
  31. BeforeSave, // About to save
  32. AfterSave, // File was saved
  33. // Language/mode
  34. LanguageChanged // Buffer language/mode changed
  35. };
  36. /// Event data passed to callbacks
  37. struct BufferEventData {
  38. BufferEvent event;
  39. size_t line = 0; // Line number for LineChanged events
  40. std::string language = ""; // For LanguageChanged events
  41. };
  42. /// Text styling attributes for syntax highlighting
  43. struct TextAttribute {
  44. enum class Style {
  45. Normal = 0,
  46. Bold = 1,
  47. Italic = 2,
  48. Underline = 4,
  49. // Can combine with bitwise OR
  50. };
  51. // Common semantic colors for syntax highlighting
  52. enum class ColorType {
  53. Default,
  54. Keyword, // if, for, while, etc.
  55. String, // String literals
  56. Comment, // Comments
  57. Function, // Function names
  58. Type, // Type names, classes
  59. Number, // Numeric literals
  60. Operator, // +, -, *, etc.
  61. Variable, // Variable names
  62. Constant, // Constants, enums
  63. Error, // Error highlighting
  64. };
  65. ColorType color = ColorType::Default;
  66. int style_flags = 0; // Combination of Style flags
  67. TextAttribute() = default;
  68. TextAttribute(ColorType c, int s = 0) : color(c), style_flags(s) {}
  69. };
  70. /// A range with associated styling
  71. struct StyledRange {
  72. Range range;
  73. TextAttribute attr;
  74. StyledRange() = default;
  75. StyledRange(Range r, TextAttribute a) : range(r), attr(a) {}
  76. };
  77. /// Undo/Redo state snapshot
  78. struct UndoState {
  79. std::vector<std::string> lines;
  80. Position cursor;
  81. UndoState() = default;
  82. UndoState(const std::vector<std::string>& l, Position c) : lines(l), cursor(c) {}
  83. };
  84. /// A text buffer that manages the content of a file or scratch buffer
  85. class Buffer {
  86. public:
  87. /// Create an empty buffer
  88. Buffer();
  89. /// Create a buffer with a name (for scratch buffers)
  90. explicit Buffer(std::string name);
  91. /// Create a buffer from a file
  92. static std::optional<Buffer> from_file(const std::filesystem::path& path);
  93. // Disable copy, allow move
  94. Buffer(const Buffer&) = delete;
  95. Buffer& operator=(const Buffer&) = delete;
  96. Buffer(Buffer&&) noexcept = default;
  97. Buffer& operator=(Buffer&&) noexcept = default;
  98. ~Buffer() = default;
  99. // === Content Access ===
  100. /// Get the number of lines in the buffer
  101. [[nodiscard]] size_t line_count() const noexcept;
  102. /// Get a line by index (0-based)
  103. [[nodiscard]] const std::string& line(size_t index) const;
  104. /// Get all lines
  105. [[nodiscard]] const std::vector<std::string>& lines() const noexcept;
  106. /// Get the entire buffer content as a single string
  107. [[nodiscard]] std::string content() const;
  108. // === Modification ===
  109. /// Insert text at a position
  110. void insert(Position pos, std::string_view text);
  111. /// Insert a character at a position
  112. void insert_char(Position pos, char c);
  113. /// Insert a newline at a position
  114. void insert_newline(Position pos);
  115. /// Delete a range of text
  116. void erase(Range range);
  117. /// Delete a character at a position (backspace)
  118. void erase_char(Position pos);
  119. /// Replace text in a range
  120. void replace(Range range, std::string_view text);
  121. /// Find text starting from a position
  122. [[nodiscard]] std::optional<Range> find(const std::string& query, Position start_pos) const;
  123. /// Clear the entire buffer
  124. void clear();
  125. // === File Operations ===
  126. /// Save the buffer to its associated file
  127. bool save();
  128. /// Save the buffer to a specific file
  129. bool save_as(const std::filesystem::path& path);
  130. /// Check if the buffer has been modified since last save
  131. [[nodiscard]] bool is_modified() const noexcept;
  132. /// Get the file path associated with this buffer (if any)
  133. [[nodiscard]] std::optional<std::filesystem::path> file_path() const noexcept;
  134. // === Buffer Properties ===
  135. /// Get the buffer name
  136. [[nodiscard]] const std::string& name() const noexcept;
  137. /// Set the buffer name
  138. void set_name(std::string name);
  139. /// Check if position is valid
  140. [[nodiscard]] bool is_valid_position(Position pos) const noexcept;
  141. /// Clamp a position to valid bounds
  142. [[nodiscard]] Position clamp_position(Position pos) const noexcept;
  143. // === Syntax Highlighting / Styling ===
  144. /// Set styling for a range of text
  145. void set_style(Range range, TextAttribute attr);
  146. /// Get all styled ranges for a specific line
  147. [[nodiscard]] const std::vector<StyledRange>& get_line_styles(size_t line) const;
  148. /// Clear all styling information
  149. void clear_styles();
  150. /// Clear styling for a specific line
  151. void clear_line_styles(size_t line);
  152. // === Events & Hooks ===
  153. using BufferEventCallback = std::function<void(const BufferEventData&)>;
  154. /// Register a callback for buffer events
  155. void on_buffer_event(BufferEventCallback callback);
  156. /// Get the language/file type of this buffer
  157. [[nodiscard]] const std::string& language() const noexcept { return language_; }
  158. /// Set the language/file type (triggers LanguageChanged event)
  159. void set_language(std::string lang);
  160. /// Auto-detect language from file path
  161. static std::string detect_language(const std::filesystem::path& path);
  162. // === Undo/Redo ===
  163. /// Undo the last change
  164. bool undo(Position& out_cursor);
  165. /// Redo the last undone change
  166. bool redo(Position& out_cursor);
  167. /// Check if undo is available
  168. [[nodiscard]] bool can_undo() const noexcept { return !undo_stack_.empty(); }
  169. /// Check if redo is available
  170. [[nodiscard]] bool can_redo() const noexcept { return !redo_stack_.empty(); }
  171. /// Save current state to undo stack (called automatically before changes)
  172. void save_undo_state(Position cursor);
  173. /// Clear redo stack (called when new change happens)
  174. void clear_redo_stack();
  175. private:
  176. std::string name_;
  177. std::vector<std::string> lines_;
  178. std::optional<std::filesystem::path> file_path_;
  179. bool modified_;
  180. std::string language_;
  181. // Styling information: one vector of styled ranges per line
  182. std::vector<std::vector<StyledRange>> line_styles_;
  183. // Event callbacks
  184. std::vector<BufferEventCallback> event_callbacks_;
  185. // Undo/Redo stacks
  186. std::vector<UndoState> undo_stack_;
  187. std::vector<UndoState> redo_stack_;
  188. static constexpr size_t MAX_UNDO_LEVELS = 100;
  189. bool in_undo_redo_ = false; // Prevent saving state during undo/redo
  190. /// Ensure the buffer has at least one line
  191. void ensure_min_lines();
  192. /// Mark the buffer as modified
  193. void mark_modified();
  194. /// Ensure styles vector matches lines vector size
  195. void ensure_styles_size();
  196. /// Emit a buffer event to all registered callbacks
  197. void emit_event(BufferEvent event, size_t line = 0);
  198. };
  199. } // namespace lumacs