Update Scintilla to version 3.6.3
[geany-mirror.git] / scintilla / src / PerLine.cxx
blob6a3dd33dd4ee13496ed3e1933dee72832b6e27b5
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 <stdexcept>
11 #include <vector>
12 #include <algorithm>
14 #include "Platform.h"
16 #include "Scintilla.h"
17 #include "Position.h"
18 #include "SplitVector.h"
19 #include "Partitioning.h"
20 #include "CellBuffer.h"
21 #include "PerLine.h"
23 #ifdef SCI_NAMESPACE
24 using namespace Scintilla;
25 #endif
27 MarkerHandleSet::MarkerHandleSet() {
28 root = 0;
31 MarkerHandleSet::~MarkerHandleSet() {
32 MarkerHandleNumber *mhn = root;
33 while (mhn) {
34 MarkerHandleNumber *mhnToFree = mhn;
35 mhn = mhn->next;
36 delete mhnToFree;
38 root = 0;
41 int MarkerHandleSet::Length() const {
42 int c = 0;
43 MarkerHandleNumber *mhn = root;
44 while (mhn) {
45 c++;
46 mhn = mhn->next;
48 return c;
51 int MarkerHandleSet::MarkValue() const {
52 unsigned int m = 0;
53 MarkerHandleNumber *mhn = root;
54 while (mhn) {
55 m |= (1 << mhn->number);
56 mhn = mhn->next;
58 return m;
61 bool MarkerHandleSet::Contains(int handle) const {
62 MarkerHandleNumber *mhn = root;
63 while (mhn) {
64 if (mhn->handle == handle) {
65 return true;
67 mhn = mhn->next;
69 return false;
72 bool MarkerHandleSet::InsertHandle(int handle, int markerNum) {
73 MarkerHandleNumber *mhn = new MarkerHandleNumber;
74 mhn->handle = handle;
75 mhn->number = markerNum;
76 mhn->next = root;
77 root = mhn;
78 return true;
81 void MarkerHandleSet::RemoveHandle(int handle) {
82 MarkerHandleNumber **pmhn = &root;
83 while (*pmhn) {
84 MarkerHandleNumber *mhn = *pmhn;
85 if (mhn->handle == handle) {
86 *pmhn = mhn->next;
87 delete mhn;
88 return;
90 pmhn = &((*pmhn)->next);
94 bool MarkerHandleSet::RemoveNumber(int markerNum, bool all) {
95 bool performedDeletion = false;
96 MarkerHandleNumber **pmhn = &root;
97 while (*pmhn) {
98 MarkerHandleNumber *mhn = *pmhn;
99 if (mhn->number == markerNum) {
100 *pmhn = mhn->next;
101 delete mhn;
102 performedDeletion = true;
103 if (!all)
104 break;
105 } else {
106 pmhn = &((*pmhn)->next);
109 return performedDeletion;
112 void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
113 MarkerHandleNumber **pmhn = &other->root;
114 while (*pmhn) {
115 pmhn = &((*pmhn)->next);
117 *pmhn = root;
118 root = other->root;
119 other->root = 0;
122 LineMarkers::~LineMarkers() {
123 Init();
126 void LineMarkers::Init() {
127 for (int line = 0; line < markers.Length(); line++) {
128 delete markers[line];
129 markers[line] = 0;
131 markers.DeleteAll();
134 void LineMarkers::InsertLine(int line) {
135 if (markers.Length()) {
136 markers.Insert(line, 0);
140 void LineMarkers::RemoveLine(int line) {
141 // Retain the markers from the deleted line by oring them into the previous line
142 if (markers.Length()) {
143 if (line > 0) {
144 MergeMarkers(line - 1);
146 markers.Delete(line);
150 int LineMarkers::LineFromHandle(int markerHandle) {
151 if (markers.Length()) {
152 for (int line = 0; line < markers.Length(); line++) {
153 if (markers[line]) {
154 if (markers[line]->Contains(markerHandle)) {
155 return line;
160 return -1;
163 void LineMarkers::MergeMarkers(int pos) {
164 if (markers[pos + 1] != NULL) {
165 if (markers[pos] == NULL)
166 markers[pos] = new MarkerHandleSet;
167 markers[pos]->CombineWith(markers[pos + 1]);
168 delete markers[pos + 1];
169 markers[pos + 1] = NULL;
173 int LineMarkers::MarkValue(int line) {
174 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line])
175 return markers[line]->MarkValue();
176 else
177 return 0;
180 int LineMarkers::MarkerNext(int lineStart, int mask) const {
181 if (lineStart < 0)
182 lineStart = 0;
183 int length = markers.Length();
184 for (int iLine = lineStart; iLine < length; iLine++) {
185 MarkerHandleSet *onLine = markers[iLine];
186 if (onLine && ((onLine->MarkValue() & mask) != 0))
187 //if ((pdoc->GetMark(iLine) & lParam) != 0)
188 return iLine;
190 return -1;
193 int LineMarkers::AddMark(int line, int markerNum, int lines) {
194 handleCurrent++;
195 if (!markers.Length()) {
196 // No existing markers so allocate one element per line
197 markers.InsertValue(0, lines, 0);
199 if (line >= markers.Length()) {
200 return -1;
202 if (!markers[line]) {
203 // Need new structure to hold marker handle
204 markers[line] = new MarkerHandleSet();
206 markers[line]->InsertHandle(handleCurrent, markerNum);
208 return handleCurrent;
211 bool LineMarkers::DeleteMark(int line, int markerNum, bool all) {
212 bool someChanges = false;
213 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) {
214 if (markerNum == -1) {
215 someChanges = true;
216 delete markers[line];
217 markers[line] = NULL;
218 } else {
219 someChanges = markers[line]->RemoveNumber(markerNum, all);
220 if (markers[line]->Length() == 0) {
221 delete markers[line];
222 markers[line] = NULL;
226 return someChanges;
229 void LineMarkers::DeleteMarkFromHandle(int markerHandle) {
230 int line = LineFromHandle(markerHandle);
231 if (line >= 0) {
232 markers[line]->RemoveHandle(markerHandle);
233 if (markers[line]->Length() == 0) {
234 delete markers[line];
235 markers[line] = NULL;
240 LineLevels::~LineLevels() {
243 void LineLevels::Init() {
244 levels.DeleteAll();
247 void LineLevels::InsertLine(int line) {
248 if (levels.Length()) {
249 int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE;
250 levels.InsertValue(line, 1, level);
254 void LineLevels::RemoveLine(int line) {
255 if (levels.Length()) {
256 // Move up following lines but merge header flag from this line
257 // to line before to avoid a temporary disappearence causing expansion.
258 int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG;
259 levels.Delete(line);
260 if (line == levels.Length()-1) // Last line loses the header flag
261 levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG;
262 else if (line > 0)
263 levels[line-1] |= firstHeader;
267 void LineLevels::ExpandLevels(int sizeNew) {
268 levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
271 void LineLevels::ClearLevels() {
272 levels.DeleteAll();
275 int LineLevels::SetLevel(int line, int level, int lines) {
276 int prev = 0;
277 if ((line >= 0) && (line < lines)) {
278 if (!levels.Length()) {
279 ExpandLevels(lines + 1);
281 prev = levels[line];
282 if (prev != level) {
283 levels[line] = level;
286 return prev;
289 int LineLevels::GetLevel(int line) const {
290 if (levels.Length() && (line >= 0) && (line < levels.Length())) {
291 return levels[line];
292 } else {
293 return SC_FOLDLEVELBASE;
297 LineState::~LineState() {
300 void LineState::Init() {
301 lineStates.DeleteAll();
304 void LineState::InsertLine(int line) {
305 if (lineStates.Length()) {
306 lineStates.EnsureLength(line);
307 int val = (line < lineStates.Length()) ? lineStates[line] : 0;
308 lineStates.Insert(line, val);
312 void LineState::RemoveLine(int line) {
313 if (lineStates.Length() > line) {
314 lineStates.Delete(line);
318 int LineState::SetLineState(int line, int state) {
319 lineStates.EnsureLength(line + 1);
320 int stateOld = lineStates[line];
321 lineStates[line] = state;
322 return stateOld;
325 int LineState::GetLineState(int line) {
326 if (line < 0)
327 return 0;
328 lineStates.EnsureLength(line + 1);
329 return lineStates[line];
332 int LineState::GetMaxLineState() const {
333 return lineStates.Length();
336 static int NumberLines(const char *text) {
337 if (text) {
338 int newLines = 0;
339 while (*text) {
340 if (*text == '\n')
341 newLines++;
342 text++;
344 return newLines+1;
345 } else {
346 return 0;
350 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
351 // and then has text and optional styles.
353 static const int IndividualStyles = 0x100;
355 struct AnnotationHeader {
356 short style; // Style IndividualStyles implies array of styles
357 short lines;
358 int length;
361 LineAnnotation::~LineAnnotation() {
362 ClearAll();
365 void LineAnnotation::Init() {
366 ClearAll();
369 void LineAnnotation::InsertLine(int line) {
370 if (annotations.Length()) {
371 annotations.EnsureLength(line);
372 annotations.Insert(line, 0);
376 void LineAnnotation::RemoveLine(int line) {
377 if (annotations.Length() && (line > 0) && (line <= annotations.Length())) {
378 delete []annotations[line-1];
379 annotations.Delete(line-1);
383 bool LineAnnotation::MultipleStyles(int line) const {
384 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
385 return reinterpret_cast<AnnotationHeader *>(annotations[line])->style == IndividualStyles;
386 else
387 return 0;
390 int LineAnnotation::Style(int line) const {
391 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
392 return reinterpret_cast<AnnotationHeader *>(annotations[line])->style;
393 else
394 return 0;
397 const char *LineAnnotation::Text(int line) const {
398 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
399 return annotations[line]+sizeof(AnnotationHeader);
400 else
401 return 0;
404 const unsigned char *LineAnnotation::Styles(int line) const {
405 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line] && MultipleStyles(line))
406 return reinterpret_cast<unsigned char *>(annotations[line] + sizeof(AnnotationHeader) + Length(line));
407 else
408 return 0;
411 static char *AllocateAnnotation(int length, int style) {
412 size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0);
413 char *ret = new char[len]();
414 return ret;
417 void LineAnnotation::SetText(int line, const char *text) {
418 if (text && (line >= 0)) {
419 annotations.EnsureLength(line+1);
420 int style = Style(line);
421 if (annotations[line]) {
422 delete []annotations[line];
424 annotations[line] = AllocateAnnotation(static_cast<int>(strlen(text)), style);
425 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
426 pah->style = static_cast<short>(style);
427 pah->length = static_cast<int>(strlen(text));
428 pah->lines = static_cast<short>(NumberLines(text));
429 memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length);
430 } else {
431 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) {
432 delete []annotations[line];
433 annotations[line] = 0;
438 void LineAnnotation::ClearAll() {
439 for (int line = 0; line < annotations.Length(); line++) {
440 delete []annotations[line];
441 annotations[line] = 0;
443 annotations.DeleteAll();
446 void LineAnnotation::SetStyle(int line, int style) {
447 annotations.EnsureLength(line+1);
448 if (!annotations[line]) {
449 annotations[line] = AllocateAnnotation(0, style);
451 reinterpret_cast<AnnotationHeader *>(annotations[line])->style = static_cast<short>(style);
454 void LineAnnotation::SetStyles(int line, const unsigned char *styles) {
455 if (line >= 0) {
456 annotations.EnsureLength(line+1);
457 if (!annotations[line]) {
458 annotations[line] = AllocateAnnotation(0, IndividualStyles);
459 } else {
460 AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line]);
461 if (pahSource->style != IndividualStyles) {
462 char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles);
463 AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation);
464 pahAlloc->length = pahSource->length;
465 pahAlloc->lines = pahSource->lines;
466 memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length);
467 delete []annotations[line];
468 annotations[line] = allocation;
471 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
472 pah->style = IndividualStyles;
473 memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length);
477 int LineAnnotation::Length(int line) const {
478 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
479 return reinterpret_cast<AnnotationHeader *>(annotations[line])->length;
480 else
481 return 0;
484 int LineAnnotation::Lines(int line) const {
485 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
486 return reinterpret_cast<AnnotationHeader *>(annotations[line])->lines;
487 else
488 return 0;
491 LineTabstops::~LineTabstops() {
492 Init();
495 void LineTabstops::Init() {
496 for (int line = 0; line < tabstops.Length(); line++) {
497 delete tabstops[line];
499 tabstops.DeleteAll();
502 void LineTabstops::InsertLine(int line) {
503 if (tabstops.Length()) {
504 tabstops.EnsureLength(line);
505 tabstops.Insert(line, 0);
509 void LineTabstops::RemoveLine(int line) {
510 if (tabstops.Length() > line) {
511 delete tabstops[line];
512 tabstops.Delete(line);
516 bool LineTabstops::ClearTabstops(int line) {
517 if (line < tabstops.Length()) {
518 TabstopList *tl = tabstops[line];
519 if (tl) {
520 tl->clear();
521 return true;
524 return false;
527 bool LineTabstops::AddTabstop(int line, int x) {
528 tabstops.EnsureLength(line + 1);
529 if (!tabstops[line]) {
530 tabstops[line] = new TabstopList();
533 TabstopList *tl = tabstops[line];
534 if (tl) {
535 // tabstop positions are kept in order - insert in the right place
536 std::vector<int>::iterator it = std::lower_bound(tl->begin(), tl->end(), x);
537 // don't insert duplicates
538 if (it == tl->end() || *it != x) {
539 tl->insert(it, x);
540 return true;
543 return false;
546 int LineTabstops::GetNextTabstop(int line, int x) const {
547 if (line < tabstops.Length()) {
548 TabstopList *tl = tabstops[line];
549 if (tl) {
550 for (size_t i = 0; i < tl->size(); i++) {
551 if ((*tl)[i] > x) {
552 return (*tl)[i];
557 return 0;