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.
7
8 #include <string.h>
9
10 #include <vector>
11 #include <algorithm>
12
13 #include "Platform.h"
14
15 #include "Scintilla.h"
16 #include "SplitVector.h"
17 #include "Partitioning.h"
18 #include "CellBuffer.h"
19 #include "PerLine.h"
20
21 #ifdef SCI_NAMESPACE
22 using namespace Scintilla;
23 #endif
24
MarkerHandleSet()25 MarkerHandleSet::MarkerHandleSet() {
26 root = 0;
27 }
28
~MarkerHandleSet()29 MarkerHandleSet::~MarkerHandleSet() {
30 MarkerHandleNumber *mhn = root;
31 while (mhn) {
32 MarkerHandleNumber *mhnToFree = mhn;
33 mhn = mhn->next;
34 delete mhnToFree;
35 }
36 root = 0;
37 }
38
Length() const39 int MarkerHandleSet::Length() const {
40 int c = 0;
41 MarkerHandleNumber *mhn = root;
42 while (mhn) {
43 c++;
44 mhn = mhn->next;
45 }
46 return c;
47 }
48
MarkValue() const49 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;
55 }
56 return m;
57 }
58
Contains(int handle) const59 bool MarkerHandleSet::Contains(int handle) const {
60 MarkerHandleNumber *mhn = root;
61 while (mhn) {
62 if (mhn->handle == handle) {
63 return true;
64 }
65 mhn = mhn->next;
66 }
67 return false;
68 }
69
InsertHandle(int handle,int markerNum)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;
77 }
78
RemoveHandle(int handle)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;
87 }
88 pmhn = &((*pmhn)->next);
89 }
90 }
91
RemoveNumber(int markerNum,bool all)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);
105 }
106 }
107 return performedDeletion;
108 }
109
CombineWith(MarkerHandleSet * other)110 void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
111 MarkerHandleNumber **pmhn = &root;
112 while (*pmhn) {
113 pmhn = &((*pmhn)->next);
114 }
115 *pmhn = other->root;
116 other->root = 0;
117 }
118
~LineMarkers()119 LineMarkers::~LineMarkers() {
120 Init();
121 }
122
Init()123 void LineMarkers::Init() {
124 for (int line = 0; line < markers.Length(); line++) {
125 delete markers[line];
126 markers[line] = 0;
127 }
128 markers.DeleteAll();
129 }
130
InsertLine(int line)131 void LineMarkers::InsertLine(int line) {
132 if (markers.Length()) {
133 markers.Insert(line, 0);
134 }
135 }
136
RemoveLine(int line)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);
142 }
143 markers.Delete(line);
144 }
145 }
146
LineFromHandle(int markerHandle)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;
153 }
154 }
155 }
156 }
157 return -1;
158 }
159
MergeMarkers(int pos)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;
167 }
168 }
169
MarkValue(int line)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;
175 }
176
MarkerNext(int lineStart,int mask) const177 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;
186 }
187 return -1;
188 }
189
AddMark(int line,int markerNum,int lines)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);
195 }
196 if (line >= markers.Length()) {
197 return -1;
198 }
199 if (!markers[line]) {
200 // Need new structure to hold marker handle
201 markers[line] = new MarkerHandleSet();
202 }
203 markers[line]->InsertHandle(handleCurrent, markerNum);
204
205 return handleCurrent;
206 }
207
DeleteMark(int line,int markerNum,bool all)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;
220 }
221 }
222 }
223 return someChanges;
224 }
225
DeleteMarkFromHandle(int markerHandle)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;
233 }
234 }
235 }
236
~LineLevels()237 LineLevels::~LineLevels() {
238 }
239
Init()240 void LineLevels::Init() {
241 levels.DeleteAll();
242 }
243
InsertLine(int line)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);
248 }
249 }
250
RemoveLine(int line)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;
261 }
262 }
263
ExpandLevels(int sizeNew)264 void LineLevels::ExpandLevels(int sizeNew) {
265 levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
266 }
267
ClearLevels()268 void LineLevels::ClearLevels() {
269 levels.DeleteAll();
270 }
271
SetLevel(int line,int level,int lines)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);
277 }
278 prev = levels[line];
279 if (prev != level) {
280 levels[line] = level;
281 }
282 }
283 return prev;
284 }
285
GetLevel(int line) const286 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;
291 }
292 }
293
~LineState()294 LineState::~LineState() {
295 }
296
Init()297 void LineState::Init() {
298 lineStates.DeleteAll();
299 }
300
InsertLine(int line)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);
306 }
307 }
308
RemoveLine(int line)309 void LineState::RemoveLine(int line) {
310 if (lineStates.Length() > line) {
311 lineStates.Delete(line);
312 }
313 }
314
SetLineState(int line,int state)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;
320 }
321
GetLineState(int line)322 int LineState::GetLineState(int line) {
323 if (line < 0)
324 return 0;
325 lineStates.EnsureLength(line + 1);
326 return lineStates[line];
327 }
328
GetMaxLineState() const329 int LineState::GetMaxLineState() const {
330 return lineStates.Length();
331 }
332
NumberLines(const char * text)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++;
340 }
341 return newLines+1;
342 } else {
343 return 0;
344 }
345 }
346
347 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
348 // and then has text and optional styles.
349
350 static const int IndividualStyles = 0x100;
351
352 struct AnnotationHeader {
353 short style; // Style IndividualStyles implies array of styles
354 short lines;
355 int length;
356 };
357
~LineAnnotation()358 LineAnnotation::~LineAnnotation() {
359 ClearAll();
360 }
361
Init()362 void LineAnnotation::Init() {
363 ClearAll();
364 }
365
InsertLine(int line)366 void LineAnnotation::InsertLine(int line) {
367 if (annotations.Length()) {
368 annotations.EnsureLength(line);
369 annotations.Insert(line, 0);
370 }
371 }
372
RemoveLine(int line)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);
377 }
378 }
379
MultipleStyles(int line) const380 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;
385 }
386
Style(int line) const387 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;
392 }
393
Text(int line) const394 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;
399 }
400
Styles(int line) const401 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;
406 }
407
AllocateAnnotation(int length,int style)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;
413 }
414
SetText(int line,const char * text)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];
421 }
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;
432 }
433 }
434 }
435
ClearAll()436 void LineAnnotation::ClearAll() {
437 for (int line = 0; line < annotations.Length(); line++) {
438 delete []annotations[line];
439 annotations[line] = 0;
440 }
441 annotations.DeleteAll();
442 }
443
SetStyle(int line,int style)444 void LineAnnotation::SetStyle(int line, int style) {
445 annotations.EnsureLength(line+1);
446 if (!annotations[line]) {
447 annotations[line] = AllocateAnnotation(0, style);
448 }
449 reinterpret_cast<AnnotationHeader *>(annotations[line])->style = static_cast<short>(style);
450 }
451
SetStyles(int line,const unsigned char * styles)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;
467 }
468 }
469 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
470 pah->style = IndividualStyles;
471 memcpy(annotations[line] + sizeof(AnnotationHeader) + pah->length, styles, pah->length);
472 }
473 }
474
Length(int line) const475 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;
480 }
481
Lines(int line) const482 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;
487 }
488
~LineTabstops()489 LineTabstops::~LineTabstops() {
490 Init();
491 }
492
Init()493 void LineTabstops::Init() {
494 for (int line = 0; line < tabstops.Length(); line++) {
495 delete tabstops[line];
496 }
497 tabstops.DeleteAll();
498 }
499
InsertLine(int line)500 void LineTabstops::InsertLine(int line) {
501 if (tabstops.Length()) {
502 tabstops.EnsureLength(line);
503 tabstops.Insert(line, 0);
504 }
505 }
506
RemoveLine(int line)507 void LineTabstops::RemoveLine(int line) {
508 if (tabstops.Length() > line) {
509 delete tabstops[line];
510 tabstops.Delete(line);
511 }
512 }
513
ClearTabstops(int 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;
520 }
521 }
522 return false;
523 }
524
AddTabstop(int line,int x)525 bool LineTabstops::AddTabstop(int line, int x) {
526 tabstops.EnsureLength(line + 1);
527 if (!tabstops[line]) {
528 tabstops[line] = new TabstopList();
529 }
530
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;
539 }
540 }
541 return false;
542 }
543
GetNextTabstop(int line,int x) const544 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];
551 }
552 }
553 }
554 }
555 return 0;
556 }
557