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 <cstddef>
9 #include <cassert>
10 #include <cstring>
11 
12 #include <stdexcept>
13 #include <string_view>
14 #include <vector>
15 #include <forward_list>
16 #include <algorithm>
17 #include <memory>
18 
19 #include "Platform.h"
20 
21 #include "Scintilla.h"
22 #include "Position.h"
23 #include "SplitVector.h"
24 #include "Partitioning.h"
25 #include "CellBuffer.h"
26 #include "PerLine.h"
27 
28 using namespace Scintilla;
29 
MarkerHandleSet()30 MarkerHandleSet::MarkerHandleSet() {
31 }
32 
~MarkerHandleSet()33 MarkerHandleSet::~MarkerHandleSet() {
34 	mhList.clear();
35 }
36 
Empty() const37 bool MarkerHandleSet::Empty() const noexcept {
38 	return mhList.empty();
39 }
40 
MarkValue() const41 int MarkerHandleSet::MarkValue() const noexcept {
42 	unsigned int m = 0;
43 	for (const MarkerHandleNumber &mhn : mhList) {
44 		m |= (1 << mhn.number);
45 	}
46 	return m;
47 }
48 
Contains(int handle) const49 bool MarkerHandleSet::Contains(int handle) const noexcept {
50 	for (const MarkerHandleNumber &mhn : mhList) {
51 		if (mhn.handle == handle) {
52 			return true;
53 		}
54 	}
55 	return false;
56 }
57 
InsertHandle(int handle,int markerNum)58 bool MarkerHandleSet::InsertHandle(int handle, int markerNum) {
59 	mhList.push_front(MarkerHandleNumber(handle, markerNum));
60 	return true;
61 }
62 
RemoveHandle(int handle)63 void MarkerHandleSet::RemoveHandle(int handle) {
64 	mhList.remove_if([handle](const MarkerHandleNumber &mhn) { return mhn.handle == handle; });
65 }
66 
RemoveNumber(int markerNum,bool all)67 bool MarkerHandleSet::RemoveNumber(int markerNum, bool all) {
68 	bool performedDeletion = false;
69 	mhList.remove_if([&](const MarkerHandleNumber &mhn) {
70 		if ((all || !performedDeletion) && (mhn.number == markerNum)) {
71 			performedDeletion = true;
72 			return true;
73 		}
74 		return false;
75 	});
76 	return performedDeletion;
77 }
78 
CombineWith(MarkerHandleSet * other)79 void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
80 	mhList.splice_after(mhList.before_begin(), other->mhList);
81 }
82 
~LineMarkers()83 LineMarkers::~LineMarkers() {
84 }
85 
Init()86 void LineMarkers::Init() {
87 	markers.DeleteAll();
88 }
89 
InsertLine(Sci::Line line)90 void LineMarkers::InsertLine(Sci::Line line) {
91 	if (markers.Length()) {
92 		markers.Insert(line, 0);
93 	}
94 }
95 
RemoveLine(Sci::Line line)96 void LineMarkers::RemoveLine(Sci::Line line) {
97 	// Retain the markers from the deleted line by oring them into the previous line
98 	if (markers.Length()) {
99 		if (line > 0) {
100 			MergeMarkers(line - 1);
101 		}
102 		markers.Delete(line);
103 	}
104 }
105 
LineFromHandle(int markerHandle)106 Sci::Line LineMarkers::LineFromHandle(int markerHandle) {
107 	if (markers.Length()) {
108 		for (Sci::Line line = 0; line < markers.Length(); line++) {
109 			if (markers[line]) {
110 				if (markers[line]->Contains(markerHandle)) {
111 					return line;
112 				}
113 			}
114 		}
115 	}
116 	return -1;
117 }
118 
MergeMarkers(Sci::Line line)119 void LineMarkers::MergeMarkers(Sci::Line line) {
120 	if (markers[line + 1]) {
121 		if (!markers[line])
122 			markers[line] = std::make_unique<MarkerHandleSet>();
123 		markers[line]->CombineWith(markers[line + 1].get());
124 		markers[line + 1].reset();
125 	}
126 }
127 
MarkValue(Sci::Line line)128 int LineMarkers::MarkValue(Sci::Line line) noexcept {
129 	if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line])
130 		return markers[line]->MarkValue();
131 	else
132 		return 0;
133 }
134 
MarkerNext(Sci::Line lineStart,int mask) const135 Sci::Line LineMarkers::MarkerNext(Sci::Line lineStart, int mask) const {
136 	if (lineStart < 0)
137 		lineStart = 0;
138 	const Sci::Line length = static_cast<Sci::Line>(markers.Length());
139 	for (Sci::Line iLine = lineStart; iLine < length; iLine++) {
140 		const MarkerHandleSet *onLine = markers[iLine].get();
141 		if (onLine && ((onLine->MarkValue() & mask) != 0))
142 			return iLine;
143 	}
144 	return -1;
145 }
146 
AddMark(Sci::Line line,int markerNum,Sci::Line lines)147 int LineMarkers::AddMark(Sci::Line line, int markerNum, Sci::Line lines) {
148 	handleCurrent++;
149 	if (!markers.Length()) {
150 		// No existing markers so allocate one element per line
151 		markers.InsertEmpty(0, lines);
152 	}
153 	if (line >= markers.Length()) {
154 		return -1;
155 	}
156 	if (!markers[line]) {
157 		// Need new structure to hold marker handle
158 		markers[line] = std::make_unique<MarkerHandleSet>();
159 	}
160 	markers[line]->InsertHandle(handleCurrent, markerNum);
161 
162 	return handleCurrent;
163 }
164 
DeleteMark(Sci::Line line,int markerNum,bool all)165 bool LineMarkers::DeleteMark(Sci::Line line, int markerNum, bool all) {
166 	bool someChanges = false;
167 	if (markers.Length() && (line >= 0) && (line < markers.Length()) && markers[line]) {
168 		if (markerNum == -1) {
169 			someChanges = true;
170 			markers[line].reset();
171 		} else {
172 			someChanges = markers[line]->RemoveNumber(markerNum, all);
173 			if (markers[line]->Empty()) {
174 				markers[line].reset();
175 			}
176 		}
177 	}
178 	return someChanges;
179 }
180 
DeleteMarkFromHandle(int markerHandle)181 void LineMarkers::DeleteMarkFromHandle(int markerHandle) {
182 	const Sci::Line line = LineFromHandle(markerHandle);
183 	if (line >= 0) {
184 		markers[line]->RemoveHandle(markerHandle);
185 		if (markers[line]->Empty()) {
186 			markers[line].reset();
187 		}
188 	}
189 }
190 
~LineLevels()191 LineLevels::~LineLevels() {
192 }
193 
Init()194 void LineLevels::Init() {
195 	levels.DeleteAll();
196 }
197 
InsertLine(Sci::Line line)198 void LineLevels::InsertLine(Sci::Line line) {
199 	if (levels.Length()) {
200 		const int level = (line < levels.Length()) ? levels[line] : SC_FOLDLEVELBASE;
201 		levels.InsertValue(line, 1, level);
202 	}
203 }
204 
RemoveLine(Sci::Line line)205 void LineLevels::RemoveLine(Sci::Line line) {
206 	if (levels.Length()) {
207 		// Move up following lines but merge header flag from this line
208 		// to line before to avoid a temporary disappearence causing expansion.
209 		int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG;
210 		levels.Delete(line);
211 		if (line == levels.Length()-1) // Last line loses the header flag
212 			levels[line-1] &= ~SC_FOLDLEVELHEADERFLAG;
213 		else if (line > 0)
214 			levels[line-1] |= firstHeader;
215 	}
216 }
217 
ExpandLevels(Sci::Line sizeNew)218 void LineLevels::ExpandLevels(Sci::Line sizeNew) {
219 	levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
220 }
221 
ClearLevels()222 void LineLevels::ClearLevels() {
223 	levels.DeleteAll();
224 }
225 
SetLevel(Sci::Line line,int level,Sci::Line lines)226 int LineLevels::SetLevel(Sci::Line line, int level, Sci::Line lines) {
227 	int prev = 0;
228 	if ((line >= 0) && (line < lines)) {
229 		if (!levels.Length()) {
230 			ExpandLevels(lines + 1);
231 		}
232 		prev = levels[line];
233 		if (prev != level) {
234 			levels[line] = level;
235 		}
236 	}
237 	return prev;
238 }
239 
GetLevel(Sci::Line line) const240 int LineLevels::GetLevel(Sci::Line line) const {
241 	if (levels.Length() && (line >= 0) && (line < levels.Length())) {
242 		return levels[line];
243 	} else {
244 		return SC_FOLDLEVELBASE;
245 	}
246 }
247 
~LineState()248 LineState::~LineState() {
249 }
250 
Init()251 void LineState::Init() {
252 	lineStates.DeleteAll();
253 }
254 
InsertLine(Sci::Line line)255 void LineState::InsertLine(Sci::Line line) {
256 	if (lineStates.Length()) {
257 		lineStates.EnsureLength(line);
258 		const int val = (line < lineStates.Length()) ? lineStates[line] : 0;
259 		lineStates.Insert(line, val);
260 	}
261 }
262 
RemoveLine(Sci::Line line)263 void LineState::RemoveLine(Sci::Line line) {
264 	if (lineStates.Length() > line) {
265 		lineStates.Delete(line);
266 	}
267 }
268 
SetLineState(Sci::Line line,int state)269 int LineState::SetLineState(Sci::Line line, int state) {
270 	lineStates.EnsureLength(line + 1);
271 	const int stateOld = lineStates[line];
272 	lineStates[line] = state;
273 	return stateOld;
274 }
275 
GetLineState(Sci::Line line)276 int LineState::GetLineState(Sci::Line line) {
277 	if (line < 0)
278 		return 0;
279 	lineStates.EnsureLength(line + 1);
280 	return lineStates[line];
281 }
282 
GetMaxLineState() const283 Sci::Line LineState::GetMaxLineState() const {
284 	return static_cast<Sci::Line>(lineStates.Length());
285 }
286 
NumberLines(const char * text)287 static int NumberLines(const char *text) noexcept {
288 	if (text) {
289 		int newLines = 0;
290 		while (*text) {
291 			if (*text == '\n')
292 				newLines++;
293 			text++;
294 		}
295 		return newLines+1;
296 	} else {
297 		return 0;
298 	}
299 }
300 
301 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
302 // and then has text and optional styles.
303 
304 static const int IndividualStyles = 0x100;
305 
306 struct AnnotationHeader {
307 	short style;	// Style IndividualStyles implies array of styles
308 	short lines;
309 	int length;
310 };
311 
~LineAnnotation()312 LineAnnotation::~LineAnnotation() {
313 }
314 
Init()315 void LineAnnotation::Init() {
316 	ClearAll();
317 }
318 
InsertLine(Sci::Line line)319 void LineAnnotation::InsertLine(Sci::Line line) {
320 	if (annotations.Length()) {
321 		annotations.EnsureLength(line);
322 		annotations.Insert(line, std::unique_ptr<char []>());
323 	}
324 }
325 
RemoveLine(Sci::Line line)326 void LineAnnotation::RemoveLine(Sci::Line line) {
327 	if (annotations.Length() && (line > 0) && (line <= annotations.Length())) {
328 		annotations[line-1].reset();
329 		annotations.Delete(line-1);
330 	}
331 }
332 
MultipleStyles(Sci::Line line) const333 bool LineAnnotation::MultipleStyles(Sci::Line line) const {
334 	if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
335 		return reinterpret_cast<AnnotationHeader *>(annotations[line].get())->style == IndividualStyles;
336 	else
337 		return false;
338 }
339 
Style(Sci::Line line) const340 int LineAnnotation::Style(Sci::Line line) const {
341 	if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
342 		return reinterpret_cast<AnnotationHeader *>(annotations[line].get())->style;
343 	else
344 		return 0;
345 }
346 
Text(Sci::Line line) const347 const char *LineAnnotation::Text(Sci::Line line) const {
348 	if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
349 		return annotations[line].get()+sizeof(AnnotationHeader);
350 	else
351 		return nullptr;
352 }
353 
Styles(Sci::Line line) const354 const unsigned char *LineAnnotation::Styles(Sci::Line line) const {
355 	if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line] && MultipleStyles(line))
356 		return reinterpret_cast<unsigned char *>(annotations[line].get() + sizeof(AnnotationHeader) + Length(line));
357 	else
358 		return nullptr;
359 }
360 
AllocateAnnotation(int length,int style)361 static std::unique_ptr<char[]>AllocateAnnotation(int length, int style) {
362 	const size_t len = sizeof(AnnotationHeader) + length + ((style == IndividualStyles) ? length : 0);
363 	return std::make_unique<char[]>(len);
364 }
365 
SetText(Sci::Line line,const char * text)366 void LineAnnotation::SetText(Sci::Line line, const char *text) {
367 	if (text && (line >= 0)) {
368 		annotations.EnsureLength(line+1);
369 		const int style = Style(line);
370 		annotations[line] = AllocateAnnotation(static_cast<int>(strlen(text)), style);
371 		char *pa = annotations[line].get();
372 		assert(pa);
373 		AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(pa);
374 		pah->style = static_cast<short>(style);
375 		pah->length = static_cast<int>(strlen(text));
376 		pah->lines = static_cast<short>(NumberLines(text));
377 		memcpy(pa+sizeof(AnnotationHeader), text, pah->length);
378 	} else {
379 		if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line]) {
380 			annotations[line].reset();
381 		}
382 	}
383 }
384 
ClearAll()385 void LineAnnotation::ClearAll() {
386 	annotations.DeleteAll();
387 }
388 
SetStyle(Sci::Line line,int style)389 void LineAnnotation::SetStyle(Sci::Line line, int style) {
390 	annotations.EnsureLength(line+1);
391 	if (!annotations[line]) {
392 		annotations[line] = AllocateAnnotation(0, style);
393 	}
394 	reinterpret_cast<AnnotationHeader *>(annotations[line].get())->style = static_cast<short>(style);
395 }
396 
SetStyles(Sci::Line line,const unsigned char * styles)397 void LineAnnotation::SetStyles(Sci::Line line, const unsigned char *styles) {
398 	if (line >= 0) {
399 		annotations.EnsureLength(line+1);
400 		if (!annotations[line]) {
401 			annotations[line] = AllocateAnnotation(0, IndividualStyles);
402 		} else {
403 			const AnnotationHeader *pahSource = reinterpret_cast<AnnotationHeader *>(annotations[line].get());
404 			if (pahSource->style != IndividualStyles) {
405 				std::unique_ptr<char[]>allocation = AllocateAnnotation(pahSource->length, IndividualStyles);
406 				AnnotationHeader *pahAlloc = reinterpret_cast<AnnotationHeader *>(allocation.get());
407 				pahAlloc->length = pahSource->length;
408 				pahAlloc->lines = pahSource->lines;
409 				memcpy(allocation.get() + sizeof(AnnotationHeader), annotations[line].get() + sizeof(AnnotationHeader), pahSource->length);
410 				annotations[line] = std::move(allocation);
411 			}
412 		}
413 		AnnotationHeader *pah = reinterpret_cast<AnnotationHeader *>(annotations[line].get());
414 		pah->style = IndividualStyles;
415 		memcpy(annotations[line].get() + sizeof(AnnotationHeader) + pah->length, styles, pah->length);
416 	}
417 }
418 
Length(Sci::Line line) const419 int LineAnnotation::Length(Sci::Line line) const {
420 	if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
421 		return reinterpret_cast<AnnotationHeader *>(annotations[line].get())->length;
422 	else
423 		return 0;
424 }
425 
Lines(Sci::Line line) const426 int LineAnnotation::Lines(Sci::Line line) const {
427 	if (annotations.Length() && (line >= 0) && (line < annotations.Length()) && annotations[line])
428 		return reinterpret_cast<AnnotationHeader *>(annotations[line].get())->lines;
429 	else
430 		return 0;
431 }
432 
~LineTabstops()433 LineTabstops::~LineTabstops() {
434 }
435 
Init()436 void LineTabstops::Init() {
437 	tabstops.DeleteAll();
438 }
439 
InsertLine(Sci::Line line)440 void LineTabstops::InsertLine(Sci::Line line) {
441 	if (tabstops.Length()) {
442 		tabstops.EnsureLength(line);
443 		tabstops.Insert(line, nullptr);
444 	}
445 }
446 
RemoveLine(Sci::Line line)447 void LineTabstops::RemoveLine(Sci::Line line) {
448 	if (tabstops.Length() > line) {
449 		tabstops[line].reset();
450 		tabstops.Delete(line);
451 	}
452 }
453 
ClearTabstops(Sci::Line line)454 bool LineTabstops::ClearTabstops(Sci::Line line) {
455 	if (line < tabstops.Length()) {
456 		TabstopList *tl = tabstops[line].get();
457 		if (tl) {
458 			tl->clear();
459 			return true;
460 		}
461 	}
462 	return false;
463 }
464 
AddTabstop(Sci::Line line,int x)465 bool LineTabstops::AddTabstop(Sci::Line line, int x) {
466 	tabstops.EnsureLength(line + 1);
467 	if (!tabstops[line]) {
468 		tabstops[line] = std::make_unique<TabstopList>();
469 	}
470 
471 	TabstopList *tl = tabstops[line].get();
472 	if (tl) {
473 		// tabstop positions are kept in order - insert in the right place
474 		std::vector<int>::iterator it = std::lower_bound(tl->begin(), tl->end(), x);
475 		// don't insert duplicates
476 		if (it == tl->end() || *it != x) {
477 			tl->insert(it, x);
478 			return true;
479 		}
480 	}
481 	return false;
482 }
483 
GetNextTabstop(Sci::Line line,int x) const484 int LineTabstops::GetNextTabstop(Sci::Line line, int x) const {
485 	if (line < tabstops.Length()) {
486 		TabstopList *tl = tabstops[line].get();
487 		if (tl) {
488 			for (const int i : *tl) {
489 				if (i > x) {
490 					return i;
491 				}
492 			}
493 		}
494 	}
495 	return 0;
496 }
497