Update Scintilla to version 3.5.7
[TortoiseGit.git] / ext / scintilla / src / PerLine.cxx
blob4e241f8242d706f8c107f63a91c3739f962868fb
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 = &other->root;
112 while (*pmhn) {
113 pmhn = &((*pmhn)->next);
115 *pmhn = root;
116 root = other->root;
117 other->root = 0;
120 LineMarkers::~LineMarkers() {
121 Init();
124 void LineMarkers::Init() {
125 for (int line = 0; line < markers.Length(); line++) {
126 delete markers[line];
127 markers[line] = 0;
129 markers.DeleteAll();
132 void LineMarkers::InsertLine(int line) {
133 if (markers.Length()) {
134 markers.Insert(line, 0);
138 void LineMarkers::RemoveLine(int line) {
139 // Retain the markers from the deleted line by oring them into the previous line
140 if (markers.Length()) {
141 if (line > 0) {
142 MergeMarkers(line - 1);
144 markers.Delete(line);
148 int LineMarkers::LineFromHandle(int markerHandle) {
149 if (markers.Length()) {
150 for (int line = 0; line < markers.Length(); line++) {
151 if (markers[line]) {
152 if (markers[line]->Contains(markerHandle)) {
153 return line;
158 return -1;
161 void LineMarkers::MergeMarkers(int pos) {
162 if (markers[pos + 1] != NULL) {
163 if (markers[pos] == NULL)
164 markers[pos] = new MarkerHandleSet;
165 markers[pos]->CombineWith(markers[pos + 1]);
166 delete markers[pos + 1];
167 markers[pos + 1] = NULL;
171 int LineMarkers::MarkValue(int line) {
172 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line])
173 return markers[line]->MarkValue();
174 else
175 return 0;
178 int LineMarkers::MarkerNext(int lineStart, int mask) const {
179 if (lineStart < 0)
180 lineStart = 0;
181 int length = markers.Length();
182 for (int iLine = lineStart; iLine < length; iLine++) {
183 MarkerHandleSet *onLine = markers[iLine];
184 if (onLine && ((onLine->MarkValue() & mask) != 0))
185 //if ((pdoc->GetMark(iLine) & lParam) != 0)
186 return iLine;
188 return -1;
191 int LineMarkers::AddMark(int line, int markerNum, int lines) {
192 handleCurrent++;
193 if (!markers.Length()) {
194 // No existing markers so allocate one element per line
195 markers.InsertValue(0, lines, 0);
197 if (line >= markers.Length()) {
198 return -1;
200 if (!markers[line]) {
201 // Need new structure to hold marker handle
202 markers[line] = new MarkerHandleSet();
204 markers[line]->InsertHandle(handleCurrent, markerNum);
206 return handleCurrent;
209 bool LineMarkers::DeleteMark(int line, int markerNum, bool all) {
210 bool someChanges = false;
211 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) {
212 if (markerNum == -1) {
213 someChanges = true;
214 delete markers[line];
215 markers[line] = NULL;
216 } else {
217 someChanges = markers[line]->RemoveNumber(markerNum, all);
218 if (markers[line]->Length() == 0) {
219 delete markers[line];
220 markers[line] = NULL;
224 return someChanges;
227 void LineMarkers::DeleteMarkFromHandle(int markerHandle) {
228 int line = LineFromHandle(markerHandle);
229 if (line >= 0) {
230 markers[line]->RemoveHandle(markerHandle);
231 if (markers[line]->Length() == 0) {
232 delete markers[line];
233 markers[line] = NULL;
238 LineLevels::~LineLevels() {
241 void LineLevels::Init() {
242 levels.DeleteAll();
245 void LineLevels::InsertLine(int line) {
246 if (levels.Length()) {
247 int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE;
248 levels.InsertValue(line, 1, level);
252 void LineLevels::RemoveLine(int line) {
253 if (levels.Length()) {
254 // Move up following lines but merge header flag from this line
255 // to line before to avoid a temporary disappearence causing expansion.
256 int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG;
257 levels.Delete(line);
258 if (line == levels.Length()-1) // Last line loses the header flag
259 levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG;
260 else if (line > 0)
261 levels[line-1] |= firstHeader;
265 void LineLevels::ExpandLevels(int sizeNew) {
266 levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
269 void LineLevels::ClearLevels() {
270 levels.DeleteAll();
273 int LineLevels::SetLevel(int line, int level, int lines) {
274 int prev = 0;
275 if ((line >= 0) && (line < lines)) {
276 if (!levels.Length()) {
277 ExpandLevels(lines + 1);
279 prev = levels[line];
280 if (prev != level) {
281 levels[line] = level;
284 return prev;
287 int LineLevels::GetLevel(int line) const {
288 if (levels.Length() && (line >= 0) && (line < levels.Length())) {
289 return levels[line];
290 } else {
291 return SC_FOLDLEVELBASE;
295 LineState::~LineState() {
298 void LineState::Init() {
299 lineStates.DeleteAll();
302 void LineState::InsertLine(int line) {
303 if (lineStates.Length()) {
304 lineStates.EnsureLength(line);
305 int val = (line < lineStates.Length()) ? lineStates[line] : 0;
306 lineStates.Insert(line, val);
310 void LineState::RemoveLine(int line) {
311 if (lineStates.Length() > line) {
312 lineStates.Delete(line);
316 int LineState::SetLineState(int line, int state) {
317 lineStates.EnsureLength(line + 1);
318 int stateOld = lineStates[line];
319 lineStates[line] = state;
320 return stateOld;
323 int LineState::GetLineState(int line) {
324 if (line < 0)
325 return 0;
326 lineStates.EnsureLength(line + 1);
327 return lineStates[line];
330 int LineState::GetMaxLineState() const {
331 return lineStates.Length();
334 static int NumberLines(const char *text) {
335 if (text) {
336 int newLines = 0;
337 while (*text) {
338 if (*text == '\n')
339 newLines++;
340 text++;
342 return newLines+1;
343 } else {
344 return 0;
348 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
349 // and then has text and optional styles.
351 static const int IndividualStyles = 0x100;
353 struct AnnotationHeader {
354 short style; // Style IndividualStyles implies array of styles
355 short lines;
356 int length;
359 LineAnnotation::~LineAnnotation() {
360 ClearAll();
363 void LineAnnotation::Init() {
364 ClearAll();
367 void LineAnnotation::InsertLine(int line) {
368 if (annotations.Length()) {
369 annotations.EnsureLength(line);
370 annotations.Insert(line, 0);
374 void LineAnnotation::RemoveLine(int line) {
375 if (annotations.Length() && (line > 0) && (line <= annotations.Length())) {
376 delete []annotations[line-1];
377 annotations.Delete(line-1);
381 bool LineAnnotation::MultipleStyles(int line) const {
382 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
383 return reinterpret_cast<AnnotationHeader *>(annotations[line])->style == IndividualStyles;
384 else
385 return 0;
388 int LineAnnotation::Style(int line) const {
389 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
390 return reinterpret_cast<AnnotationHeader *>(annotations[line])->style;
391 else
392 return 0;
395 const char *LineAnnotation::Text(int line) const {
396 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
397 return annotations[line]+sizeof(AnnotationHeader);
398 else
399 return 0;
402 const unsigned char *LineAnnotation::Styles(int line) const {
403 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line] && MultipleStyles(line))
404 return reinterpret_cast<unsigned char *>(annotations[line] + sizeof(AnnotationHeader) + Length(line));
405 else
406 return 0;
409 static char *AllocateAnnotation(int length, int style) {
410 size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0);
411 char *ret = new char[len];
412 memset(ret, 0, len);
413 return ret;
416 void LineAnnotation::SetText(int line, const char *text) {
417 if (text && (line >= 0)) {
418 annotations.EnsureLength(line+1);
419 int style = Style(line);
420 if (annotations[line]) {
421 delete []annotations[line];
423 annotations[line] = AllocateAnnotation(static_cast<int>(strlen(text)), style);
424 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
425 pah->style = static_cast<short>(style);
426 pah->length = static_cast<int>(strlen(text));
427 pah->lines = static_cast<short>(NumberLines(text));
428 memcpy(annotations[line]+sizeof(AnnotationHeader), text, pah->length);
429 } else {
430 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) {
431 delete []annotations[line];
432 annotations[line] = 0;
437 void LineAnnotation::ClearAll() {
438 for (int line = 0; line < annotations.Length(); line++) {
439 delete []annotations[line];
440 annotations[line] = 0;
442 annotations.DeleteAll();
445 void LineAnnotation::SetStyle(int line, int style) {
446 annotations.EnsureLength(line+1);
447 if (!annotations[line]) {
448 annotations[line] = AllocateAnnotation(0, style);
450 reinterpret_cast<AnnotationHeader *>(annotations[line])->style = static_cast<short>(style);
453 void LineAnnotation::SetStyles(int line, const unsigned char *styles) {
454 if (line >= 0) {
455 annotations.EnsureLength(line+1);
456 if (!annotations[line]) {
457 annotations[line] = AllocateAnnotation(0, IndividualStyles);
458 } else {
459 AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line]);
460 if (pahSource->style != IndividualStyles) {
461 char *allocation = AllocateAnnotation(pahSource->length, IndividualStyles);
462 AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation);
463 pahAlloc->length = pahSource->length;
464 pahAlloc->lines = pahSource->lines;
465 memcpy(allocation + sizeof(AnnotationHeader), annotations[line] + sizeof(AnnotationHeader), pahSource->length);
466 delete []annotations[line];
467 annotations[line] = allocation;
470 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
471 pah->style = IndividualStyles;
472 memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length);
476 int LineAnnotation::Length(int line) const {
477 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
478 return reinterpret_cast<AnnotationHeader *>(annotations[line])->length;
479 else
480 return 0;
483 int LineAnnotation::Lines(int line) const {
484 if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
485 return reinterpret_cast<AnnotationHeader *>(annotations[line])->lines;
486 else
487 return 0;
490 LineTabstops::~LineTabstops() {
491 Init();
494 void LineTabstops::Init() {
495 for (int line = 0; line < tabstops.Length(); line++) {
496 delete tabstops[line];
498 tabstops.DeleteAll();
501 void LineTabstops::InsertLine(int line) {
502 if (tabstops.Length()) {
503 tabstops.EnsureLength(line);
504 tabstops.Insert(line, 0);
508 void LineTabstops::RemoveLine(int line) {
509 if (tabstops.Length() > line) {
510 delete tabstops[line];
511 tabstops.Delete(line);
515 bool LineTabstops::ClearTabstops(int line) {
516 if (line < tabstops.Length()) {
517 TabstopList *tl = tabstops[line];
518 if (tl) {
519 tl->clear();
520 return true;
523 return false;
526 bool LineTabstops::AddTabstop(int line, int x) {
527 tabstops.EnsureLength(line + 1);
528 if (!tabstops[line]) {
529 tabstops[line] = new TabstopList();
532 TabstopList *tl = tabstops[line];
533 if (tl) {
534 // tabstop positions are kept in order - insert in the right place
535 std::vector<int>::iterator it = std::lower_bound(tl->begin(), tl->end(), x);
536 // don't insert duplicates
537 if (it == tl->end() || *it != x) {
538 tl->insert(it, x);
539 return true;
542 return false;
545 int LineTabstops::GetNextTabstop(int line, int x) const {
546 if (line < tabstops.Length()) {
547 TabstopList *tl = tabstops[line];
548 if (tl) {
549 for (size_t i = 0; i < tl->size(); i++) {
550 if ((*tl)[i] > x) {
551 return (*tl)[i];
556 return 0;