1 /** @file RunStyles.cxx
2  ** Data structure used to store sparse styles.
3  **/
4 // Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
5 // The License.txt file describes the conditions under which this software may be distributed.
6 
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 
12 #include "Platform.h"
13 
14 #include "Scintilla.h"
15 #include "SplitVector.h"
16 #include "Partitioning.h"
17 #include "RunStyles.h"
18 
19 #ifdef SCI_NAMESPACE
20 using namespace Scintilla;
21 #endif
22 
23 // Find the first run at a position
RunFromPosition(int position) const24 int RunStyles::RunFromPosition(int position) const {
25 	int run = starts->PartitionFromPosition(position);
26 	// Go to first element with this position
27 	while ((run > 0) && (position == starts->PositionFromPartition(run-1))) {
28 		run--;
29 	}
30 	return run;
31 }
32 
33 // If there is no run boundary at position, insert one continuing style.
SplitRun(int position)34 int RunStyles::SplitRun(int position) {
35 	int run = RunFromPosition(position);
36 	int posRun = starts->PositionFromPartition(run);
37 	if (posRun < position) {
38 		int runStyle = ValueAt(position);
39 		run++;
40 		starts->InsertPartition(run, position);
41 		styles->InsertValue(run, 1, runStyle);
42 	}
43 	return run;
44 }
45 
RemoveRun(int run)46 void RunStyles::RemoveRun(int run) {
47 	starts->RemovePartition(run);
48 	styles->DeleteRange(run, 1);
49 }
50 
RemoveRunIfEmpty(int run)51 void RunStyles::RemoveRunIfEmpty(int run) {
52 	if ((run < starts->Partitions()) && (starts->Partitions() > 1)) {
53 		if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) {
54 			RemoveRun(run);
55 		}
56 	}
57 }
58 
RemoveRunIfSameAsPrevious(int run)59 void RunStyles::RemoveRunIfSameAsPrevious(int run) {
60 	if ((run > 0) && (run < starts->Partitions())) {
61 		if (styles->ValueAt(run-1) == styles->ValueAt(run)) {
62 			RemoveRun(run);
63 		}
64 	}
65 }
66 
RunStyles()67 RunStyles::RunStyles() {
68 	starts = new Partitioning(8);
69 	styles = new SplitVector<int>();
70 	styles->InsertValue(0, 2, 0);
71 }
72 
~RunStyles()73 RunStyles::~RunStyles() {
74 	delete starts;
75 	starts = NULL;
76 	delete styles;
77 	styles = NULL;
78 }
79 
Length() const80 int RunStyles::Length() const {
81 	return starts->PositionFromPartition(starts->Partitions());
82 }
83 
ValueAt(int position) const84 int RunStyles::ValueAt(int position) const {
85 	return styles->ValueAt(starts->PartitionFromPosition(position));
86 }
87 
FindNextChange(int position,int end)88 int RunStyles::FindNextChange(int position, int end) {
89 	int run = starts->PartitionFromPosition(position);
90 	if (run < starts->Partitions()) {
91 		int runChange = starts->PositionFromPartition(run);
92 		if (runChange > position)
93 			return runChange;
94 		int nextChange = starts->PositionFromPartition(run + 1);
95 		if (nextChange > position) {
96 			return nextChange;
97 		} else if (position < end) {
98 			return end;
99 		} else {
100 			return end + 1;
101 		}
102 	} else {
103 		return end + 1;
104 	}
105 }
106 
StartRun(int position)107 int RunStyles::StartRun(int position) {
108 	return starts->PositionFromPartition(starts->PartitionFromPosition(position));
109 }
110 
EndRun(int position)111 int RunStyles::EndRun(int position) {
112 	return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1);
113 }
114 
FillRange(int & position,int value,int & fillLength)115 bool RunStyles::FillRange(int &position, int value, int &fillLength) {
116 	int end = position + fillLength;
117 	int runEnd = RunFromPosition(end);
118 	if (styles->ValueAt(runEnd) == value) {
119 		// End already has value so trim range.
120 		end = starts->PositionFromPartition(runEnd);
121 		if (position >= end) {
122 			// Whole range is already same as value so no action
123 			return false;
124 		}
125 		fillLength = end - position;
126 	} else {
127 		runEnd = SplitRun(end);
128 	}
129 	int runStart = RunFromPosition(position);
130 	if (styles->ValueAt(runStart) == value) {
131 		// Start is in expected value so trim range.
132 		runStart++;
133 		position = starts->PositionFromPartition(runStart);
134 		fillLength = end - position;
135 	} else {
136 		if (starts->PositionFromPartition(runStart) < position) {
137 			runStart = SplitRun(position);
138 			runEnd++;
139 		}
140 	}
141 	if (runStart < runEnd) {
142 		styles->SetValueAt(runStart, value);
143 		// Remove each old run over the range
144 		for (int run=runStart+1; run<runEnd; run++) {
145 			RemoveRun(runStart+1);
146 		}
147 		runEnd = RunFromPosition(end);
148 		RemoveRunIfSameAsPrevious(runEnd);
149 		RemoveRunIfSameAsPrevious(runStart);
150 		runEnd = RunFromPosition(end);
151 		RemoveRunIfEmpty(runEnd);
152 		return true;
153 	} else {
154 		return false;
155 	}
156 }
157 
SetValueAt(int position,int value)158 void RunStyles::SetValueAt(int position, int value) {
159 	int len = 1;
160 	FillRange(position, value, len);
161 }
162 
InsertSpace(int position,int insertLength)163 void RunStyles::InsertSpace(int position, int insertLength) {
164 	int runStart = RunFromPosition(position);
165 	if (starts->PositionFromPartition(runStart) == position) {
166 		int runStyle = ValueAt(position);
167 		// Inserting at start of run so make previous longer
168 		if (runStart == 0) {
169 			// Inserting at start of document so ensure 0
170 			if (runStyle) {
171 				styles->SetValueAt(0, 0);
172 				starts->InsertPartition(1, 0);
173 				styles->InsertValue(1, 1, runStyle);
174 				starts->InsertText(0, insertLength);
175 			} else {
176 				starts->InsertText(runStart, insertLength);
177 			}
178 		} else {
179 			if (runStyle) {
180 				starts->InsertText(runStart-1, insertLength);
181 			} else {
182 				// Insert at end of run so do not extend style
183 				starts->InsertText(runStart, insertLength);
184 			}
185 		}
186 	} else {
187 		starts->InsertText(runStart, insertLength);
188 	}
189 }
190 
DeleteAll()191 void RunStyles::DeleteAll() {
192 	delete starts;
193 	starts = NULL;
194 	delete styles;
195 	styles = NULL;
196 	starts = new Partitioning(8);
197 	styles = new SplitVector<int>();
198 	styles->InsertValue(0, 2, 0);
199 }
200 
DeleteRange(int position,int deleteLength)201 void RunStyles::DeleteRange(int position, int deleteLength) {
202 	int end = position + deleteLength;
203 	int runStart = RunFromPosition(position);
204 	int runEnd = RunFromPosition(end);
205 	if (runStart == runEnd) {
206 		// Deleting from inside one run
207 		starts->InsertText(runStart, -deleteLength);
208 	} else {
209 		runStart = SplitRun(position);
210 		runEnd = SplitRun(end);
211 		starts->InsertText(runStart, -deleteLength);
212 		// Remove each old run over the range
213 		for (int run=runStart; run<runEnd; run++) {
214 			RemoveRun(runStart);
215 		}
216 		RemoveRunIfEmpty(runStart);
217 		RemoveRunIfSameAsPrevious(runStart);
218 	}
219 }
220 
Runs() const221 int RunStyles::Runs() const {
222 	return starts->Partitions();
223 }
224 
AllSame() const225 bool RunStyles::AllSame() const {
226 	for (int run = 1; run < starts->Partitions(); run++) {
227 		if (styles->ValueAt(run) != styles->ValueAt(run - 1))
228 			return false;
229 	}
230 	return true;
231 }
232 
AllSameAs(int value) const233 bool RunStyles::AllSameAs(int value) const {
234 	return AllSame() && (styles->ValueAt(0) == value);
235 }
236 
Find(int value,int start) const237 int RunStyles::Find(int value, int start) const {
238 	if (start < Length()) {
239 		int run = start ? RunFromPosition(start) : 0;
240 		if (styles->ValueAt(run) == value)
241 			return start;
242 		run++;
243 		while (run < starts->Partitions()) {
244 			if (styles->ValueAt(run) == value)
245 				return starts->PositionFromPartition(run);
246 			run++;
247 		}
248 	}
249 	return -1;
250 }
251