1// Scintilla source code edit control
2/** @file CellBuffer.h
3 ** Manages the text of the document.
4 **/
5// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
6// The License.txt file describes the conditions under which this software may be distributed.
7
8#ifndef CELLBUFFER_H
9#define CELLBUFFER_H
10
11namespace Scintilla::Internal {
12
13// Interface to per-line data that wants to see each line insertion and deletion
14class PerLine {
15public:
16 virtual ~PerLine() {}
17 virtual void Init()=0;
18 virtual void InsertLine(Sci::Line line)=0;
19 virtual void InsertLines(Sci::Line line, Sci::Line lines) = 0;
20 virtual void RemoveLine(Sci::Line line)=0;
21};
22
23/**
24 * The line vector contains information about each of the lines in a cell buffer.
25 */
26class ILineVector;
27
28enum class ActionType { insert, remove, start, container };
29
30/**
31 * Actions are used to store all the information required to perform one undo/redo step.
32 */
33class Action {
34public:
35 ActionType at;
36 Sci::Position position;
37 std::unique_ptr<char[]> data;
38 Sci::Position lenData;
39 bool mayCoalesce;
40
41 Action() noexcept;
42 // Deleted so Action objects can not be copied.
43 Action(const Action &other) = delete;
44 Action &operator=(const Action &other) = delete;
45 Action &operator=(const Action &&other) = delete;
46 // Move constructor allows vector to be resized without reallocating.
47 Action(Action &&other) noexcept = default;
48 ~Action();
49 void Create(ActionType at_, Sci::Position position_=0, const char *data_=nullptr, Sci::Position lenData_=0, bool mayCoalesce_=true);
50 void Clear() noexcept;
51};
52
53/**
54 *
55 */
56class UndoHistory {
57 std::vector<Action> actions;
58 int maxAction;
59 int currentAction;
60 int undoSequenceDepth;
61 int savePoint;
62 int tentativePoint;
63
64 void EnsureUndoRoom();
65
66public:
67 UndoHistory();
68 // Deleted so UndoHistory objects can not be copied.
69 UndoHistory(const UndoHistory &) = delete;
70 UndoHistory(UndoHistory &&) = delete;
71 void operator=(const UndoHistory &) = delete;
72 void operator=(UndoHistory &&) = delete;
73 ~UndoHistory();
74
75 const char *AppendAction(ActionType at, Sci::Position position, const char *data, Sci::Position lengthData, bool &startSequence, bool mayCoalesce=true);
76
77 void BeginUndoAction();
78 void EndUndoAction();
79 void DropUndoSequence();
80 void DeleteUndoHistory();
81
82 /// The save point is a marker in the undo stack where the container has stated that
83 /// the buffer was saved. Undo and redo can move over the save point.
84 void SetSavePoint() noexcept;
85 bool IsSavePoint() const noexcept;
86
87 // Tentative actions are used for input composition so that it can be undone cleanly
88 void TentativeStart();
89 void TentativeCommit();
90 bool TentativeActive() const noexcept;
91 int TentativeSteps() noexcept;
92
93 /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
94 /// called that many times. Similarly for redo.
95 bool CanUndo() const noexcept;
96 int StartUndo();
97 const Action &GetUndoStep() const;
98 void CompletedUndoStep();
99 bool CanRedo() const noexcept;
100 int StartRedo();
101 const Action &GetRedoStep() const;
102 void CompletedRedoStep();
103};
104
105struct SplitView {
106 const char *segment1 = nullptr;
107 size_t length1 = 0;
108 const char *segment2 = nullptr;
109 size_t length = 0;
110
111 bool operator==(const SplitView &other) const noexcept {
112 return segment1 == other.segment1 && length1 == other.length1 &&
113 segment2 == other.segment2 && length == other.length;
114 }
115 bool operator!=(const SplitView &other) const noexcept {
116 return !(*this == other);
117 }
118
119 char CharAt(size_t position) const noexcept {
120 if (position < length1) {
121 return segment1[position];
122 }
123 if (position < length) {
124 return segment2[position];
125 }
126 return 0;
127 }
128};
129
130
131/**
132 * Holder for an expandable array of characters that supports undo and line markers.
133 * Based on article "Data Structures in a Bit-Mapped Text Editor"
134 * by Wilfred J. Hansen, Byte January 1987, page 183.
135 */
136class CellBuffer {
137private:
138 bool hasStyles;
139 bool largeDocument;
140 SplitVector<char> substance;
141 SplitVector<char> style;
142 bool readOnly;
143 bool utf8Substance;
144 Scintilla::LineEndType utf8LineEnds;
145
146 bool collectingUndo;
147 UndoHistory uh;
148
149 std::unique_ptr<ILineVector> plv;
150
151 bool UTF8LineEndOverlaps(Sci::Position position) const noexcept;
152 bool UTF8IsCharacterBoundary(Sci::Position position) const;
153 void ResetLineEnds();
154 void RecalculateIndexLineStarts(Sci::Line lineFirst, Sci::Line lineLast);
155 bool MaintainingLineCharacterIndex() const noexcept;
156 /// Actions without undo
157 void BasicInsertString(Sci::Position position, const char *s, Sci::Position insertLength);
158 void BasicDeleteChars(Sci::Position position, Sci::Position deleteLength);
159
160public:
161
162 CellBuffer(bool hasStyles_, bool largeDocument_);
163 // Deleted so CellBuffer objects can not be copied.
164 CellBuffer(const CellBuffer &) = delete;
165 CellBuffer(CellBuffer &&) = delete;
166 void operator=(const CellBuffer &) = delete;
167 void operator=(CellBuffer &&) = delete;
168 ~CellBuffer();
169
170 /// Retrieving positions outside the range of the buffer works and returns 0
171 char CharAt(Sci::Position position) const noexcept;
172 unsigned char UCharAt(Sci::Position position) const noexcept;
173 void GetCharRange(char *buffer, Sci::Position position, Sci::Position lengthRetrieve) const;
174 char StyleAt(Sci::Position position) const noexcept;
175 void GetStyleRange(unsigned char *buffer, Sci::Position position, Sci::Position lengthRetrieve) const;
176 const char *BufferPointer();
177 const char *RangePointer(Sci::Position position, Sci::Position rangeLength) noexcept;
178 Sci::Position GapPosition() const noexcept;
179 SplitView AllView() const noexcept;
180
181 Sci::Position Length() const noexcept;
182 void Allocate(Sci::Position newSize);
183 void SetUTF8Substance(bool utf8Substance_) noexcept;
184 Scintilla::LineEndType GetLineEndTypes() const noexcept { return utf8LineEnds; }
185 void SetLineEndTypes(Scintilla::LineEndType utf8LineEnds_);
186 bool ContainsLineEnd(const char *s, Sci::Position length) const noexcept;
187 void SetPerLine(PerLine *pl) noexcept;
188 Scintilla::LineCharacterIndexType LineCharacterIndex() const noexcept;
189 void AllocateLineCharacterIndex(Scintilla::LineCharacterIndexType lineCharacterIndex);
190 void ReleaseLineCharacterIndex(Scintilla::LineCharacterIndexType lineCharacterIndex);
191 Sci::Line Lines() const noexcept;
192 void AllocateLines(Sci::Line lines);
193 Sci::Position LineStart(Sci::Line line) const noexcept;
194 Sci::Position IndexLineStart(Sci::Line line, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept;
195 Sci::Line LineFromPosition(Sci::Position pos) const noexcept;
196 Sci::Line LineFromPositionIndex(Sci::Position pos, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept;
197 void InsertLine(Sci::Line line, Sci::Position position, bool lineStart);
198 void RemoveLine(Sci::Line line);
199 const char *InsertString(Sci::Position position, const char *s, Sci::Position insertLength, bool &startSequence);
200
201 /// Setting styles for positions outside the range of the buffer is safe and has no effect.
202 /// @return true if the style of a character is changed.
203 bool SetStyleAt(Sci::Position position, char styleValue) noexcept;
204 bool SetStyleFor(Sci::Position position, Sci::Position lengthStyle, char styleValue) noexcept;
205
206 const char *DeleteChars(Sci::Position position, Sci::Position deleteLength, bool &startSequence);
207
208 bool IsReadOnly() const noexcept;
209 void SetReadOnly(bool set) noexcept;
210 bool IsLarge() const noexcept;
211 bool HasStyles() const noexcept;
212
213 /// The save point is a marker in the undo stack where the container has stated that
214 /// the buffer was saved. Undo and redo can move over the save point.
215 void SetSavePoint();
216 bool IsSavePoint() const noexcept;
217
218 void TentativeStart();
219 void TentativeCommit();
220 bool TentativeActive() const noexcept;
221 int TentativeSteps() noexcept;
222
223 bool SetUndoCollection(bool collectUndo);
224 bool IsCollectingUndo() const noexcept;
225 void BeginUndoAction();
226 void EndUndoAction();
227 void AddUndoAction(Sci::Position token, bool mayCoalesce);
228 void DeleteUndoHistory();
229
230 /// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
231 /// called that many times. Similarly for redo.
232 bool CanUndo() const noexcept;
233 int StartUndo();
234 const Action &GetUndoStep() const;
235 void PerformUndoStep();
236 bool CanRedo() const noexcept;
237 int StartRedo();
238 const Action &GetRedoStep() const;
239 void PerformRedoStep();
240};
241
242}
243
244#endif
245