1 /** @file RunStyles.cxx
2 ** Data structure used to store sparse styles.
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.
20 #include "Scintilla.h"
22 #include "SplitVector.h"
23 #include "Partitioning.h"
24 #include "RunStyles.h"
27 using namespace Scintilla
;
30 // Find the first run at a position
31 int RunStyles::RunFromPosition(int position
) const {
32 int run
= starts
->PartitionFromPosition(position
);
33 // Go to first element with this position
34 while ((run
> 0) && (position
== starts
->PositionFromPartition(run
-1))) {
40 // If there is no run boundary at position, insert one continuing style.
41 int RunStyles::SplitRun(int position
) {
42 int run
= RunFromPosition(position
);
43 const int posRun
= starts
->PositionFromPartition(run
);
44 if (posRun
< position
) {
45 int runStyle
= ValueAt(position
);
47 starts
->InsertPartition(run
, position
);
48 styles
->InsertValue(run
, 1, runStyle
);
53 void RunStyles::RemoveRun(int run
) {
54 starts
->RemovePartition(run
);
55 styles
->DeleteRange(run
, 1);
58 void RunStyles::RemoveRunIfEmpty(int run
) {
59 if ((run
< starts
->Partitions()) && (starts
->Partitions() > 1)) {
60 if (starts
->PositionFromPartition(run
) == starts
->PositionFromPartition(run
+1)) {
66 void RunStyles::RemoveRunIfSameAsPrevious(int run
) {
67 if ((run
> 0) && (run
< starts
->Partitions())) {
68 if (styles
->ValueAt(run
-1) == styles
->ValueAt(run
)) {
74 RunStyles::RunStyles() {
75 starts
.reset(new Partitioning(8));
76 styles
.reset(new SplitVector
<int>());
77 styles
->InsertValue(0, 2, 0);
80 RunStyles::~RunStyles() {
83 int RunStyles::Length() const {
84 return starts
->PositionFromPartition(starts
->Partitions());
87 int RunStyles::ValueAt(int position
) const {
88 return styles
->ValueAt(starts
->PartitionFromPosition(position
));
91 int RunStyles::FindNextChange(int position
, int end
) const {
92 const int run
= starts
->PartitionFromPosition(position
);
93 if (run
< starts
->Partitions()) {
94 const int runChange
= starts
->PositionFromPartition(run
);
95 if (runChange
> position
)
97 const int nextChange
= starts
->PositionFromPartition(run
+ 1);
98 if (nextChange
> position
) {
100 } else if (position
< end
) {
110 int RunStyles::StartRun(int position
) const {
111 return starts
->PositionFromPartition(starts
->PartitionFromPosition(position
));
114 int RunStyles::EndRun(int position
) const {
115 return starts
->PositionFromPartition(starts
->PartitionFromPosition(position
) + 1);
118 bool RunStyles::FillRange(int &position
, int value
, int &fillLength
) {
119 if (fillLength
<= 0) {
122 int end
= position
+ fillLength
;
123 if (end
> Length()) {
126 int runEnd
= RunFromPosition(end
);
127 if (styles
->ValueAt(runEnd
) == value
) {
128 // End already has value so trim range.
129 end
= starts
->PositionFromPartition(runEnd
);
130 if (position
>= end
) {
131 // Whole range is already same as value so no action
134 fillLength
= end
- position
;
136 runEnd
= SplitRun(end
);
138 int runStart
= RunFromPosition(position
);
139 if (styles
->ValueAt(runStart
) == value
) {
140 // Start is in expected value so trim range.
142 position
= starts
->PositionFromPartition(runStart
);
143 fillLength
= end
- position
;
145 if (starts
->PositionFromPartition(runStart
) < position
) {
146 runStart
= SplitRun(position
);
150 if (runStart
< runEnd
) {
151 styles
->SetValueAt(runStart
, value
);
152 // Remove each old run over the range
153 for (int run
=runStart
+1; run
<runEnd
; run
++) {
154 RemoveRun(runStart
+1);
156 runEnd
= RunFromPosition(end
);
157 RemoveRunIfSameAsPrevious(runEnd
);
158 RemoveRunIfSameAsPrevious(runStart
);
159 runEnd
= RunFromPosition(end
);
160 RemoveRunIfEmpty(runEnd
);
167 void RunStyles::SetValueAt(int position
, int value
) {
169 FillRange(position
, value
, len
);
172 void RunStyles::InsertSpace(int position
, int insertLength
) {
173 int runStart
= RunFromPosition(position
);
174 if (starts
->PositionFromPartition(runStart
) == position
) {
175 int runStyle
= ValueAt(position
);
176 // Inserting at start of run so make previous longer
178 // Inserting at start of document so ensure 0
180 styles
->SetValueAt(0, 0);
181 starts
->InsertPartition(1, 0);
182 styles
->InsertValue(1, 1, runStyle
);
183 starts
->InsertText(0, insertLength
);
185 starts
->InsertText(runStart
, insertLength
);
189 starts
->InsertText(runStart
-1, insertLength
);
191 // Insert at end of run so do not extend style
192 starts
->InsertText(runStart
, insertLength
);
196 starts
->InsertText(runStart
, insertLength
);
200 void RunStyles::DeleteAll() {
201 starts
.reset(new Partitioning(8));
202 styles
.reset(new SplitVector
<int>());
203 styles
->InsertValue(0, 2, 0);
206 void RunStyles::DeleteRange(int position
, int deleteLength
) {
207 int end
= position
+ deleteLength
;
208 int runStart
= RunFromPosition(position
);
209 int runEnd
= RunFromPosition(end
);
210 if (runStart
== runEnd
) {
211 // Deleting from inside one run
212 starts
->InsertText(runStart
, -deleteLength
);
213 RemoveRunIfEmpty(runStart
);
215 runStart
= SplitRun(position
);
216 runEnd
= SplitRun(end
);
217 starts
->InsertText(runStart
, -deleteLength
);
218 // Remove each old run over the range
219 for (int run
=runStart
; run
<runEnd
; run
++) {
222 RemoveRunIfEmpty(runStart
);
223 RemoveRunIfSameAsPrevious(runStart
);
227 int RunStyles::Runs() const {
228 return starts
->Partitions();
231 bool RunStyles::AllSame() const {
232 for (int run
= 1; run
< starts
->Partitions(); run
++) {
233 if (styles
->ValueAt(run
) != styles
->ValueAt(run
- 1))
239 bool RunStyles::AllSameAs(int value
) const {
240 return AllSame() && (styles
->ValueAt(0) == value
);
243 int RunStyles::Find(int value
, int start
) const {
244 if (start
< Length()) {
245 int run
= start
? RunFromPosition(start
) : 0;
246 if (styles
->ValueAt(run
) == value
)
249 while (run
< starts
->Partitions()) {
250 if (styles
->ValueAt(run
) == value
)
251 return starts
->PositionFromPartition(run
);
258 void RunStyles::Check() const {
260 throw std::runtime_error("RunStyles: Length can not be negative.");
262 if (starts
->Partitions() < 1) {
263 throw std::runtime_error("RunStyles: Must always have 1 or more partitions.");
265 if (starts
->Partitions() != styles
->Length()-1) {
266 throw std::runtime_error("RunStyles: Partitions and styles different lengths.");
269 while (start
< Length()) {
270 const int end
= EndRun(start
);
272 throw std::runtime_error("RunStyles: Partition is 0 length.");
276 if (styles
->ValueAt(styles
->Length()-1) != 0) {
277 throw std::runtime_error("RunStyles: Unused style at end changed.");
279 for (int j
=1; j
<styles
->Length()-1; j
++) {
280 if (styles
->ValueAt(j
) == styles
->ValueAt(j
-1)) {
281 throw std::runtime_error("RunStyles: Style of a partition same as previous.");