]>
Commit | Line | Data |
---|---|---|
7e0c58e9 RD |
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 | |
1dcf666d | 24 | int RunStyles::RunFromPosition(int position) const { |
7e0c58e9 RD |
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. | |
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 | ||
46 | void RunStyles::RemoveRun(int run) { | |
47 | starts->RemovePartition(run); | |
48 | styles->DeleteRange(run, 1); | |
49 | } | |
50 | ||
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 | ||
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 | ||
67 | RunStyles::RunStyles() { | |
68 | starts = new Partitioning(8); | |
69 | styles = new SplitVector<int>(); | |
70 | styles->InsertValue(0, 2, 0); | |
71 | } | |
72 | ||
73 | RunStyles::~RunStyles() { | |
74 | delete starts; | |
75 | starts = NULL; | |
76 | delete styles; | |
77 | styles = NULL; | |
78 | } | |
79 | ||
9e96e16f | 80 | int RunStyles::Length() const { |
7e0c58e9 RD |
81 | return starts->PositionFromPartition(starts->Partitions()); |
82 | } | |
83 | ||
9e96e16f | 84 | int RunStyles::ValueAt(int position) const { |
7e0c58e9 RD |
85 | return styles->ValueAt(starts->PartitionFromPosition(position)); |
86 | } | |
87 | ||
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 | ||
107 | int RunStyles::StartRun(int position) { | |
108 | return starts->PositionFromPartition(starts->PartitionFromPosition(position)); | |
109 | } | |
110 | ||
111 | int RunStyles::EndRun(int position) { | |
112 | return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1); | |
113 | } | |
114 | ||
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); | |
1dcf666d RD |
150 | runEnd = RunFromPosition(end); |
151 | RemoveRunIfEmpty(runEnd); | |
152 | return true; | |
153 | } else { | |
154 | return false; | |
7e0c58e9 | 155 | } |
7e0c58e9 RD |
156 | } |
157 | ||
158 | void RunStyles::SetValueAt(int position, int value) { | |
159 | int len = 1; | |
160 | FillRange(position, value, len); | |
161 | } | |
162 | ||
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 | ||
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 | ||
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 | ||
1dcf666d RD |
221 | int RunStyles::Runs() const { |
222 | return starts->Partitions(); | |
223 | } | |
224 | ||
225 | 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 | ||
233 | bool RunStyles::AllSameAs(int value) const { | |
234 | return AllSame() && (styles->ValueAt(0) == value); | |
235 | } | |
236 | ||
237 | 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 | } |