1 /** @file RunStyles.cxx
\r
2 ** Data structure used to store sparse styles.
\r
4 // Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
\r
5 // The License.txt file describes the conditions under which this software may be distributed.
\r
12 #include "Platform.h"
\r
14 #include "Scintilla.h"
\r
15 #include "SplitVector.h"
\r
16 #include "Partitioning.h"
\r
17 #include "RunStyles.h"
\r
19 #ifdef SCI_NAMESPACE
\r
20 using namespace Scintilla;
\r
23 // Find the first run at a position
\r
24 int RunStyles::RunFromPosition(int position) {
\r
25 int run = starts->PartitionFromPosition(position);
\r
26 // Go to first element with this position
\r
27 while ((run > 0) && (position == starts->PositionFromPartition(run-1))) {
\r
33 // If there is no run boundary at position, insert one continuing style.
\r
34 int RunStyles::SplitRun(int position) {
\r
35 int run = RunFromPosition(position);
\r
36 int posRun = starts->PositionFromPartition(run);
\r
37 if (posRun < position) {
\r
38 int runStyle = ValueAt(position);
\r
40 starts->InsertPartition(run, position);
\r
41 styles->InsertValue(run, 1, runStyle);
\r
46 void RunStyles::RemoveRun(int run) {
\r
47 starts->RemovePartition(run);
\r
48 styles->DeleteRange(run, 1);
\r
51 void RunStyles::RemoveRunIfEmpty(int run) {
\r
52 if ((run < starts->Partitions()) && (starts->Partitions() > 1)) {
\r
53 if (starts->PositionFromPartition(run) == starts->PositionFromPartition(run+1)) {
\r
59 void RunStyles::RemoveRunIfSameAsPrevious(int run) {
\r
60 if ((run > 0) && (run < starts->Partitions())) {
\r
61 if (styles->ValueAt(run-1) == styles->ValueAt(run)) {
\r
67 RunStyles::RunStyles() {
\r
68 starts = new Partitioning(8);
\r
69 styles = new SplitVector<int>();
\r
70 styles->InsertValue(0, 2, 0);
\r
73 RunStyles::~RunStyles() {
\r
80 int RunStyles::Length() const {
\r
81 return starts->PositionFromPartition(starts->Partitions());
\r
84 int RunStyles::ValueAt(int position) const {
\r
85 return styles->ValueAt(starts->PartitionFromPosition(position));
\r
88 int RunStyles::FindNextChange(int position, int end) {
\r
89 int run = starts->PartitionFromPosition(position);
\r
90 if (run < starts->Partitions()) {
\r
91 int runChange = starts->PositionFromPartition(run);
\r
92 if (runChange > position)
\r
94 int nextChange = starts->PositionFromPartition(run + 1);
\r
95 if (nextChange > position) {
\r
97 } else if (position < end) {
\r
107 int RunStyles::StartRun(int position) {
\r
108 return starts->PositionFromPartition(starts->PartitionFromPosition(position));
\r
111 int RunStyles::EndRun(int position) {
\r
112 return starts->PositionFromPartition(starts->PartitionFromPosition(position) + 1);
\r
115 bool RunStyles::FillRange(int &position, int value, int &fillLength) {
\r
116 int end = position + fillLength;
\r
117 int runEnd = RunFromPosition(end);
\r
118 if (styles->ValueAt(runEnd) == value) {
\r
119 // End already has value so trim range.
\r
120 end = starts->PositionFromPartition(runEnd);
\r
121 if (position >= end) {
\r
122 // Whole range is already same as value so no action
\r
125 fillLength = end - position;
\r
127 runEnd = SplitRun(end);
\r
129 int runStart = RunFromPosition(position);
\r
130 if (styles->ValueAt(runStart) == value) {
\r
131 // Start is in expected value so trim range.
\r
133 position = starts->PositionFromPartition(runStart);
\r
134 fillLength = end - position;
\r
136 if (starts->PositionFromPartition(runStart) < position) {
\r
137 runStart = SplitRun(position);
\r
141 if (runStart < runEnd) {
\r
142 styles->SetValueAt(runStart, value);
\r
143 // Remove each old run over the range
\r
144 for (int run=runStart+1; run<runEnd; run++) {
\r
145 RemoveRun(runStart+1);
\r
147 runEnd = RunFromPosition(end);
\r
148 RemoveRunIfSameAsPrevious(runEnd);
\r
149 RemoveRunIfSameAsPrevious(runStart);
\r
154 void RunStyles::SetValueAt(int position, int value) {
\r
156 FillRange(position, value, len);
\r
159 void RunStyles::InsertSpace(int position, int insertLength) {
\r
160 int runStart = RunFromPosition(position);
\r
161 if (starts->PositionFromPartition(runStart) == position) {
\r
162 int runStyle = ValueAt(position);
\r
163 // Inserting at start of run so make previous longer
\r
164 if (runStart == 0) {
\r
165 // Inserting at start of document so ensure 0
\r
167 styles->SetValueAt(0, 0);
\r
168 starts->InsertPartition(1, 0);
\r
169 styles->InsertValue(1, 1, runStyle);
\r
170 starts->InsertText(0, insertLength);
\r
172 starts->InsertText(runStart, insertLength);
\r
176 starts->InsertText(runStart-1, insertLength);
\r
178 // Insert at end of run so do not extend style
\r
179 starts->InsertText(runStart, insertLength);
\r
183 starts->InsertText(runStart, insertLength);
\r
187 void RunStyles::DeleteAll() {
\r
192 starts = new Partitioning(8);
\r
193 styles = new SplitVector<int>();
\r
194 styles->InsertValue(0, 2, 0);
\r
197 void RunStyles::DeleteRange(int position, int deleteLength) {
\r
198 int end = position + deleteLength;
\r
199 int runStart = RunFromPosition(position);
\r
200 int runEnd = RunFromPosition(end);
\r
201 if (runStart == runEnd) {
\r
202 // Deleting from inside one run
\r
203 starts->InsertText(runStart, -deleteLength);
\r
205 runStart = SplitRun(position);
\r
206 runEnd = SplitRun(end);
\r
207 starts->InsertText(runStart, -deleteLength);
\r
208 // Remove each old run over the range
\r
209 for (int run=runStart; run<runEnd; run++) {
\r
210 RemoveRun(runStart);
\r
212 RemoveRunIfEmpty(runStart);
\r
213 RemoveRunIfSameAsPrevious(runStart);
\r