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 | |
11 | namespace Scintilla::Internal { |
12 | |
13 | // Interface to per-line data that wants to see each line insertion and deletion |
14 | class PerLine { |
15 | public: |
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 | */ |
26 | class ILineVector; |
27 | |
28 | enum 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 | */ |
33 | class Action { |
34 | public: |
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 | */ |
56 | class 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 | |
66 | public: |
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 | |
105 | struct 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 | */ |
136 | class CellBuffer { |
137 | private: |
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 | |
160 | public: |
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 | |