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.
16 #include "Scintilla.h"
18 #include "SplitVector.h"
19 #include "Partitioning.h"
20 #include "CellBuffer.h"
24 using namespace Scintilla
;
27 MarkerHandleSet::MarkerHandleSet() {
31 MarkerHandleSet::~MarkerHandleSet() {
32 MarkerHandleNumber
*mhn
= root
;
34 MarkerHandleNumber
*mhnToFree
= mhn
;
41 int MarkerHandleSet::Length() const {
43 MarkerHandleNumber
*mhn
= root
;
51 int MarkerHandleSet::MarkValue() const {
53 MarkerHandleNumber
*mhn
= root
;
55 m
|= (1 << mhn
->number
);
61 bool MarkerHandleSet::Contains(int handle
) const {
62 MarkerHandleNumber
*mhn
= root
;
64 if (mhn
->handle
== handle
) {
72 bool MarkerHandleSet::InsertHandle(int handle
, int markerNum
) {
73 MarkerHandleNumber
*mhn
= new MarkerHandleNumber
;
75 mhn
->number
= markerNum
;
81 void MarkerHandleSet::RemoveHandle(int handle
) {
82 MarkerHandleNumber
**pmhn
= &root
;
84 MarkerHandleNumber
*mhn
= *pmhn
;
85 if (mhn
->handle
== handle
) {
90 pmhn
= &((*pmhn
)->next
);
94 bool MarkerHandleSet::RemoveNumber(int markerNum
, bool all
) {
95 bool performedDeletion
= false;
96 MarkerHandleNumber
**pmhn
= &root
;
98 MarkerHandleNumber
*mhn
= *pmhn
;
99 if (mhn
->number
== markerNum
) {
102 performedDeletion
= true;
106 pmhn
= &((*pmhn
)->next
);
109 return performedDeletion
;
112 void MarkerHandleSet::CombineWith(MarkerHandleSet
*other
) {
113 MarkerHandleNumber
**pmhn
= &other
->root
;
115 pmhn
= &((*pmhn
)->next
);
122 LineMarkers::~LineMarkers() {
126 void LineMarkers::Init() {
127 for (int line
= 0; line
< markers
.Length(); line
++) {
128 delete markers
[line
];
134 void LineMarkers::InsertLine(int line
) {
135 if (markers
.Length()) {
136 markers
.Insert(line
, 0);
140 void LineMarkers::RemoveLine(int line
) {
141 // Retain the markers from the deleted line by oring them into the previous line
142 if (markers
.Length()) {
144 MergeMarkers(line
- 1);
146 markers
.Delete(line
);
150 int LineMarkers::LineFromHandle(int markerHandle
) {
151 if (markers
.Length()) {
152 for (int line
= 0; line
< markers
.Length(); line
++) {
154 if (markers
[line
]->Contains(markerHandle
)) {
163 void LineMarkers::MergeMarkers(int pos
) {
164 if (markers
[pos
+ 1] != NULL
) {
165 if (markers
[pos
] == NULL
)
166 markers
[pos
] = new MarkerHandleSet
;
167 markers
[pos
]->CombineWith(markers
[pos
+ 1]);
168 delete markers
[pos
+ 1];
169 markers
[pos
+ 1] = NULL
;
173 int LineMarkers::MarkValue(int line
) {
174 if (markers
.Length() && (line
>= 0) && (line
< markers
.Length()) && markers
[line
])
175 return markers
[line
]->MarkValue();
180 int LineMarkers::MarkerNext(int lineStart
, int mask
) const {
183 int length
= markers
.Length();
184 for (int iLine
= lineStart
; iLine
< length
; iLine
++) {
185 MarkerHandleSet
*onLine
= markers
[iLine
];
186 if (onLine
&& ((onLine
->MarkValue() & mask
) != 0))
187 //if ((pdoc->GetMark(iLine) & lParam) != 0)
193 int LineMarkers::AddMark(int line
, int markerNum
, int lines
) {
195 if (!markers
.Length()) {
196 // No existing markers so allocate one element per line
197 markers
.InsertValue(0, lines
, 0);
199 if (line
>= markers
.Length()) {
202 if (!markers
[line
]) {
203 // Need new structure to hold marker handle
204 markers
[line
] = new MarkerHandleSet();
206 markers
[line
]->InsertHandle(handleCurrent
, markerNum
);
208 return handleCurrent
;
211 bool LineMarkers::DeleteMark(int line
, int markerNum
, bool all
) {
212 bool someChanges
= false;
213 if (markers
.Length() && (line
>= 0) && (line
< markers
.Length()) && markers
[line
]) {
214 if (markerNum
== -1) {
216 delete markers
[line
];
217 markers
[line
] = NULL
;
219 someChanges
= markers
[line
]->RemoveNumber(markerNum
, all
);
220 if (markers
[line
]->Length() == 0) {
221 delete markers
[line
];
222 markers
[line
] = NULL
;
229 void LineMarkers::DeleteMarkFromHandle(int markerHandle
) {
230 int line
= LineFromHandle(markerHandle
);
232 markers
[line
]->RemoveHandle(markerHandle
);
233 if (markers
[line
]->Length() == 0) {
234 delete markers
[line
];
235 markers
[line
] = NULL
;
240 LineLevels::~LineLevels() {
243 void LineLevels::Init() {
247 void LineLevels::InsertLine(int line
) {
248 if (levels
.Length()) {
249 int level
= (line
< levels
.Length()) ? levels
[line
] : SC_FOLDLEVELBASE
;
250 levels
.InsertValue(line
, 1, level
);
254 void LineLevels::RemoveLine(int line
) {
255 if (levels
.Length()) {
256 // Move up following lines but merge header flag from this line
257 // to line before to avoid a temporary disappearence causing expansion.
258 int firstHeader
= levels
[line
] & SC_FOLDLEVELHEADERFLAG
;
260 if (line
== levels
.Length()-1) // Last line loses the header flag
261 levels
[line
-1] &= ~SC_FOLDLEVELHEADERFLAG
;
263 levels
[line
-1] |= firstHeader
;
267 void LineLevels::ExpandLevels(int sizeNew
) {
268 levels
.InsertValue(levels
.Length(), sizeNew
- levels
.Length(), SC_FOLDLEVELBASE
);
271 void LineLevels::ClearLevels() {
275 int LineLevels::SetLevel(int line
, int level
, int lines
) {
277 if ((line
>= 0) && (line
< lines
)) {
278 if (!levels
.Length()) {
279 ExpandLevels(lines
+ 1);
283 levels
[line
] = level
;
289 int LineLevels::GetLevel(int line
) const {
290 if (levels
.Length() && (line
>= 0) && (line
< levels
.Length())) {
293 return SC_FOLDLEVELBASE
;
297 LineState::~LineState() {
300 void LineState::Init() {
301 lineStates
.DeleteAll();
304 void LineState::InsertLine(int line
) {
305 if (lineStates
.Length()) {
306 lineStates
.EnsureLength(line
);
307 int val
= (line
< lineStates
.Length()) ? lineStates
[line
] : 0;
308 lineStates
.Insert(line
, val
);
312 void LineState::RemoveLine(int line
) {
313 if (lineStates
.Length() > line
) {
314 lineStates
.Delete(line
);
318 int LineState::SetLineState(int line
, int state
) {
319 lineStates
.EnsureLength(line
+ 1);
320 int stateOld
= lineStates
[line
];
321 lineStates
[line
] = state
;
325 int LineState::GetLineState(int line
) {
328 lineStates
.EnsureLength(line
+ 1);
329 return lineStates
[line
];
332 int LineState::GetMaxLineState() const {
333 return lineStates
.Length();
336 static int NumberLines(const char *text
) {
350 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
351 // and then has text and optional styles.
353 static const int IndividualStyles
= 0x100;
355 struct AnnotationHeader
{
356 short style
; // Style IndividualStyles implies array of styles
361 LineAnnotation::~LineAnnotation() {
365 void LineAnnotation::Init() {
369 void LineAnnotation::InsertLine(int line
) {
370 if (annotations
.Length()) {
371 annotations
.EnsureLength(line
);
372 annotations
.Insert(line
, 0);
376 void LineAnnotation::RemoveLine(int line
) {
377 if (annotations
.Length() && (line
> 0) && (line
<= annotations
.Length())) {
378 delete []annotations
[line
-1];
379 annotations
.Delete(line
-1);
383 bool LineAnnotation::MultipleStyles(int line
) const {
384 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
385 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->style
== IndividualStyles
;
390 int LineAnnotation::Style(int line
) const {
391 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
392 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->style
;
397 const char *LineAnnotation::Text(int line
) const {
398 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
399 return annotations
[line
]+sizeof(AnnotationHeader
);
404 const unsigned char *LineAnnotation::Styles(int line
) const {
405 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
] && MultipleStyles(line
))
406 return reinterpret_cast<unsigned char *>(annotations
[line
] + sizeof(AnnotationHeader
) + Length(line
));
411 static char *AllocateAnnotation(int length
, int style
) {
412 size_t len
= sizeof(AnnotationHeader
) + length
+ ((style
== IndividualStyles
) ? length
: 0);
413 char *ret
= new char[len
]();
417 void LineAnnotation::SetText(int line
, const char *text
) {
418 if (text
&& (line
>= 0)) {
419 annotations
.EnsureLength(line
+1);
420 int style
= Style(line
);
421 if (annotations
[line
]) {
422 delete []annotations
[line
];
424 annotations
[line
] = AllocateAnnotation(static_cast<int>(strlen(text
)), style
);
425 AnnotationHeader
*pah
= reinterpret_cast<AnnotationHeader
*>(annotations
[line
]);
426 pah
->style
= static_cast<short>(style
);
427 pah
->length
= static_cast<int>(strlen(text
));
428 pah
->lines
= static_cast<short>(NumberLines(text
));
429 memcpy(annotations
[line
]+sizeof(AnnotationHeader
), text
, pah
->length
);
431 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
]) {
432 delete []annotations
[line
];
433 annotations
[line
] = 0;
438 void LineAnnotation::ClearAll() {
439 for (int line
= 0; line
< annotations
.Length(); line
++) {
440 delete []annotations
[line
];
441 annotations
[line
] = 0;
443 annotations
.DeleteAll();
446 void LineAnnotation::SetStyle(int line
, int style
) {
447 annotations
.EnsureLength(line
+1);
448 if (!annotations
[line
]) {
449 annotations
[line
] = AllocateAnnotation(0, style
);
451 reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->style
= static_cast<short>(style
);
454 void LineAnnotation::SetStyles(int line
, const unsigned char *styles
) {
456 annotations
.EnsureLength(line
+1);
457 if (!annotations
[line
]) {
458 annotations
[line
] = AllocateAnnotation(0, IndividualStyles
);
460 AnnotationHeader
*pahSource
= reinterpret_cast<AnnotationHeader
*>(annotations
[line
]);
461 if (pahSource
->style
!= IndividualStyles
) {
462 char *allocation
= AllocateAnnotation(pahSource
->length
, IndividualStyles
);
463 AnnotationHeader
*pahAlloc
= reinterpret_cast<AnnotationHeader
*>(allocation
);
464 pahAlloc
->length
= pahSource
->length
;
465 pahAlloc
->lines
= pahSource
->lines
;
466 memcpy(allocation
+ sizeof(AnnotationHeader
), annotations
[line
] + sizeof(AnnotationHeader
), pahSource
->length
);
467 delete []annotations
[line
];
468 annotations
[line
] = allocation
;
471 AnnotationHeader
*pah
= reinterpret_cast<AnnotationHeader
*>(annotations
[line
]);
472 pah
->style
= IndividualStyles
;
473 memcpy(annotations
[line
] + sizeof(AnnotationHeader
) + pah
->length
, styles
, pah
->length
);
477 int LineAnnotation::Length(int line
) const {
478 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
479 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->length
;
484 int LineAnnotation::Lines(int line
) const {
485 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
486 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->lines
;
491 LineTabstops::~LineTabstops() {
495 void LineTabstops::Init() {
496 for (int line
= 0; line
< tabstops
.Length(); line
++) {
497 delete tabstops
[line
];
499 tabstops
.DeleteAll();
502 void LineTabstops::InsertLine(int line
) {
503 if (tabstops
.Length()) {
504 tabstops
.EnsureLength(line
);
505 tabstops
.Insert(line
, 0);
509 void LineTabstops::RemoveLine(int line
) {
510 if (tabstops
.Length() > line
) {
511 delete tabstops
[line
];
512 tabstops
.Delete(line
);
516 bool LineTabstops::ClearTabstops(int line
) {
517 if (line
< tabstops
.Length()) {
518 TabstopList
*tl
= tabstops
[line
];
527 bool LineTabstops::AddTabstop(int line
, int x
) {
528 tabstops
.EnsureLength(line
+ 1);
529 if (!tabstops
[line
]) {
530 tabstops
[line
] = new TabstopList();
533 TabstopList
*tl
= tabstops
[line
];
535 // tabstop positions are kept in order - insert in the right place
536 std::vector
<int>::iterator it
= std::lower_bound(tl
->begin(), tl
->end(), x
);
537 // don't insert duplicates
538 if (it
== tl
->end() || *it
!= x
) {
546 int LineTabstops::GetNextTabstop(int line
, int x
) const {
547 if (line
< tabstops
.Length()) {
548 TabstopList
*tl
= tabstops
[line
];
550 for (size_t i
= 0; i
< tl
->size(); i
++) {