]>
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 | |
24 | int RunStyles::RunFromPosition(int position) { | |
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 | ||
80 | int RunStyles::Length() { | |
81 | return starts->PositionFromPartition(starts->Partitions()); | |
82 | } | |
83 | ||
84 | int RunStyles::ValueAt(int position) { | |
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); | |
150 | } | |
151 | return true; | |
152 | } | |
153 | ||
154 | void RunStyles::SetValueAt(int position, int value) { | |
155 | int len = 1; | |
156 | FillRange(position, value, len); | |
157 | } | |
158 | ||
159 | void RunStyles::InsertSpace(int position, int insertLength) { | |
160 | int runStart = RunFromPosition(position); | |
161 | if (starts->PositionFromPartition(runStart) == position) { | |
162 | int runStyle = ValueAt(position); | |
163 | // Inserting at start of run so make previous longer | |
164 | if (runStart == 0) { | |
165 | // Inserting at start of document so ensure 0 | |
166 | if (runStyle) { | |
167 | styles->SetValueAt(0, 0); | |
168 | starts->InsertPartition(1, 0); | |
169 | styles->InsertValue(1, 1, runStyle); | |
170 | starts->InsertText(0, insertLength); | |
171 | } else { | |
172 | starts->InsertText(runStart, insertLength); | |
173 | } | |
174 | } else { | |
175 | if (runStyle) { | |
176 | starts->InsertText(runStart-1, insertLength); | |
177 | } else { | |
178 | // Insert at end of run so do not extend style | |
179 | starts->InsertText(runStart, insertLength); | |
180 | } | |
181 | } | |
182 | } else { | |
183 | starts->InsertText(runStart, insertLength); | |
184 | } | |
185 | } | |
186 | ||
187 | void RunStyles::DeleteAll() { | |
188 | delete starts; | |
189 | starts = NULL; | |
190 | delete styles; | |
191 | styles = NULL; | |
192 | starts = new Partitioning(8); | |
193 | styles = new SplitVector<int>(); | |
194 | styles->InsertValue(0, 2, 0); | |
195 | } | |
196 | ||
197 | void RunStyles::DeleteRange(int position, int deleteLength) { | |
198 | int end = position + deleteLength; | |
199 | int runStart = RunFromPosition(position); | |
200 | int runEnd = RunFromPosition(end); | |
201 | if (runStart == runEnd) { | |
202 | // Deleting from inside one run | |
203 | starts->InsertText(runStart, -deleteLength); | |
204 | } else { | |
205 | runStart = SplitRun(position); | |
206 | runEnd = SplitRun(end); | |
207 | starts->InsertText(runStart, -deleteLength); | |
208 | // Remove each old run over the range | |
209 | for (int run=runStart; run<runEnd; run++) { | |
210 | RemoveRun(runStart); | |
211 | } | |
212 | RemoveRunIfEmpty(runStart); | |
213 | RemoveRunIfSameAsPrevious(runStart); | |
214 | } | |
215 | } | |
216 |