Update Scintilla to version 3.4.4
[TortoiseGit.git] / ext / scintilla / src / PerLine.cxx
blob27257cd78fc6030fabf7255f9d04cc8ebc28f142
1 // Scintilla source code edit control
2 /** @file PerLine.cxx
3 ** Manages data associated with each line of the document
4 **/
5 // Copyright 1998-2009 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
8 #include <string.h>
10 #include <algorithm>
12 #include "Platform.h"
14 #include "Scintilla.h"
15 #include "SplitVector.h"
16 #include "Partitioning.h"
17 #include "CellBuffer.h"
18 #include "PerLine.h"
20 #ifdef SCI_NAMESPACE
21 using namespace Scintilla;
22 #endif
24 MarkerHandleSet::MarkerHandleSet() {
25 root = 0;
28 MarkerHandleSet::~MarkerHandleSet() {
29 MarkerHandleNumber *mhn = root;
30 while (mhn) {
31 MarkerHandleNumber *mhnToFree = mhn;
32 mhn = mhn->next;
33 delete mhnToFree;
35 root = 0;
38 int MarkerHandleSet::Length() const {
39 int c = 0;
40 MarkerHandleNumber *mhn = root;
41 while (mhn) {
42 c++;
43 mhn = mhn->next;
45 return c;
48 int MarkerHandleSet::MarkValue() const {
49 unsigned int m = 0;
50 MarkerHandleNumber *mhn = root;
51 while (mhn) {
52 m |= (1 << mhn->number);
53 mhn = mhn->next;
55 return m;
58 bool MarkerHandleSet::Contains(int handle) const {
59 MarkerHandleNumber *mhn = root;
60 while (mhn) {
61 if (mhn->handle == handle) {
62 return true;
64 mhn = mhn->next;
66 return false;
69 bool MarkerHandleSet::InsertHandle(int handle, int markerNum) {
70 MarkerHandleNumber *mhn = new MarkerHandleNumber;
71 mhn->handle = handle;
72 mhn->number = markerNum;
73 mhn->next = root;
74 root = mhn;
75 return true;
78 void MarkerHandleSet::RemoveHandle(int handle) {
79 MarkerHandleNumber **pmhn = &root;
80 while (*pmhn) {
81 MarkerHandleNumber *mhn = *pmhn;
82 if (mhn->handle == handle) {
83 *pmhn = mhn->next;
84 delete mhn;
85 return;
87 pmhn = &((*pmhn)->next);
91 bool MarkerHandleSet::RemoveNumber(int markerNum, bool all) {
92 bool performedDeletion = false;
93 MarkerHandleNumber **pmhn = &root;
94 while (*pmhn) {
95 MarkerHandleNumber *mhn = *pmhn;
96 if (mhn->number == markerNum) {
97 *pmhn = mhn->next;
98 delete mhn;
99 performedDeletion = true;
100 if (!all)
101 break;
102 } else {
103 pmhn = &((*pmhn)->next);
106 return performedDeletion;
109 void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
110 MarkerHandleNumber **pmhn = &root;
111 while (*pmhn) {
112 pmhn = &((*pmhn)->next);
114 *pmhn = other->root;
115 other->root = 0;
118 LineMarkers::~LineMarkers() {
119 Init();
122 void LineMarkers::Init() {
123 for (int line = 0; line < markers.Length(); line++) {
124 delete markers[line];
125 markers[line] = 0;
127 markers.DeleteAll();
130 void LineMarkers::InsertLine(int line) {
131 if (markers.Length()) {
132 markers.Insert(line, 0);
136 void LineMarkers::RemoveLine(int line) {
137 // Retain the markers from the deleted line by oring them into the previous line
138 if (markers.Length()) {
139 if (line > 0) {
140 MergeMarkers(line - 1);
142 markers.Delete(line);
146 int LineMarkers::LineFromHandle(int markerHandle) {
147 if (markers.Length()) {
148 for (int line = 0; line < markers.Length(); line++) {
149 if (markers[line]) {
150 if (markers[line]->Contains(markerHandle)) {
151 return line;
156 return -1;
159 void LineMarkers::MergeMarkers(int pos) {
160 if (markers[pos + 1] != NULL) {
161 if (markers[pos] == NULL)
162 markers[pos] = new MarkerHandleSet;
163 markers[pos]->CombineWith(markers[pos + 1]);
164 delete markers[pos + 1];
165 markers[pos + 1] = NULL;
169 int LineMarkers::MarkValue(int line) {
170 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line])
171 return markers[line]->MarkValue();
172 else
173 return 0;
176 int LineMarkers::MarkerNext(int lineStart, int mask) const {
177 if (lineStart < 0)
178 lineStart = 0;
179 int length = markers.Length();
180 for (int iLine = lineStart; iLine < length; iLine++) {
181 MarkerHandleSet *onLine = markers[iLine];
182 if (onLine && ((onLine->MarkValue() & mask) != 0))
183 //if ((pdoc->GetMark(iLine) & lParam) != 0)
184 return iLine;
186 return -1;
189 int LineMarkers::AddMark(int line, int markerNum, int lines) {
190 handleCurrent++;
191 if (!markers.Length()) {
192 // No existing markers so allocate one element per line
193 markers.InsertValue(0, lines, 0);
195 if (line >= markers.Length()) {
196 return -1;
198 if (!markers[line]) {
199 // Need new structure to hold marker handle
200 markers[line] = new MarkerHandleSet();
202 markers[line]->InsertHandle(handleCurrent, markerNum);
204 return handleCurrent;
207 bool LineMarkers::DeleteMark(int line, int markerNum, bool all) {
208 bool someChanges = false;
209 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) {
210 if (markerNum == -1) {
211 someChanges = true;
212 delete markers[line];
213 markers[line] = NULL;
214 } else {
215 someChanges = markers[line]->RemoveNumber(markerNum, all);
216 if (markers[line]->Length() == 0) {
217 delete markers[line];
218 markers[line] = NULL;
222 return someChanges;
225 void LineMarkers::DeleteMarkFromHandle(int markerHandle) {
226 int line = LineFromHandle(markerHandle);
227 if (line >= 0) {
228 markers[line]->RemoveHandle(markerHandle);
229 if (markers[line]->Length() == 0) {
230 delete markers[line];
231 markers[line] = NULL;
236 LineLevels::~LineLevels() {
239 void LineLevels::Init() {
240 levels.DeleteAll();
243 void LineLevels::InsertLine(int line) {
244 if (levels.Length()) {
245 int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE;
246 levels.InsertValue(line, 1, level);
250 void LineLevels::RemoveLine(int line) {
251 if (levels.Length()) {
252 // Move up following lines but merge header flag from this line
253 // to line before to avoid a temporary disappearence causing expansion.
254 int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG;
255 levels.Delete(line);
256 if (line == levels.Length()-1) // Last line loses the header flag
257 levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG;
258 else if (line > 0)
259 levels[line-1] |= firstHeader;
263 void LineLevels::ExpandLevels(int sizeNew) {
264 levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
267 void LineLevels::ClearLevels() {
268 levels.DeleteAll();
271 int LineLevels::SetLevel(int line, int level, int lines) {
272 int prev = 0;
273 if ((line >= 0) && (line < lines)) {
274 if (!levels.Length()) {
275 ExpandLevels(lines + 1);
277 prev = levels[line];
278 if (prev != level) {
279 levels[line] = level;
282 return prev;
285 int LineLevels::GetLevel(int line) const {
286 if (levels.Length() && (line >= 0) && (line < levels.Length())) {
287 return levels[line];
288 } else {
289 return SC_FOLDLEVELBASE;
293 LineState::~LineState() {
296 void LineState::Init() {
297 lineStates.DeleteAll();
300 void LineState::InsertLine(int line) {
301 if (lineStates.Length()) {
302 lineStates.EnsureLength(line);
303 int val = (line < lineStates.Length()) ? lineStates[line] : 0;
304 lineStates.Insert(line, val);
308 void LineState::RemoveLine(int line) {
309 if (lineStates.Length() > line) {
310 lineStates.Delete(line);
314 int LineState::SetLineState(int line, int state) {
315 lineStates.EnsureLength(line + 1);
316 int stateOld = lineStates[line];
317 lineStates[line] = state;
318 return stateOld;
321 int LineState::GetLineState(int line) {
322 if (line < 0)
323 return 0;
324 lineStates.EnsureLength(line + 1);
325 return lineStates[line];
328 int LineState::GetMaxLineState() const {
329 return lineStates.Length();
332 static int NumberLines(const char *text) {
333 if (text) {
334 int newLines = 0;
335 while (*text) {
336 if (*text == '\n')
337 newLines++;
338 text++;
340 return newLines+1;
341 } else {
342 return 0;
346 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
347 // and then has text and optional styles.
349 static const int IndividualStyles = 0x100;
351 struct AnnotationHeader {
352 short style; // Style IndividualStyles implies array of styles
353 short lines;
354 int length;
357 LineAnnotation::~LineAnnotation() {
358 ClearAll();
361 void LineAnnotation::Init() {
362 ClearAll();
365 void LineAnnotation::InsertLine(int line) {
366 if (annotations.Length()) {
367 annotations.EnsureLength(line);
368 annotations.Insert(line, 0);
372 void LineAnnotation::RemoveLine(int line) {
373 if (annotations.Length() && (line > 0) && (line <= annotations.Length())) {
374 delete []annotations[line-1];
375 annotations.Delete(line-1);
379 bool LineAnnotation::MultipleStyles(int line) const {
380 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
381 return reinterpret_cast<AnnotationHeader *>(annotations[line])->style == IndividualStyles;
382 else
383 return 0;
386 int LineAnnotation::Style(int line) const {
387 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
388 return reinterpret_cast<AnnotationHeader *>(annotations[line])->style;
389 else
390 return 0;
393 const char *LineAnnotation::Text(int line) const {
394 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
395 return annotations[line]+sizeof(AnnotationHeader);
396 else
397 return 0;
400 const unsigned char *LineAnnotation::Styles(int line) const {
401 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line] && MultipleStyles(line))
402 return reinterpret_cast<unsigned char *>(annotations[line] + sizeof(AnnotationHeader) + Length(line));
403 else
404 return 0;
407 static char *AllocateAnnotation(int length, int style) {
408 size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0);
409 char *ret = new char[len];
410 memset(ret, 0, len);
411 return ret;
414 void LineAnnotation::SetText(int line, const char *text) {
415 if (text && (line >= 0)) {
416 annotations.EnsureLength(line+1);
417 int style = Style(line);
418 if (annotations[line]) {
419 delete []annotations[line];
421 annotations[line] = AllocateAnnotation(static_cast<int>(strlen(text)), style);
422 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
423 pah->style = static_cast<short>(style);
424 pah->length = static_cast<int>(strlen(text));
425 pah->lines = static_cast<short>(NumberLines(text));
426 memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length);
427 } else {
428 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) {
429 delete []annotations[line];
430 annotations[line] = 0;
435 void LineAnnotation::ClearAll() {
436 for (int line = 0; line < annotations.Length(); line++) {
437 delete []annotations[line];
438 annotations[line] = 0;
440 annotations.DeleteAll();
443 void LineAnnotation::SetStyle(int line, int style) {
444 annotations.EnsureLength(line+1);
445 if (!annotations[line]) {
446 annotations[line] = AllocateAnnotation(0, style);
448 reinterpret_cast<AnnotationHeader *>(annotations[line])->style = static_cast<short>(style);
451 void LineAnnotation::SetStyles(int line, const unsigned char *styles) {
452 if (line >= 0) {
453 annotations.EnsureLength(line+1);
454 if (!annotations[line]) {
455 annotations[line] = AllocateAnnotation(0, IndividualStyles);
456 } else {
457 AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line]);
458 if (pahSource->style != IndividualStyles) {
459 char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles);
460 AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation);
461 pahAlloc->length = pahSource->length;
462 pahAlloc->lines = pahSource->lines;
463 memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length);
464 delete []annotations[line];
465 annotations[line] = allocation;
468 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
469 pah->style = IndividualStyles;
470 memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length);
474 int LineAnnotation::Length(int line) const {
475 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
476 return reinterpret_cast<AnnotationHeader *>(annotations[line])->length;
477 else
478 return 0;
481 int LineAnnotation::Lines(int line) const {
482 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
483 return reinterpret_cast<AnnotationHeader *>(annotations[line])->lines;
484 else
485 return 0;