#pragma once #include #include #include #include #include #include namespace lumacs { /// Represents a cursor position in a buffer struct Position { size_t line; size_t column; auto operator<=>(const Position&) const = default; }; /// Represents a range in the buffer struct Range { Position start; Position end; auto operator<=>(const Range&) const = default; }; /// Buffer events for hooks/callbacks enum class BufferEvent { // Lifecycle events Created, // Buffer was created Loaded, // File was loaded into buffer Closed, // Buffer is being closed // Modification events BeforeChange, // About to modify buffer (can be used to save state for undo) AfterChange, // Buffer content was modified LineChanged, // Specific line was modified // File operations BeforeSave, // About to save AfterSave, // File was saved // Language/mode LanguageChanged // Buffer language/mode changed }; /// Event data passed to callbacks struct BufferEventData { BufferEvent event; size_t line = 0; // Line number for LineChanged events std::string language = ""; // For LanguageChanged events }; /// Text styling attributes for syntax highlighting struct TextAttribute { enum class Style { Normal = 0, Bold = 1, Italic = 2, Underline = 4, // Can combine with bitwise OR }; // Common semantic colors for syntax highlighting enum class ColorType { Default, Keyword, // if, for, while, etc. String, // String literals Comment, // Comments Function, // Function names Type, // Type names, classes Number, // Numeric literals Operator, // +, -, *, etc. Variable, // Variable names Constant, // Constants, enums Error, // Error highlighting }; ColorType color = ColorType::Default; int style_flags = 0; // Combination of Style flags TextAttribute() = default; TextAttribute(ColorType c, int s = 0) : color(c), style_flags(s) {} }; /// A range with associated styling struct StyledRange { Range range; TextAttribute attr; StyledRange() = default; StyledRange(Range r, TextAttribute a) : range(r), attr(a) {} }; /// Undo/Redo state snapshot struct UndoState { std::vector lines; Position cursor; UndoState() = default; UndoState(const std::vector& l, Position c) : lines(l), cursor(c) {} }; /// A text buffer that manages the content of a file or scratch buffer class Buffer { public: /// Create an empty buffer Buffer(); /// Create a buffer with a name (for scratch buffers) explicit Buffer(std::string name); /// Create a buffer from a file static std::optional from_file(const std::filesystem::path& path); // Disable copy, allow move Buffer(const Buffer&) = delete; Buffer& operator=(const Buffer&) = delete; Buffer(Buffer&&) noexcept = default; Buffer& operator=(Buffer&&) noexcept = default; ~Buffer() = default; // === Content Access === /// Get the number of lines in the buffer [[nodiscard]] size_t line_count() const noexcept; /// Get a line by index (0-based) [[nodiscard]] const std::string& line(size_t index) const; /// Get all lines [[nodiscard]] const std::vector& lines() const noexcept; /// Get the entire buffer content as a single string [[nodiscard]] std::string content() const; // === Modification === /// Insert text at a position void insert(Position pos, std::string_view text); /// Insert a character at a position void insert_char(Position pos, char c); /// Insert a newline at a position void insert_newline(Position pos); /// Delete a range of text void erase(Range range); /// Delete a character at a position (backspace) void erase_char(Position pos); /// Replace text in a range void replace(Range range, std::string_view text); /// Find text starting from a position [[nodiscard]] std::optional find(const std::string& query, Position start_pos) const; /// Clear the entire buffer void clear(); // === File Operations === /// Save the buffer to its associated file bool save(); /// Save the buffer to a specific file bool save_as(const std::filesystem::path& path); /// Check if the buffer has been modified since last save [[nodiscard]] bool is_modified() const noexcept; /// Get the file path associated with this buffer (if any) [[nodiscard]] std::optional file_path() const noexcept; // === Buffer Properties === /// Get the buffer name [[nodiscard]] const std::string& name() const noexcept; /// Set the buffer name void set_name(std::string name); /// Check if position is valid [[nodiscard]] bool is_valid_position(Position pos) const noexcept; /// Clamp a position to valid bounds [[nodiscard]] Position clamp_position(Position pos) const noexcept; // === Syntax Highlighting / Styling === /// Set styling for a range of text void set_style(Range range, TextAttribute attr); /// Get all styled ranges for a specific line [[nodiscard]] const std::vector& get_line_styles(size_t line) const; /// Clear all styling information void clear_styles(); /// Clear styling for a specific line void clear_line_styles(size_t line); // === Events & Hooks === using BufferEventCallback = std::function; /// Register a callback for buffer events void on_buffer_event(BufferEventCallback callback); /// Get the language/file type of this buffer [[nodiscard]] const std::string& language() const noexcept { return language_; } /// Set the language/file type (triggers LanguageChanged event) void set_language(std::string lang); /// Auto-detect language from file path static std::string detect_language(const std::filesystem::path& path); // === Undo/Redo === /// Undo the last change bool undo(Position& out_cursor); /// Redo the last undone change bool redo(Position& out_cursor); /// Check if undo is available [[nodiscard]] bool can_undo() const noexcept { return !undo_stack_.empty(); } /// Check if redo is available [[nodiscard]] bool can_redo() const noexcept { return !redo_stack_.empty(); } /// Save current state to undo stack (called automatically before changes) void save_undo_state(Position cursor); /// Clear redo stack (called when new change happens) void clear_redo_stack(); private: std::string name_; std::vector lines_; std::optional file_path_; bool modified_; std::string language_; // Styling information: one vector of styled ranges per line std::vector> line_styles_; // Event callbacks std::vector event_callbacks_; // Undo/Redo stacks std::vector undo_stack_; std::vector redo_stack_; static constexpr size_t MAX_UNDO_LEVELS = 100; bool in_undo_redo_ = false; // Prevent saving state during undo/redo /// Ensure the buffer has at least one line void ensure_min_lines(); /// Mark the buffer as modified void mark_modified(); /// Ensure styles vector matches lines vector size void ensure_styles_size(); /// Emit a buffer event to all registered callbacks void emit_event(BufferEvent event, size_t line = 0); }; } // namespace lumacs