kill_ring_manager.hpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. #pragma once
  2. #include <string>
  3. #include <deque>
  4. #include <optional>
  5. #include "lumacs/buffer.hpp" // For Position and Range
  6. namespace lumacs {
  7. /// @brief Implements an Emacs-like kill ring (clipboard history).
  8. /// The kill ring stores killed (cut) text in a circular buffer.
  9. /// Also tracks yank position state for yank-pop functionality.
  10. class KillRingManager {
  11. public:
  12. explicit KillRingManager(size_t max_size = 60);
  13. /// @brief Pushes text onto the kill ring. If the last entry was also a kill
  14. /// (not a yank), it appends to that entry. Otherwise, it creates a new entry.
  15. /// @param text The text to push.
  16. void push(const std::string& text);
  17. /// @brief Retrieves the current (most recently pushed) entry in the kill ring.
  18. /// @return The current entry. Returns empty string if ring is empty.
  19. [[nodiscard]] std::string current() const;
  20. /// @brief Rotates the kill ring and retrieves the previous entry.
  21. /// Used for `yank-pop`.
  22. /// @return The previous entry. Returns empty string if ring is empty.
  23. [[nodiscard]] std::string previous();
  24. /// @brief Checks if the kill ring is empty.
  25. [[nodiscard]] bool empty() const { return ring_.empty(); }
  26. /// @brief Clears the kill ring.
  27. void clear() { ring_.clear(); }
  28. // === Yank State Tracking ===
  29. /// @brief Record the start and end positions of a yank operation.
  30. /// @param start The position where the yank started.
  31. /// @param end The position where the yank ended.
  32. void set_yank_range(Position start, Position end);
  33. /// @brief Get the yank start position if a yank was performed.
  34. [[nodiscard]] std::optional<Position> yank_start() const { return last_yank_start_; }
  35. /// @brief Get the yank end position if a yank was performed.
  36. [[nodiscard]] std::optional<Position> yank_end() const { return last_yank_end_; }
  37. /// @brief Update just the yank end position (after yank-pop replaces text).
  38. void set_yank_end(Position end) { last_yank_end_ = end; }
  39. /// @brief Check if a yank operation has been recorded.
  40. [[nodiscard]] bool has_yank_state() const {
  41. return last_yank_start_.has_value() && last_yank_end_.has_value();
  42. }
  43. /// @brief Clear the yank state (e.g., after a non-yank command).
  44. void clear_yank_state() {
  45. last_yank_start_.reset();
  46. last_yank_end_.reset();
  47. }
  48. private:
  49. std::deque<std::string> ring_;
  50. size_t max_size_;
  51. bool last_action_was_kill_ = false; // Tracks if the last push was a kill or append
  52. // Yank position tracking (moved from EditorCore)
  53. std::optional<Position> last_yank_start_;
  54. std::optional<Position> last_yank_end_;
  55. };
  56. } // namespace lumacs