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.
14 #include "Scintilla.h"
15 #include "SplitVector.h"
16 #include "Partitioning.h"
17 #include "RunStyles.h"
20 using namespace Scintilla
;
23 // Find the first run at a position
24 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))) {
33 // If there is no run boundary at position, insert one continuing style.
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
);
40 starts
->InsertPartition(run
, position
);
41 styles
->InsertValue(run
, 1, runStyle
);
46 void RunStyles::RemoveRun(int run
) {
47 starts
->RemovePartition(run
);
48 styles
->DeleteRange(run
, 1);
51 void RunStyles::RemoveRunIfEmpty(int run
) {
52 if ((run
< starts
->Partitions()) && (starts
->Partitions() > 1)) {
53 if (starts
->PositionFromPartition(run
) == starts
->PositionFromPartition(run
+1)) {
59 void RunStyles::RemoveRunIfSameAsPrevious(int run
) {
60 if ((run
> 0) && (run
< starts
->Partitions())) {
61 if (styles
->ValueAt(run
-1) == styles
->ValueAt(run
)) {
67 RunStyles::RunStyles() {
68 starts
= new Partitioning(8);
69 styles
= new SplitVector
<int>();
70 styles
->InsertValue(0, 2, 0);
73 RunStyles::~RunStyles() {
80 int RunStyles::Length() const {
81 return starts
->PositionFromPartition(starts
->Partitions());
84 int RunStyles::ValueAt(int position
) const {
85 return styles
->ValueAt(starts
->PartitionFromPosition(position
));
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
)
94 int nextChange
= starts
->PositionFromPartition(run
+ 1);
95 if (nextChange
> position
) {
97 } else if (position
< end
) {
107 int RunStyles::StartRun(int position
) {
108 return starts
->PositionFromPartition(starts
->PartitionFromPosition(position
));
111 int RunStyles::EndRun(int position
) {
112 return starts
->PositionFromPartition(starts
->PartitionFromPosition(position
) + 1);
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
125 fillLength
= end
- position
;
127 runEnd
= SplitRun(end
);
129 int runStart
= RunFromPosition(position
);
130 if (styles
->ValueAt(runStart
) == value
) {
131 // Start is in expected value so trim range.
133 position
= starts
->PositionFromPartition(runStart
);
134 fillLength
= end
- position
;
136 if (starts
->PositionFromPartition(runStart
) < position
) {
137 runStart
= SplitRun(position
);
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);
147 runEnd
= RunFromPosition(end
);
148 RemoveRunIfSameAsPrevious(runEnd
);
149 RemoveRunIfSameAsPrevious(runStart
);
150 runEnd
= RunFromPosition(end
);
151 RemoveRunIfEmpty(runEnd
);
158 void RunStyles::SetValueAt(int position
, int value
) {
160 FillRange(position
, value
, len
);
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
169 // Inserting at start of document so ensure 0
171 styles
->SetValueAt(0, 0);
172 starts
->InsertPartition(1, 0);
173 styles
->InsertValue(1, 1, runStyle
);
174 starts
->InsertText(0, insertLength
);
176 starts
->InsertText(runStart
, insertLength
);
180 starts
->InsertText(runStart
-1, insertLength
);
182 // Insert at end of run so do not extend style
183 starts
->InsertText(runStart
, insertLength
);
187 starts
->InsertText(runStart
, insertLength
);
191 void RunStyles::DeleteAll() {
196 starts
= new Partitioning(8);
197 styles
= new SplitVector
<int>();
198 styles
->InsertValue(0, 2, 0);
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 RemoveRunIfEmpty(runStart
);
210 runStart
= SplitRun(position
);
211 runEnd
= SplitRun(end
);
212 starts
->InsertText(runStart
, -deleteLength
);
213 // Remove each old run over the range
214 for (int run
=runStart
; run
<runEnd
; run
++) {
217 RemoveRunIfEmpty(runStart
);
218 RemoveRunIfSameAsPrevious(runStart
);
222 int RunStyles::Runs() const {
223 return starts
->Partitions();
226 bool RunStyles::AllSame() const {
227 for (int run
= 1; run
< starts
->Partitions(); run
++) {
228 if (styles
->ValueAt(run
) != styles
->ValueAt(run
- 1))
234 bool RunStyles::AllSameAs(int value
) const {
235 return AllSame() && (styles
->ValueAt(0) == value
);
238 int RunStyles::Find(int value
, int start
) const {
239 if (start
< Length()) {
240 int run
= start
? RunFromPosition(start
) : 0;
241 if (styles
->ValueAt(run
) == value
)
244 while (run
< starts
->Partitions()) {
245 if (styles
->ValueAt(run
) == value
)
246 return starts
->PositionFromPartition(run
);