GTextDocument.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #pragma once
  2. #include <AK/Badge.h>
  3. #include <AK/HashTable.h>
  4. #include <AK/NonnullOwnPtrVector.h>
  5. #include <AK/NonnullRefPtr.h>
  6. #include <AK/RefCounted.h>
  7. #include <LibCore/CTimer.h>
  8. #include <LibDraw/Color.h>
  9. #include <LibDraw/Font.h>
  10. #include <LibGUI/GTextRange.h>
  11. #include <LibGUI/GUndoStack.h>
  12. class GTextEditor;
  13. class GTextDocument;
  14. class GTextDocumentLine;
  15. struct GTextDocumentSpan {
  16. GTextRange range;
  17. Color color;
  18. Optional<Color> background_color;
  19. bool is_skippable { false };
  20. const Font* font { nullptr };
  21. void* data { nullptr };
  22. };
  23. class GTextDocumentUndoCommand : public GCommand {
  24. public:
  25. GTextDocumentUndoCommand(GTextDocument&);
  26. virtual ~GTextDocumentUndoCommand();
  27. protected:
  28. GTextDocument& m_document;
  29. };
  30. class InsertTextCommand : public GTextDocumentUndoCommand {
  31. public:
  32. InsertTextCommand(GTextDocument&, const String&, const GTextPosition&);
  33. virtual void undo() override;
  34. virtual void redo() override;
  35. private:
  36. String m_text;
  37. GTextRange m_range;
  38. };
  39. class RemoveTextCommand : public GTextDocumentUndoCommand {
  40. public:
  41. RemoveTextCommand(GTextDocument&, const String&, const GTextRange&);
  42. virtual void undo() override;
  43. virtual void redo() override;
  44. private:
  45. String m_text;
  46. GTextRange m_range;
  47. };
  48. class GTextDocument : public RefCounted<GTextDocument> {
  49. public:
  50. enum class SearchShouldWrap {
  51. No = 0,
  52. Yes
  53. };
  54. class Client {
  55. public:
  56. virtual ~Client();
  57. virtual void document_did_append_line() = 0;
  58. virtual void document_did_insert_line(size_t) = 0;
  59. virtual void document_did_remove_line(size_t) = 0;
  60. virtual void document_did_remove_all_lines() = 0;
  61. virtual void document_did_change() = 0;
  62. virtual void document_did_set_text() = 0;
  63. virtual void document_did_set_cursor(const GTextPosition&) = 0;
  64. };
  65. static NonnullRefPtr<GTextDocument> create(Client* client = nullptr)
  66. {
  67. return adopt(*new GTextDocument(client));
  68. }
  69. size_t line_count() const { return (size_t)m_lines.size(); }
  70. const GTextDocumentLine& line(size_t line_index) const { return m_lines[(int)line_index]; }
  71. GTextDocumentLine& line(size_t line_index) { return m_lines[(int)line_index]; }
  72. void set_spans(const Vector<GTextDocumentSpan>& spans) { m_spans = spans; }
  73. void set_text(const StringView&);
  74. const NonnullOwnPtrVector<GTextDocumentLine>& lines() const { return m_lines; }
  75. NonnullOwnPtrVector<GTextDocumentLine>& lines() { return m_lines; }
  76. bool has_spans() const { return !m_spans.is_empty(); }
  77. const Vector<GTextDocumentSpan>& spans() const { return m_spans; }
  78. void set_span_at_index(size_t index, GTextDocumentSpan span) { m_spans[(int)index] = move(span); }
  79. void append_line(NonnullOwnPtr<GTextDocumentLine>);
  80. void remove_line(size_t line_index);
  81. void remove_all_lines();
  82. void insert_line(size_t line_index, NonnullOwnPtr<GTextDocumentLine>);
  83. void register_client(Client&);
  84. void unregister_client(Client&);
  85. void update_views(Badge<GTextDocumentLine>);
  86. String text_in_range(const GTextRange&) const;
  87. Vector<GTextRange> find_all(const StringView& needle) const;
  88. GTextRange find_next(const StringView&, const GTextPosition& start = {}, SearchShouldWrap = SearchShouldWrap::Yes) const;
  89. GTextRange find_previous(const StringView&, const GTextPosition& start = {}, SearchShouldWrap = SearchShouldWrap::Yes) const;
  90. GTextPosition next_position_after(const GTextPosition&, SearchShouldWrap = SearchShouldWrap::Yes) const;
  91. GTextPosition previous_position_before(const GTextPosition&, SearchShouldWrap = SearchShouldWrap::Yes) const;
  92. char character_at(const GTextPosition&) const;
  93. GTextRange range_for_entire_line(size_t line_index) const;
  94. Optional<GTextDocumentSpan> first_non_skippable_span_before(const GTextPosition&) const;
  95. Optional<GTextDocumentSpan> first_non_skippable_span_after(const GTextPosition&) const;
  96. void add_to_undo_stack(NonnullOwnPtr<GTextDocumentUndoCommand>);
  97. bool can_undo() const { return m_undo_stack.can_undo(); }
  98. bool can_redo() const { return m_undo_stack.can_redo(); }
  99. void undo();
  100. void redo();
  101. void notify_did_change();
  102. void set_all_cursors(const GTextPosition&);
  103. GTextPosition insert_at(const GTextPosition&, char);
  104. GTextPosition insert_at(const GTextPosition&, const StringView&);
  105. void remove(const GTextRange&);
  106. private:
  107. explicit GTextDocument(Client* client);
  108. void update_undo_timer();
  109. NonnullOwnPtrVector<GTextDocumentLine> m_lines;
  110. Vector<GTextDocumentSpan> m_spans;
  111. HashTable<Client*> m_clients;
  112. bool m_client_notifications_enabled { true };
  113. GUndoStack m_undo_stack;
  114. RefPtr<CTimer> m_undo_timer;
  115. };
  116. class GTextDocumentLine {
  117. friend class GTextEditor;
  118. friend class GTextDocument;
  119. public:
  120. explicit GTextDocumentLine(GTextDocument&);
  121. explicit GTextDocumentLine(GTextDocument&, const StringView&);
  122. StringView view() const { return { characters(), (size_t)length() }; }
  123. const char* characters() const { return m_text.data(); }
  124. size_t length() const { return (size_t)m_text.size() - 1; }
  125. void set_text(GTextDocument&, const StringView&);
  126. void append(GTextDocument&, char);
  127. void prepend(GTextDocument&, char);
  128. void insert(GTextDocument&, size_t index, char);
  129. void remove(GTextDocument&, size_t index);
  130. void append(GTextDocument&, const char*, size_t);
  131. void truncate(GTextDocument&, size_t length);
  132. void clear(GTextDocument&);
  133. size_t first_non_whitespace_column() const;
  134. private:
  135. // NOTE: This vector is null terminated.
  136. Vector<char> m_text;
  137. };