1 // Scintilla source code edit control
3 ** Manages data associated with each line of the document
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.
14 #include <forward_list>
20 #include "Scintilla.h"
22 #include "SplitVector.h"
23 #include "Partitioning.h"
24 #include "CellBuffer.h"
27 using namespace Scintilla
;
29 MarkerHandleSet::MarkerHandleSet() {
32 MarkerHandleSet::~MarkerHandleSet() {
36 bool MarkerHandleSet::Empty() const {
37 return mhList
.empty();
40 int MarkerHandleSet::MarkValue() const {
42 for (const MarkerHandleNumber
&mhn
: mhList
) {
43 m
|= (1 << mhn
.number
);
48 bool MarkerHandleSet::Contains(int handle
) const {
49 for (const MarkerHandleNumber
&mhn
: mhList
) {
50 if (mhn
.handle
== handle
) {
57 bool MarkerHandleSet::InsertHandle(int handle
, int markerNum
) {
58 mhList
.push_front(MarkerHandleNumber(handle
, markerNum
));
62 void MarkerHandleSet::RemoveHandle(int handle
) {
63 mhList
.remove_if([=](const MarkerHandleNumber
&mhn
) { return mhn
.handle
== handle
; });
66 bool MarkerHandleSet::RemoveNumber(int markerNum
, bool all
) {
67 bool performedDeletion
= false;
68 mhList
.remove_if([&](const MarkerHandleNumber
&mhn
) {
69 if ((all
|| !performedDeletion
) && (mhn
.number
== markerNum
)) {
70 performedDeletion
= true;
75 return performedDeletion
;
78 void MarkerHandleSet::CombineWith(MarkerHandleSet
*other
) {
79 mhList
.splice_after(mhList
.before_begin(), other
->mhList
);
82 LineMarkers::~LineMarkers() {
86 void LineMarkers::Init() {
90 void LineMarkers::InsertLine(Sci::Line line
) {
91 if (markers
.Length()) {
92 markers
.Insert(line
, 0);
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()) {
100 MergeMarkers(line
- 1);
102 markers
.Delete(line
);
106 Sci::Line
LineMarkers::LineFromHandle(int markerHandle
) {
107 if (markers
.Length()) {
108 for (Sci::Line line
= 0; line
< markers
.Length(); line
++) {
110 if (markers
[line
]->Contains(markerHandle
)) {
119 void LineMarkers::MergeMarkers(Sci::Line line
) {
120 if (markers
[line
+ 1]) {
122 markers
[line
].reset(new MarkerHandleSet
);
123 markers
[line
]->CombineWith(markers
[line
+ 1].get());
124 markers
[line
+ 1].reset();
128 int LineMarkers::MarkValue(Sci::Line line
) {
129 if (markers
.Length() && (line
>= 0) && (line
< markers
.Length()) && markers
[line
])
130 return markers
[line
]->MarkValue();
135 Sci::Line
LineMarkers::MarkerNext(Sci::Line lineStart
, int mask
) const {
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))
147 int LineMarkers::AddMark(Sci::Line line
, int markerNum
, Sci::Line lines
) {
149 if (!markers
.Length()) {
150 // No existing markers so allocate one element per line
151 markers
.InsertEmpty(0, lines
);
153 if (line
>= markers
.Length()) {
156 if (!markers
[line
]) {
157 // Need new structure to hold marker handle
158 markers
[line
].reset(new MarkerHandleSet());
160 markers
[line
]->InsertHandle(handleCurrent
, markerNum
);
162 return handleCurrent
;
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) {
170 markers
[line
].reset();
172 someChanges
= markers
[line
]->RemoveNumber(markerNum
, all
);
173 if (markers
[line
]->Empty()) {
174 markers
[line
].reset();
181 void LineMarkers::DeleteMarkFromHandle(int markerHandle
) {
182 Sci::Line line
= LineFromHandle(markerHandle
);
184 markers
[line
]->RemoveHandle(markerHandle
);
185 if (markers
[line
]->Empty()) {
186 markers
[line
].reset();
191 LineLevels::~LineLevels() {
194 void LineLevels::Init() {
198 void LineLevels::InsertLine(Sci::Line line
) {
199 if (levels
.Length()) {
200 int level
= (line
< levels
.Length()) ? levels
[line
] : SC_FOLDLEVELBASE
;
201 levels
.InsertValue(line
, 1, level
);
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
;
211 if (line
== levels
.Length()-1) // Last line loses the header flag
212 levels
[line
-1] &= ~SC_FOLDLEVELHEADERFLAG
;
214 levels
[line
-1] |= firstHeader
;
218 void LineLevels::ExpandLevels(Sci::Line sizeNew
) {
219 levels
.InsertValue(levels
.Length(), sizeNew
- levels
.Length(), SC_FOLDLEVELBASE
);
222 void LineLevels::ClearLevels() {
226 int LineLevels::SetLevel(Sci::Line line
, int level
, Sci::Line lines
) {
228 if ((line
>= 0) && (line
< lines
)) {
229 if (!levels
.Length()) {
230 ExpandLevels(lines
+ 1);
234 levels
[line
] = level
;
240 int LineLevels::GetLevel(Sci::Line line
) const {
241 if (levels
.Length() && (line
>= 0) && (line
< levels
.Length())) {
244 return SC_FOLDLEVELBASE
;
248 LineState::~LineState() {
251 void LineState::Init() {
252 lineStates
.DeleteAll();
255 void LineState::InsertLine(Sci::Line line
) {
256 if (lineStates
.Length()) {
257 lineStates
.EnsureLength(line
);
258 int val
= (line
< lineStates
.Length()) ? lineStates
[line
] : 0;
259 lineStates
.Insert(line
, val
);
263 void LineState::RemoveLine(Sci::Line line
) {
264 if (lineStates
.Length() > line
) {
265 lineStates
.Delete(line
);
269 int LineState::SetLineState(Sci::Line line
, int state
) {
270 lineStates
.EnsureLength(line
+ 1);
271 const int stateOld
= lineStates
[line
];
272 lineStates
[line
] = state
;
276 int LineState::GetLineState(Sci::Line line
) {
279 lineStates
.EnsureLength(line
+ 1);
280 return lineStates
[line
];
283 Sci::Line
LineState::GetMaxLineState() const {
284 return static_cast<Sci::Line
>(lineStates
.Length());
287 static int NumberLines(const char *text
) {
301 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
302 // and then has text and optional styles.
304 static const int IndividualStyles
= 0x100;
306 struct AnnotationHeader
{
307 short style
; // Style IndividualStyles implies array of styles
312 LineAnnotation::~LineAnnotation() {
316 void LineAnnotation::Init() {
320 void LineAnnotation::InsertLine(Sci::Line line
) {
321 if (annotations
.Length()) {
322 annotations
.EnsureLength(line
);
323 annotations
.Insert(line
, std::unique_ptr
<char []>());
327 void LineAnnotation::RemoveLine(Sci::Line line
) {
328 if (annotations
.Length() && (line
> 0) && (line
<= annotations
.Length())) {
329 annotations
[line
-1].reset();
330 annotations
.Delete(line
-1);
334 bool LineAnnotation::MultipleStyles(Sci::Line line
) const {
335 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
336 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
].get())->style
== IndividualStyles
;
341 int LineAnnotation::Style(Sci::Line line
) const {
342 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
343 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
].get())->style
;
348 const char *LineAnnotation::Text(Sci::Line line
) const {
349 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
350 return annotations
[line
].get()+sizeof(AnnotationHeader
);
355 const unsigned char *LineAnnotation::Styles(Sci::Line line
) const {
356 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
] && MultipleStyles(line
))
357 return reinterpret_cast<unsigned char *>(annotations
[line
].get() + sizeof(AnnotationHeader
) + Length(line
));
362 static char *AllocateAnnotation(int length
, int style
) {
363 const size_t len
= sizeof(AnnotationHeader
) + length
+ ((style
== IndividualStyles
) ? length
: 0);
364 char *ret
= new char[len
]();
368 void LineAnnotation::SetText(Sci::Line line
, const char *text
) {
369 if (text
&& (line
>= 0)) {
370 annotations
.EnsureLength(line
+1);
371 const int style
= Style(line
);
372 annotations
[line
].reset(AllocateAnnotation(static_cast<int>(strlen(text
)), style
));
373 char *pa
= annotations
[line
].get();
375 AnnotationHeader
*pah
= reinterpret_cast<AnnotationHeader
*>(pa
);
376 pah
->style
= static_cast<short>(style
);
377 pah
->length
= static_cast<int>(strlen(text
));
378 pah
->lines
= static_cast<short>(NumberLines(text
));
379 memcpy(pa
+sizeof(AnnotationHeader
), text
, pah
->length
);
381 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
]) {
382 annotations
[line
].reset();
387 void LineAnnotation::ClearAll() {
388 annotations
.DeleteAll();
391 void LineAnnotation::SetStyle(Sci::Line line
, int style
) {
392 annotations
.EnsureLength(line
+1);
393 if (!annotations
[line
]) {
394 annotations
[line
].reset(AllocateAnnotation(0, style
));
396 reinterpret_cast<AnnotationHeader
*>(annotations
[line
].get())->style
= static_cast<short>(style
);
399 void LineAnnotation::SetStyles(Sci::Line line
, const unsigned char *styles
) {
401 annotations
.EnsureLength(line
+1);
402 if (!annotations
[line
]) {
403 annotations
[line
].reset(AllocateAnnotation(0, IndividualStyles
));
405 AnnotationHeader
*pahSource
= reinterpret_cast<AnnotationHeader
*>(annotations
[line
].get());
406 if (pahSource
->style
!= IndividualStyles
) {
407 char *allocation
= AllocateAnnotation(pahSource
->length
, IndividualStyles
);
408 AnnotationHeader
*pahAlloc
= reinterpret_cast<AnnotationHeader
*>(allocation
);
409 pahAlloc
->length
= pahSource
->length
;
410 pahAlloc
->lines
= pahSource
->lines
;
411 memcpy(allocation
+ sizeof(AnnotationHeader
), annotations
[line
].get() + sizeof(AnnotationHeader
), pahSource
->length
);
412 annotations
[line
].reset(allocation
);
415 AnnotationHeader
*pah
= reinterpret_cast<AnnotationHeader
*>(annotations
[line
].get());
416 pah
->style
= IndividualStyles
;
417 memcpy(annotations
[line
].get() + sizeof(AnnotationHeader
) + pah
->length
, styles
, pah
->length
);
421 int LineAnnotation::Length(Sci::Line line
) const {
422 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
423 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
].get())->length
;
428 int LineAnnotation::Lines(Sci::Line line
) const {
429 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
430 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
].get())->lines
;
435 LineTabstops::~LineTabstops() {
436 tabstops
.DeleteAll();
439 void LineTabstops::Init() {
440 tabstops
.DeleteAll();
443 void LineTabstops::InsertLine(Sci::Line line
) {
444 if (tabstops
.Length()) {
445 tabstops
.EnsureLength(line
);
446 tabstops
.Insert(line
, nullptr);
450 void LineTabstops::RemoveLine(Sci::Line line
) {
451 if (tabstops
.Length() > line
) {
452 tabstops
[line
].reset();
453 tabstops
.Delete(line
);
457 bool LineTabstops::ClearTabstops(Sci::Line line
) {
458 if (line
< tabstops
.Length()) {
459 TabstopList
*tl
= tabstops
[line
].get();
468 bool LineTabstops::AddTabstop(Sci::Line line
, int x
) {
469 tabstops
.EnsureLength(line
+ 1);
470 if (!tabstops
[line
]) {
471 tabstops
[line
].reset(new TabstopList());
474 TabstopList
*tl
= tabstops
[line
].get();
476 // tabstop positions are kept in order - insert in the right place
477 std::vector
<int>::iterator it
= std::lower_bound(tl
->begin(), tl
->end(), x
);
478 // don't insert duplicates
479 if (it
== tl
->end() || *it
!= x
) {
487 int LineTabstops::GetNextTabstop(Sci::Line line
, int x
) const {
488 if (line
< tabstops
.Length()) {
489 TabstopList
*tl
= tabstops
[line
].get();
491 for (const int i
: *tl
) {