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.
15 #include "Scintilla.h"
16 #include "SplitVector.h"
17 #include "Partitioning.h"
18 #include "CellBuffer.h"
22 using namespace Scintilla
;
25 MarkerHandleSet::MarkerHandleSet() {
29 MarkerHandleSet::~MarkerHandleSet() {
30 MarkerHandleNumber
*mhn
= root
;
32 MarkerHandleNumber
*mhnToFree
= mhn
;
39 int MarkerHandleSet::Length() const {
41 MarkerHandleNumber
*mhn
= root
;
49 int MarkerHandleSet::MarkValue() const {
51 MarkerHandleNumber
*mhn
= root
;
53 m
|= (1 << mhn
->number
);
59 bool MarkerHandleSet::Contains(int handle
) const {
60 MarkerHandleNumber
*mhn
= root
;
62 if (mhn
->handle
== handle
) {
70 bool MarkerHandleSet::InsertHandle(int handle
, int markerNum
) {
71 MarkerHandleNumber
*mhn
= new MarkerHandleNumber
;
73 mhn
->number
= markerNum
;
79 void MarkerHandleSet::RemoveHandle(int handle
) {
80 MarkerHandleNumber
**pmhn
= &root
;
82 MarkerHandleNumber
*mhn
= *pmhn
;
83 if (mhn
->handle
== handle
) {
88 pmhn
= &((*pmhn
)->next
);
92 bool MarkerHandleSet::RemoveNumber(int markerNum
, bool all
) {
93 bool performedDeletion
= false;
94 MarkerHandleNumber
**pmhn
= &root
;
96 MarkerHandleNumber
*mhn
= *pmhn
;
97 if (mhn
->number
== markerNum
) {
100 performedDeletion
= true;
104 pmhn
= &((*pmhn
)->next
);
107 return performedDeletion
;
110 void MarkerHandleSet::CombineWith(MarkerHandleSet
*other
) {
111 MarkerHandleNumber
**pmhn
= &root
;
113 pmhn
= &((*pmhn
)->next
);
119 LineMarkers::~LineMarkers() {
123 void LineMarkers::Init() {
124 for (int line
= 0; line
< markers
.Length(); line
++) {
125 delete markers
[line
];
131 void LineMarkers::InsertLine(int line
) {
132 if (markers
.Length()) {
133 markers
.Insert(line
, 0);
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()) {
141 MergeMarkers(line
- 1);
143 markers
.Delete(line
);
147 int LineMarkers::LineFromHandle(int markerHandle
) {
148 if (markers
.Length()) {
149 for (int line
= 0; line
< markers
.Length(); line
++) {
151 if (markers
[line
]->Contains(markerHandle
)) {
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
;
170 int LineMarkers::MarkValue(int line
) {
171 if (markers
.Length() && (line
>= 0) && (line
< markers
.Length()) && markers
[line
])
172 return markers
[line
]->MarkValue();
177 int LineMarkers::MarkerNext(int lineStart
, int mask
) const {
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)
190 int LineMarkers::AddMark(int line
, int markerNum
, int lines
) {
192 if (!markers
.Length()) {
193 // No existing markers so allocate one element per line
194 markers
.InsertValue(0, lines
, 0);
196 if (line
>= markers
.Length()) {
199 if (!markers
[line
]) {
200 // Need new structure to hold marker handle
201 markers
[line
] = new MarkerHandleSet();
203 markers
[line
]->InsertHandle(handleCurrent
, markerNum
);
205 return handleCurrent
;
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) {
213 delete markers
[line
];
214 markers
[line
] = NULL
;
216 someChanges
= markers
[line
]->RemoveNumber(markerNum
, all
);
217 if (markers
[line
]->Length() == 0) {
218 delete markers
[line
];
219 markers
[line
] = NULL
;
226 void LineMarkers::DeleteMarkFromHandle(int markerHandle
) {
227 int line
= LineFromHandle(markerHandle
);
229 markers
[line
]->RemoveHandle(markerHandle
);
230 if (markers
[line
]->Length() == 0) {
231 delete markers
[line
];
232 markers
[line
] = NULL
;
237 LineLevels::~LineLevels() {
240 void LineLevels::Init() {
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
);
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
;
257 if (line
== levels
.Length()-1) // Last line loses the header flag
258 levels
[line
-1] &= ~SC_FOLDLEVELHEADERFLAG
;
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() {
272 int LineLevels::SetLevel(int line
, int level
, int lines
) {
274 if ((line
>= 0) && (line
< lines
)) {
275 if (!levels
.Length()) {
276 ExpandLevels(lines
+ 1);
280 levels
[line
] = level
;
286 int LineLevels::GetLevel(int line
) const {
287 if (levels
.Length() && (line
>= 0) && (line
< levels
.Length())) {
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 int val
= (line
< lineStates
.Length()) ? lineStates
[line
] : 0;
305 lineStates
.Insert(line
, val
);
309 void LineState::RemoveLine(int line
) {
310 if (lineStates
.Length() > line
) {
311 lineStates
.Delete(line
);
315 int LineState::SetLineState(int line
, int state
) {
316 lineStates
.EnsureLength(line
+ 1);
317 int stateOld
= lineStates
[line
];
318 lineStates
[line
] = state
;
322 int LineState::GetLineState(int line
) {
325 lineStates
.EnsureLength(line
+ 1);
326 return lineStates
[line
];
329 int LineState::GetMaxLineState() const {
330 return lineStates
.Length();
333 static int NumberLines(const char *text
) {
347 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
348 // and then has text and optional styles.
350 static const int IndividualStyles
= 0x100;
352 struct AnnotationHeader
{
353 short style
; // Style IndividualStyles implies array of styles
358 LineAnnotation::~LineAnnotation() {
362 void LineAnnotation::Init() {
366 void LineAnnotation::InsertLine(int line
) {
367 if (annotations
.Length()) {
368 annotations
.EnsureLength(line
);
369 annotations
.Insert(line
, 0);
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);
380 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
;
387 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
;
394 const char *LineAnnotation::Text(int line
) const {
395 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
396 return annotations
[line
]+sizeof(AnnotationHeader
);
401 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
));
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
];
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
];
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
);
429 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
]) {
430 delete []annotations
[line
];
431 annotations
[line
] = 0;
436 void LineAnnotation::ClearAll() {
437 for (int line
= 0; line
< annotations
.Length(); line
++) {
438 delete []annotations
[line
];
439 annotations
[line
] = 0;
441 annotations
.DeleteAll();
444 void LineAnnotation::SetStyle(int line
, int style
) {
445 annotations
.EnsureLength(line
+1);
446 if (!annotations
[line
]) {
447 annotations
[line
] = AllocateAnnotation(0, style
);
449 reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->style
= static_cast<short>(style
);
452 void LineAnnotation::SetStyles(int line
, const unsigned char *styles
) {
454 annotations
.EnsureLength(line
+1);
455 if (!annotations
[line
]) {
456 annotations
[line
] = AllocateAnnotation(0, IndividualStyles
);
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
);
475 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
;
482 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
;
489 LineTabstops::~LineTabstops() {
493 void LineTabstops::Init() {
494 for (int line
= 0; line
< tabstops
.Length(); line
++) {
495 delete tabstops
[line
];
497 tabstops
.DeleteAll();
500 void LineTabstops::InsertLine(int line
) {
501 if (tabstops
.Length()) {
502 tabstops
.EnsureLength(line
);
503 tabstops
.Insert(line
, 0);
507 void LineTabstops::RemoveLine(int line
) {
508 if (tabstops
.Length() > line
) {
509 delete tabstops
[line
];
510 tabstops
.Delete(line
);
514 bool LineTabstops::ClearTabstops(int line
) {
515 if (line
< tabstops
.Length()) {
516 TabstopList
*tl
= tabstops
[line
];
525 bool LineTabstops::AddTabstop(int line
, int x
) {
526 tabstops
.EnsureLength(line
+ 1);
527 if (!tabstops
[line
]) {
528 tabstops
[line
] = new TabstopList();
531 TabstopList
*tl
= tabstops
[line
];
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
) {
544 int LineTabstops::GetNextTabstop(int line
, int x
) const {
545 if (line
< tabstops
.Length()) {
546 TabstopList
*tl
= tabstops
[line
];
548 for (size_t i
= 0; i
< tl
->size(); i
++) {