r5116 | eht16 | 2010-08-05 22:13:47 +0100 (Thu, 05 Aug 2010) | 3 lines
[geany-mirror.git] / scintilla / PerLine.cxx
bloba19c117bc4d0ec8813341173a9319103511dcd3d
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 "Platform.h"
12 #include "Scintilla.h"
13 #include "SplitVector.h"
14 #include "Partitioning.h"
15 #include "CellBuffer.h"
16 #include "PerLine.h"
18 #ifdef SCI_NAMESPACE
19 using namespace Scintilla;
20 #endif
22 MarkerHandleSet::MarkerHandleSet() {
23 root = 0;
26 MarkerHandleSet::~MarkerHandleSet() {
27 MarkerHandleNumber *mhn = root;
28 while (mhn) {
29 MarkerHandleNumber *mhnToFree = mhn;
30 mhn = mhn->next;
31 delete mhnToFree;
33 root = 0;
36 int MarkerHandleSet::Length() const {
37 int c = 0;
38 MarkerHandleNumber *mhn = root;
39 while (mhn) {
40 c++;
41 mhn = mhn->next;
43 return c;
46 int MarkerHandleSet::NumberFromHandle(int handle) const {
47 MarkerHandleNumber *mhn = root;
48 while (mhn) {
49 if (mhn->handle == handle) {
50 return mhn->number;
52 mhn = mhn->next;
54 return - 1;
57 int MarkerHandleSet::MarkValue() const {
58 unsigned int m = 0;
59 MarkerHandleNumber *mhn = root;
60 while (mhn) {
61 m |= (1 << mhn->number);
62 mhn = mhn->next;
64 return m;
67 bool MarkerHandleSet::Contains(int handle) const {
68 MarkerHandleNumber *mhn = root;
69 while (mhn) {
70 if (mhn->handle == handle) {
71 return true;
73 mhn = mhn->next;
75 return false;
78 bool MarkerHandleSet::InsertHandle(int handle, int markerNum) {
79 MarkerHandleNumber *mhn = new MarkerHandleNumber;
80 if (!mhn)
81 return false;
82 mhn->handle = handle;
83 mhn->number = markerNum;
84 mhn->next = root;
85 root = mhn;
86 return true;
89 void MarkerHandleSet::RemoveHandle(int handle) {
90 MarkerHandleNumber **pmhn = &root;
91 while (*pmhn) {
92 MarkerHandleNumber *mhn = *pmhn;
93 if (mhn->handle == handle) {
94 *pmhn = mhn->next;
95 delete mhn;
96 return;
98 pmhn = &((*pmhn)->next);
102 bool MarkerHandleSet::RemoveNumber(int markerNum) {
103 bool performedDeletion = false;
104 MarkerHandleNumber **pmhn = &root;
105 while (*pmhn) {
106 MarkerHandleNumber *mhn = *pmhn;
107 if (mhn->number == markerNum) {
108 *pmhn = mhn->next;
109 delete mhn;
110 performedDeletion = true;
111 } else {
112 pmhn = &((*pmhn)->next);
115 return performedDeletion;
118 void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
119 MarkerHandleNumber **pmhn = &root;
120 while (*pmhn) {
121 pmhn = &((*pmhn)->next);
123 *pmhn = other->root;
124 other->root = 0;
127 LineMarkers::~LineMarkers() {
128 Init();
131 void LineMarkers::Init() {
132 for (int line = 0; line < markers.Length(); line++) {
133 delete markers[line];
134 markers[line] = 0;
136 markers.DeleteAll();
139 void LineMarkers::InsertLine(int line) {
140 if (markers.Length()) {
141 markers.Insert(line, 0);
145 void LineMarkers::RemoveLine(int line) {
146 // Retain the markers from the deleted line by oring them into the previous line
147 if (markers.Length()) {
148 if (line > 0) {
149 MergeMarkers(line - 1);
151 markers.Delete(line);
155 int LineMarkers::LineFromHandle(int markerHandle) {
156 if (markers.Length()) {
157 for (int line = 0; line < markers.Length(); line++) {
158 if (markers[line]) {
159 if (markers[line]->Contains(markerHandle)) {
160 return line;
165 return -1;
168 void LineMarkers::MergeMarkers(int pos) {
169 if (markers[pos + 1] != NULL) {
170 if (markers[pos] == NULL)
171 markers[pos] = new MarkerHandleSet;
172 markers[pos]->CombineWith(markers[pos + 1]);
173 delete markers[pos + 1];
174 markers[pos + 1] = NULL;
178 int LineMarkers::MarkValue(int line) {
179 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line])
180 return markers[line]->MarkValue();
181 else
182 return 0;
185 int LineMarkers::AddMark(int line, int markerNum, int lines) {
186 handleCurrent++;
187 if (!markers.Length()) {
188 // No existing markers so allocate one element per line
189 markers.InsertValue(0, lines, 0);
191 if (line >= markers.Length()) {
192 return -1;
194 if (!markers[line]) {
195 // Need new structure to hold marker handle
196 markers[line] = new MarkerHandleSet();
197 if (!markers[line])
198 return -1;
200 markers[line]->InsertHandle(handleCurrent, markerNum);
202 return handleCurrent;
205 void LineMarkers::DeleteMark(int line, int markerNum, bool all) {
206 if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) {
207 if (markerNum == -1) {
208 delete markers[line];
209 markers[line] = NULL;
210 } else {
211 bool performedDeletion = markers[line]->RemoveNumber(markerNum);
212 while (all && performedDeletion) {
213 performedDeletion = markers[line]->RemoveNumber(markerNum);
215 if (markers[line]->Length() == 0) {
216 delete markers[line];
217 markers[line] = NULL;
223 void LineMarkers::DeleteMarkFromHandle(int markerHandle) {
224 int line = LineFromHandle(markerHandle);
225 if (line >= 0) {
226 markers[line]->RemoveHandle(markerHandle);
227 if (markers[line]->Length() == 0) {
228 delete markers[line];
229 markers[line] = NULL;
234 LineLevels::~LineLevels() {
237 void LineLevels::Init() {
238 levels.DeleteAll();
241 void LineLevels::InsertLine(int line) {
242 if (levels.Length()) {
243 int level = SC_FOLDLEVELBASE;
244 if ((line > 0) && (line < levels.Length())) {
245 level = levels[line-1] & ~SC_FOLDLEVELWHITEFLAG;
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) {
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 lineStates.Insert(line, 0);
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 lineStates.EnsureLength(line + 1);
323 return lineStates[line];
326 int LineState::GetMaxLineState() {
327 return lineStates.Length();
330 static int NumberLines(const char *text) {
331 if (text) {
332 int newLines = 0;
333 while (*text) {
334 if (*text == '\n')
335 newLines++;
336 text++;
338 return newLines+1;
339 } else {
340 return 0;
344 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
345 // and then has text and optional styles.
347 static const int IndividualStyles = 0x100;
349 struct AnnotationHeader {
350 short style; // Style IndividualStyles implies array of styles
351 short lines;
352 int length;
355 LineAnnotation::~LineAnnotation() {
356 ClearAll();
359 void LineAnnotation::Init() {
360 ClearAll();
363 void LineAnnotation::InsertLine(int line) {
364 if (annotations.Length()) {
365 annotations.EnsureLength(line);
366 annotations.Insert(line, 0);
370 void LineAnnotation::RemoveLine(int line) {
371 if (annotations.Length() && (line < annotations.Length())) {
372 delete []annotations[line];
373 annotations.Delete(line);
377 bool LineAnnotation::AnySet() const {
378 return annotations.Length() > 0;
381 bool LineAnnotation::MultipleStyles(int line) const {
382 if (annotations.Length() && (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) {
389 if (annotations.Length() && (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 < 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 < 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) {
418 annotations.EnsureLength(line+1);
419 int style = Style(line);
420 if (annotations[line]) {
421 delete []annotations[line];
423 annotations[line] = AllocateAnnotation(strlen(text), style);
424 AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line]);
425 pah->style = static_cast<short>(style);
426 pah->length = 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 < 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 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);
474 int LineAnnotation::Length(int line) const {
475 if (annotations.Length() && (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 < annotations.Length()) && annotations[line])
483 return reinterpret_cast<AnnotationHeader *>(annotations[line])->lines;
484 else
485 return 0;