summaryrefslogtreecommitdiffstats
path: root/src/CellBuffer.h
blob: bb81fd5722d3784d697a1705140183bbaf1505a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
// Scintilla source code edit control
/** @file CellBuffer.h
 ** Manages the text of the document.
 **/
// Copyright 1998-2004 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#ifndef CELLBUFFER_H
#define CELLBUFFER_H

/**
 * This holds the marker identifier and the marker type to display.
 * MarkerHandleNumbers are members of lists.
 */
struct MarkerHandleNumber {
	int handle;
	int number;
	MarkerHandleNumber *next;
};

/**
 * A marker handle set contains any number of MarkerHandleNumbers.
 */
class MarkerHandleSet {
	MarkerHandleNumber *root;

public:
	MarkerHandleSet();
	~MarkerHandleSet();
	int Length();
	int NumberFromHandle(int handle);
	int MarkValue();	///< Bit set of marker numbers.
	bool Contains(int handle);
	bool InsertHandle(int handle, int markerNum);
	void RemoveHandle(int handle);
	bool RemoveNumber(int markerNum);
	void CombineWith(MarkerHandleSet *other);
};

/**
 * Each line stores the starting position of the first character of the line in the cell buffer
 * and potentially a marker handle set. Often a line will not have any attached markers.
 */
struct LineData {
	int startPosition;
	MarkerHandleSet *handleSet;
	LineData() : startPosition(0), handleSet(0) {
	}
};

/**
 * The line vector contains information about each of the lines in a cell buffer.
 */
class LineVector {
public:
	int growSize;
	int lines;
	LineData *linesData;
	int size;
	int *levels;
	int sizeLevels;

	/// Handles are allocated sequentially and should never have to be reused as 32 bit ints are very big.
	int handleCurrent;

	LineVector();
	~LineVector();
	void Init();

	void Expand(int sizeNew);
	void ExpandLevels(int sizeNew=-1);
	void ClearLevels();
	void InsertValue(int pos, int value);
	void SetValue(int pos, int value);
	void Remove(int pos);
	int LineFromPosition(int pos);

	int AddMark(int line, int marker);
	void MergeMarkers(int pos);
	void DeleteMark(int line, int markerNum, bool all);
	void DeleteMarkFromHandle(int markerHandle);
	int LineFromHandle(int markerHandle);
};

enum actionType { insertAction, removeAction, startAction };

/**
 * Actions are used to store all the information required to perform one undo/redo step.
 */
class Action {
public:
	actionType at;
	int position;
	char *data;
	int lenData;
	bool mayCoalesce;

	Action();
	~Action();
	void Create(actionType at_, int position_=0, char *data_=0, int lenData_=0, bool mayCoalesce_=true);
	void Destroy();
	void Grab(Action *source);
};

/**
 *
 */
class UndoHistory {
	Action *actions;
	int lenActions;
	int maxAction;
	int currentAction;
	int undoSequenceDepth;
	int savePoint;

	void EnsureUndoRoom();

public:
	UndoHistory();
	~UndoHistory();

	void AppendAction(actionType at, int position, char *data, int length);

	void BeginUndoAction();
	void EndUndoAction();
	void DropUndoSequence();
	void DeleteUndoHistory();

	/// The save point is a marker in the undo stack where the container has stated that
	/// the buffer was saved. Undo and redo can move over the save point.
	void SetSavePoint();
	bool IsSavePoint() const;

	/// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
	/// called that many times. Similarly for redo.
	bool CanUndo() const;
	int StartUndo();
	const Action &GetUndoStep() const;
	void CompletedUndoStep();
	bool CanRedo() const;
	int StartRedo();
	const Action &GetRedoStep() const;
	void CompletedRedoStep();
};

/**
 * Holder for an expandable array of characters that supports undo and line markers.
 * Based on article "Data Structures in a Bit-Mapped Text Editor"
 * by Wilfred J. Hansen, Byte January 1987, page 183.
 */
class CellBuffer {
private:
	char *body;		///< The cell buffer itself.
	int size;		///< Allocated size of the buffer.
	int length;		///< Total length of the data.
	int part1len;	///< Length of the first part.
	int gaplen;		///< Length of the gap between the two parts.
	char *part2body;	///< The second part of the cell buffer.
						///< Doesn't point after the gap but set so that
						///< part2body[position] is consistent with body[position].
	bool readOnly;
	int growSize;

	bool collectingUndo;
	UndoHistory uh;

	LineVector lv;

	SVector lineStates;

	void GapTo(int position);
	void RoomFor(int insertionLength);

	inline char ByteAt(int position);
	void SetByteAt(int position, char ch);

public:

	CellBuffer(int initialLength = 4000);
	~CellBuffer();

	/// Retrieving positions outside the range of the buffer works and returns 0
	char CharAt(int position);
	void GetCharRange(char *buffer, int position, int lengthRetrieve);
	char StyleAt(int position);

	int ByteLength();
	int Length();
	void Allocate(int newSize);
	int Lines();
	int LineStart(int line);
	int LineFromPosition(int pos) { return lv.LineFromPosition(pos); }
	const char *InsertString(int position, char *s, int insertLength);

	/// Setting styles for positions outside the range of the buffer is safe and has no effect.
	/// @return true if the style of a character is changed.
	bool SetStyleAt(int position, char style, char mask='\377');
	bool SetStyleFor(int position, int length, char style, char mask);

	const char *DeleteChars(int position, int deleteLength);

	bool IsReadOnly();
	void SetReadOnly(bool set);

	/// The save point is a marker in the undo stack where the container has stated that
	/// the buffer was saved. Undo and redo can move over the save point.
	void SetSavePoint();
	bool IsSavePoint();

	/// Line marker functions
	int AddMark(int line, int markerNum);
	void DeleteMark(int line, int markerNum);
	void DeleteMarkFromHandle(int markerHandle);
	int GetMark(int line);
	void DeleteAllMarks(int markerNum);
	int LineFromHandle(int markerHandle);

	/// Actions without undo
	void BasicInsertString(int position, char *s, int insertLength);
	void BasicDeleteChars(int position, int deleteLength);

	bool SetUndoCollection(bool collectUndo);
	bool IsCollectingUndo();
	void BeginUndoAction();
	void EndUndoAction();
	void DeleteUndoHistory();

	/// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
	/// called that many times. Similarly for redo.
	bool CanUndo();
	int StartUndo();
	const Action &GetUndoStep() const;
	void PerformUndoStep();
	bool CanRedo();
	int StartRedo();
	const Action &GetRedoStep() const;
	void PerformRedoStep();

	int SetLineState(int line, int state);
	int GetLineState(int line);
	int GetMaxLineState();

	int SetLevel(int line, int level);
	int GetLevel(int line);
	void ClearLevels();
};

#define CELL_SIZE	2

#endif