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