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