Update Scintilla to version 3.5.3
[TortoiseGit.git] / ext / scintilla / src / PerLine.cxx
blobf0d8fc8fb102922e4ee3ec7baa3de7b82104a641
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 <vector>
11 #include <algorithm>
13 #include "Platform.h"
15 #include "Scintilla.h"
16 #include "SplitVector.h"
17 #include "Partitioning.h"
18 #include "CellBuffer.h"
19 #include "PerLine.h"
21 #ifdef SCI_NAMESPACE
22 using namespace Scintilla;
23 #endif
25 MarkerHandleSet::MarkerHandleSet() {
26 root = 0;
29 MarkerHandleSet::~MarkerHandleSet() {
30 MarkerHandleNumber *mhn = root;
31 while (mhn) {
32 MarkerHandleNumber *mhnToFree = mhn;
33 mhn = mhn->next;
34 delete mhnToFree;
36 root = 0;
39 int MarkerHandleSet::Length() const {
40 int c = 0;
41 MarkerHandleNumber *mhn = root;
42 while (mhn) {
43 c++;
44 mhn = mhn->next;
46 return c;
49 int MarkerHandleSet::MarkValue() const {
50 unsigned int m = 0;
51 MarkerHandleNumber *mhn = root;
52 while (mhn) {
53 m |= (1 << mhn->number);
54 mhn = mhn->next;
56 return m;
59 bool MarkerHandleSet::Contains(int handle) const {
60 MarkerHandleNumber *mhn = root;
61 while (mhn) {
62 if (mhn->handle == handle) {
63 return true;
65 mhn = mhn->next;
67 return false;
70 bool MarkerHandleSet::InsertHandle(int handle, int markerNum) {
71 MarkerHandleNumber *mhn = new MarkerHandleNumber;
72 mhn->handle = handle;
73 mhn->number = markerNum;
74 mhn->next = root;
75 root = mhn;
76 return true;
79 void MarkerHandleSet::RemoveHandle(int handle) {
80 MarkerHandleNumber **pmhn = &root;
81 while (*pmhn) {
82 MarkerHandleNumber *mhn = *pmhn;
83 if (mhn->handle == handle) {
84 *pmhn = mhn->next;
85 delete mhn;
86 return;
88 pmhn = &((*pmhn)->next);
92 bool MarkerHandleSet::RemoveNumber(int markerNum, bool all) {
93 bool performedDeletion = false;
94 MarkerHandleNumber **pmhn = &root;
95 while (*pmhn) {
96 MarkerHandleNumber *mhn = *pmhn;
97 if (mhn->number == markerNum) {
98 *pmhn = mhn->next;
99 delete mhn;
100 performedDeletion = true;
101 if (!all)
102 break;
103 } else {
104 pmhn = &((*pmhn)->next);
107 return performedDeletion;
110 void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
111 MarkerHandleNumber **pmhn = &root;
112 while (*pmhn) {
113 pmhn = &((*pmhn)->next);
115 *pmhn = other->root;
116 other->root = 0;
119 LineMarkers::~LineMarkers() {
120 Init();
123 void LineMarkers::Init() {
124 for (int line = 0; line < markers.Length(); line++) {
125 delete markers[line];
126 markers[line] = 0;
128 markers.DeleteAll();
131 void LineMarkers::InsertLine(int line) {
132 if (markers.Length()) {
133 markers.Insert(line, 0);
137 void LineMarkers::RemoveLine(int line) {
138 // Retain the markers from the deleted line by oring them into the previous line
139 if (markers.Length()) {
140 if (line > 0) {
141 MergeMarkers(line - 1);
143 markers.Delete(line);
147 int LineMarkers::LineFromHandle(int markerHandle) {
148 if (markers.Length()) {
149 for (int line = 0; line < markers.Length(); line++) {
150 if (markers[line]) {
151 if (markers[line]->Contains(markerHandle)) {
152 return line;
157 return -1;
160 void LineMarkers::MergeMarkers(int pos) {
161 if (markers[pos + 1] != NULL) {
162 if (markers[pos] == NULL)
163 markers[pos] = new MarkerHandleSet;
164 markers[pos]->CombineWith(markers[pos + 1]);
165 delete markers[pos + 1];
166 markers[pos + 1] = NULL;
170 int LineMarkers::MarkValue(int line) {
171 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line])
172 return markers[line]->MarkValue();
173 else
174 return 0;
177 int LineMarkers::MarkerNext(int lineStart, int mask) const {
178 if (lineStart < 0)
179 lineStart = 0;
180 int length = markers.Length();
181 for (int iLine = lineStart; iLine < length; iLine++) {
182 MarkerHandleSet *onLine = markers[iLine];
183 if (onLine && ((onLine->MarkValue() & mask) != 0))
184 //if ((pdoc->GetMark(iLine) & lParam) != 0)
185 return iLine;
187 return -1;
190 int LineMarkers::AddMark(int line, int markerNum, int lines) {
191 handleCurrent++;
192 if (!markers.Length()) {
193 // No existing markers so allocate one element per line
194 markers.InsertValue(0, lines, 0);
196 if (line >= markers.Length()) {
197 return -1;
199 if (!markers[line]) {
200 // Need new structure to hold marker handle
201 markers[line] = new MarkerHandleSet();
203 markers[line]->InsertHandle(handleCurrent, markerNum);
205 return handleCurrent;
208 bool LineMarkers::DeleteMark(int line, int markerNum, bool all) {
209 bool someChanges = false;
210 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) {
211 if (markerNum == -1) {
212 someChanges = true;
213 delete markers[line];
214 markers[line] = NULL;
215 } else {
216 someChanges = markers[line]->RemoveNumber(markerNum, all);
217 if (markers[line]->Length() == 0) {
218 delete markers[line];
219 markers[line] = NULL;
223 return someChanges;
226 void LineMarkers::DeleteMarkFromHandle(int markerHandle) {
227 int line = LineFromHandle(markerHandle);
228 if (line >= 0) {
229 markers[line]->RemoveHandle(markerHandle);
230 if (markers[line]->Length() == 0) {
231 delete markers[line];
232 markers[line] = NULL;
237 LineLevels::~LineLevels() {
240 void LineLevels::Init() {
241 levels.DeleteAll();
244 void LineLevels::InsertLine(int line) {
245 if (levels.Length()) {
246 int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE;
247 levels.InsertValue(line, 1, level);
251 void LineLevels::RemoveLine(int line) {
252 if (levels.Length()) {
253 // Move up following lines but merge header flag from this line
254 // to line before to avoid a temporary disappearence causing expansion.
255 int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG;
256 levels.Delete(line);
257 if (line == levels.Length()-1) // Last line loses the header flag
258 levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG;
259 else if (line > 0)
260 levels[line-1] |= firstHeader;
264 void LineLevels::ExpandLevels(int sizeNew) {
265 levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
268 void LineLevels::ClearLevels() {
269 levels.DeleteAll();
272 int LineLevels::SetLevel(int line, int level, int lines) {
273 int prev = 0;
274 if ((line >= 0) && (line < lines)) {
275 if (!levels.Length()) {
276 ExpandLevels(lines + 1);
278 prev = levels[line];
279 if (prev != level) {
280 levels[line] = level;
283 return prev;
286 int LineLevels::GetLevel(int line) const {
287 if (levels.Length() && (line >= 0) && (line < levels.Length())) {
288 return levels[line];
289 } else {
290 return SC_FOLDLEVELBASE;
294 LineState::~LineState() {
297 void LineState::Init() {
298 lineStates.DeleteAll();
301 void LineState::InsertLine(int line) {
302 if (lineStates.Length()) {
303 lineStates.EnsureLength(line);
304 int val = (line < lineStates.Length()) ? lineStates[line] : 0;
305 lineStates.Insert(line, val);
309 void LineState::RemoveLine(int line) {
310 if (lineStates.Length() > line) {
311 lineStates.Delete(line);
315 int LineState::SetLineState(int line, int state) {
316 lineStates.EnsureLength(line + 1);
317 int stateOld = lineStates[line];
318 lineStates[line] = state;
319 return stateOld;
322 int LineState::GetLineState(int line) {
323 if (line < 0)
324 return 0;
325 lineStates.EnsureLength(line + 1);
326 return lineStates[line];
329 int LineState::GetMaxLineState() const {
330 return lineStates.Length();
333 static int NumberLines(const char *text) {
334 if (text) {
335 int newLines = 0;
336 while (*text) {
337 if (*text == '\n')
338 newLines++;
339 text++;
341 return newLines+1;
342 } else {
343 return 0;
347 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
348 // and then has text and optional styles.
350 static const int IndividualStyles = 0x100;
352 struct AnnotationHeader {
353 short style; // Style IndividualStyles implies array of styles
354 short lines;
355 int length;
358 LineAnnotation::~LineAnnotation() {
359 ClearAll();
362 void LineAnnotation::Init() {
363 ClearAll();
366 void LineAnnotation::InsertLine(int line) {
367 if (annotations.Length()) {
368 annotations.EnsureLength(line);
369 annotations.Insert(line, 0);
373 void LineAnnotation::RemoveLine(int line) {
374 if (annotations.Length() && (line > 0) && (line <= annotations.Length())) {
375 delete []annotations[line-1];
376 annotations.Delete(line-1);
380 bool LineAnnotation::MultipleStyles(int line) const {
381 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
382 return reinterpret_cast<AnnotationHeader *>(annotations[line])->style == IndividualStyles;
383 else
384 return 0;
387 int LineAnnotation::Style(int line) const {
388 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
389 return reinterpret_cast<AnnotationHeader *>(annotations[line])->style;
390 else
391 return 0;
394 const char *LineAnnotation::Text(int line) const {
395 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
396 return annotations[line]+sizeof(AnnotationHeader);
397 else
398 return 0;
401 const unsigned char *LineAnnotation::Styles(int line) const {
402 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line] && MultipleStyles(line))
403 return reinterpret_cast<unsigned char *>(annotations[line] + sizeof(AnnotationHeader) + Length(line));
404 else
405 return 0;
408 static char *AllocateAnnotation(int length, int style) {
409 size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0);
410 char *ret = new char[len];
411 memset(ret, 0, len);
412 return ret;
415 void LineAnnotation::SetText(int line, const char *text) {
416 if (text && (line >= 0)) {
417 annotations.EnsureLength(line+1);
418 int style = Style(line);
419 if (annotations[line]) {
420 delete []annotations[line];
422 annotations[line] = AllocateAnnotation(static_cast<int>(strlen(text)), style);
423 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
424 pah->style = static_cast<short>(style);
425 pah->length = static_cast<int>(strlen(text));
426 pah->lines = static_cast<short>(NumberLines(text));
427 memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length);
428 } else {
429 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) {
430 delete []annotations[line];
431 annotations[line] = 0;
436 void LineAnnotation::ClearAll() {
437 for (int line = 0; line < annotations.Length(); line++) {
438 delete []annotations[line];
439 annotations[line] = 0;
441 annotations.DeleteAll();
444 void LineAnnotation::SetStyle(int line, int style) {
445 annotations.EnsureLength(line+1);
446 if (!annotations[line]) {
447 annotations[line] = AllocateAnnotation(0, style);
449 reinterpret_cast<AnnotationHeader *>(annotations[line])->style = static_cast<short>(style);
452 void LineAnnotation::SetStyles(int line, const unsigned char *styles) {
453 if (line >= 0) {
454 annotations.EnsureLength(line+1);
455 if (!annotations[line]) {
456 annotations[line] = AllocateAnnotation(0, IndividualStyles);
457 } else {
458 AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line]);
459 if (pahSource->style != IndividualStyles) {
460 char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles);
461 AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation);
462 pahAlloc->length = pahSource->length;
463 pahAlloc->lines = pahSource->lines;
464 memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length);
465 delete []annotations[line];
466 annotations[line] = allocation;
469 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
470 pah->style = IndividualStyles;
471 memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length);
475 int LineAnnotation::Length(int line) const {
476 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
477 return reinterpret_cast<AnnotationHeader *>(annotations[line])->length;
478 else
479 return 0;
482 int LineAnnotation::Lines(int line) const {
483 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
484 return reinterpret_cast<AnnotationHeader *>(annotations[line])->lines;
485 else
486 return 0;
489 LineTabstops::~LineTabstops() {
490 Init();
493 void LineTabstops::Init() {
494 for (int line = 0; line < tabstops.Length(); line++) {
495 delete tabstops[line];
497 tabstops.DeleteAll();
500 void LineTabstops::InsertLine(int line) {
501 if (tabstops.Length()) {
502 tabstops.EnsureLength(line);
503 tabstops.Insert(line, 0);
507 void LineTabstops::RemoveLine(int line) {
508 if (tabstops.Length() > line) {
509 delete tabstops[line];
510 tabstops.Delete(line);
514 bool LineTabstops::ClearTabstops(int line) {
515 if (line < tabstops.Length()) {
516 TabstopList *tl = tabstops[line];
517 if (tl) {
518 tl->clear();
519 return true;
522 return false;
525 bool LineTabstops::AddTabstop(int line, int x) {
526 tabstops.EnsureLength(line + 1);
527 if (!tabstops[line]) {
528 tabstops[line] = new TabstopList();
531 TabstopList *tl = tabstops[line];
532 if (tl) {
533 // tabstop positions are kept in order - insert in the right place
534 std::vector<int>::iterator it = std::lower_bound(tl->begin(), tl->end(), x);
535 // don't insert duplicates
536 if (it == tl->end() || *it != x) {
537 tl->insert(it, x);
538 return true;
541 return false;
544 int LineTabstops::GetNextTabstop(int line, int x) const {
545 if (line < tabstops.Length()) {
546 TabstopList *tl = tabstops[line];
547 if (tl) {
548 for (size_t i = 0; i < tl->size(); i++) {
549 if ((*tl)[i] > x) {
550 return (*tl)[i];
555 return 0;