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
= &other
->root
;
113 pmhn
= &((*pmhn
)->next
);
120 LineMarkers::~LineMarkers() {
124 void LineMarkers::Init() {
125 for (int line
= 0; line
< markers
.Length(); line
++) {
126 delete markers
[line
];
132 void LineMarkers::InsertLine(int line
) {
133 if (markers
.Length()) {
134 markers
.Insert(line
, 0);
138 void LineMarkers::RemoveLine(int line
) {
139 // Retain the markers from the deleted line by oring them into the previous line
140 if (markers
.Length()) {
142 MergeMarkers(line
- 1);
144 markers
.Delete(line
);
148 int LineMarkers::LineFromHandle(int markerHandle
) {
149 if (markers
.Length()) {
150 for (int line
= 0; line
< markers
.Length(); line
++) {
152 if (markers
[line
]->Contains(markerHandle
)) {
161 void LineMarkers::MergeMarkers(int pos
) {
162 if (markers
[pos
+ 1] != NULL
) {
163 if (markers
[pos
] == NULL
)
164 markers
[pos
] = new MarkerHandleSet
;
165 markers
[pos
]->CombineWith(markers
[pos
+ 1]);
166 delete markers
[pos
+ 1];
167 markers
[pos
+ 1] = NULL
;
171 int LineMarkers::MarkValue(int line
) {
172 if (markers
.Length() && (line
>= 0) && (line
< markers
.Length()) && markers
[line
])
173 return markers
[line
]->MarkValue();
178 int LineMarkers::MarkerNext(int lineStart
, int mask
) const {
181 int length
= markers
.Length();
182 for (int iLine
= lineStart
; iLine
< length
; iLine
++) {
183 MarkerHandleSet
*onLine
= markers
[iLine
];
184 if (onLine
&& ((onLine
->MarkValue() & mask
) != 0))
185 //if ((pdoc->GetMark(iLine) & lParam) != 0)
191 int LineMarkers::AddMark(int line
, int markerNum
, int lines
) {
193 if (!markers
.Length()) {
194 // No existing markers so allocate one element per line
195 markers
.InsertValue(0, lines
, 0);
197 if (line
>= markers
.Length()) {
200 if (!markers
[line
]) {
201 // Need new structure to hold marker handle
202 markers
[line
] = new MarkerHandleSet();
204 markers
[line
]->InsertHandle(handleCurrent
, markerNum
);
206 return handleCurrent
;
209 bool LineMarkers::DeleteMark(int line
, int markerNum
, bool all
) {
210 bool someChanges
= false;
211 if (markers
.Length() && (line
>= 0) && (line
< markers
.Length()) && markers
[line
]) {
212 if (markerNum
== -1) {
214 delete markers
[line
];
215 markers
[line
] = NULL
;
217 someChanges
= markers
[line
]->RemoveNumber(markerNum
, all
);
218 if (markers
[line
]->Length() == 0) {
219 delete markers
[line
];
220 markers
[line
] = NULL
;
227 void LineMarkers::DeleteMarkFromHandle(int markerHandle
) {
228 int line
= LineFromHandle(markerHandle
);
230 markers
[line
]->RemoveHandle(markerHandle
);
231 if (markers
[line
]->Length() == 0) {
232 delete markers
[line
];
233 markers
[line
] = NULL
;
238 LineLevels::~LineLevels() {
241 void LineLevels::Init() {
245 void LineLevels::InsertLine(int line
) {
246 if (levels
.Length()) {
247 int level
= (line
< levels
.Length()) ? levels
[line
] : SC_FOLDLEVELBASE
;
248 levels
.InsertValue(line
, 1, level
);
252 void LineLevels::RemoveLine(int line
) {
253 if (levels
.Length()) {
254 // Move up following lines but merge header flag from this line
255 // to line before to avoid a temporary disappearence causing expansion.
256 int firstHeader
= levels
[line
] & SC_FOLDLEVELHEADERFLAG
;
258 if (line
== levels
.Length()-1) // Last line loses the header flag
259 levels
[line
-1] &= ~SC_FOLDLEVELHEADERFLAG
;
261 levels
[line
-1] |= firstHeader
;
265 void LineLevels::ExpandLevels(int sizeNew
) {
266 levels
.InsertValue(levels
.Length(), sizeNew
- levels
.Length(), SC_FOLDLEVELBASE
);
269 void LineLevels::ClearLevels() {
273 int LineLevels::SetLevel(int line
, int level
, int lines
) {
275 if ((line
>= 0) && (line
< lines
)) {
276 if (!levels
.Length()) {
277 ExpandLevels(lines
+ 1);
281 levels
[line
] = level
;
287 int LineLevels::GetLevel(int line
) const {
288 if (levels
.Length() && (line
>= 0) && (line
< levels
.Length())) {
291 return SC_FOLDLEVELBASE
;
295 LineState::~LineState() {
298 void LineState::Init() {
299 lineStates
.DeleteAll();
302 void LineState::InsertLine(int line
) {
303 if (lineStates
.Length()) {
304 lineStates
.EnsureLength(line
);
305 int val
= (line
< lineStates
.Length()) ? lineStates
[line
] : 0;
306 lineStates
.Insert(line
, val
);
310 void LineState::RemoveLine(int line
) {
311 if (lineStates
.Length() > line
) {
312 lineStates
.Delete(line
);
316 int LineState::SetLineState(int line
, int state
) {
317 lineStates
.EnsureLength(line
+ 1);
318 int stateOld
= lineStates
[line
];
319 lineStates
[line
] = state
;
323 int LineState::GetLineState(int line
) {
326 lineStates
.EnsureLength(line
+ 1);
327 return lineStates
[line
];
330 int LineState::GetMaxLineState() const {
331 return lineStates
.Length();
334 static int NumberLines(const char *text
) {
348 // Each allocated LineAnnotation is a char array which starts with an AnnotationHeader
349 // and then has text and optional styles.
351 static const int IndividualStyles
= 0x100;
353 struct AnnotationHeader
{
354 short style
; // Style IndividualStyles implies array of styles
359 LineAnnotation::~LineAnnotation() {
363 void LineAnnotation::Init() {
367 void LineAnnotation::InsertLine(int line
) {
368 if (annotations
.Length()) {
369 annotations
.EnsureLength(line
);
370 annotations
.Insert(line
, 0);
374 void LineAnnotation::RemoveLine(int line
) {
375 if (annotations
.Length() && (line
> 0) && (line
<= annotations
.Length())) {
376 delete []annotations
[line
-1];
377 annotations
.Delete(line
-1);
381 bool LineAnnotation::MultipleStyles(int line
) const {
382 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
383 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->style
== IndividualStyles
;
388 int LineAnnotation::Style(int line
) const {
389 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
390 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->style
;
395 const char *LineAnnotation::Text(int line
) const {
396 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
397 return annotations
[line
]+sizeof(AnnotationHeader
);
402 const unsigned char *LineAnnotation::Styles(int line
) const {
403 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
] && MultipleStyles(line
))
404 return reinterpret_cast<unsigned char *>(annotations
[line
] + sizeof(AnnotationHeader
) + Length(line
));
409 static char *AllocateAnnotation(int length
, int style
) {
410 size_t len
= sizeof(AnnotationHeader
) + length
+ ((style
== IndividualStyles
) ? length
: 0);
411 char *ret
= new char[len
];
416 void LineAnnotation::SetText(int line
, const char *text
) {
417 if (text
&& (line
>= 0)) {
418 annotations
.EnsureLength(line
+1);
419 int style
= Style(line
);
420 if (annotations
[line
]) {
421 delete []annotations
[line
];
423 annotations
[line
] = AllocateAnnotation(static_cast<int>(strlen(text
)), style
);
424 AnnotationHeader
*pah
= reinterpret_cast<AnnotationHeader
*>(annotations
[line
]);
425 pah
->style
= static_cast<short>(style
);
426 pah
->length
= static_cast<int>(strlen(text
));
427 pah
->lines
= static_cast<short>(NumberLines(text
));
428 memcpy(annotations
[line
]+sizeof(AnnotationHeader
), text
, pah
->length
);
430 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
]) {
431 delete []annotations
[line
];
432 annotations
[line
] = 0;
437 void LineAnnotation::ClearAll() {
438 for (int line
= 0; line
< annotations
.Length(); line
++) {
439 delete []annotations
[line
];
440 annotations
[line
] = 0;
442 annotations
.DeleteAll();
445 void LineAnnotation::SetStyle(int line
, int style
) {
446 annotations
.EnsureLength(line
+1);
447 if (!annotations
[line
]) {
448 annotations
[line
] = AllocateAnnotation(0, style
);
450 reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->style
= static_cast<short>(style
);
453 void LineAnnotation::SetStyles(int line
, const unsigned char *styles
) {
455 annotations
.EnsureLength(line
+1);
456 if (!annotations
[line
]) {
457 annotations
[line
] = AllocateAnnotation(0, IndividualStyles
);
459 AnnotationHeader
*pahSource
= reinterpret_cast<AnnotationHeader
*>(annotations
[line
]);
460 if (pahSource
->style
!= IndividualStyles
) {
461 char *allocation
= AllocateAnnotation(pahSource
->length
, IndividualStyles
);
462 AnnotationHeader
*pahAlloc
= reinterpret_cast<AnnotationHeader
*>(allocation
);
463 pahAlloc
->length
= pahSource
->length
;
464 pahAlloc
->lines
= pahSource
->lines
;
465 memcpy(allocation
+ sizeof(AnnotationHeader
), annotations
[line
] + sizeof(AnnotationHeader
), pahSource
->length
);
466 delete []annotations
[line
];
467 annotations
[line
] = allocation
;
470 AnnotationHeader
*pah
= reinterpret_cast<AnnotationHeader
*>(annotations
[line
]);
471 pah
->style
= IndividualStyles
;
472 memcpy(annotations
[line
] + sizeof(AnnotationHeader
) + pah
->length
, styles
, pah
->length
);
476 int LineAnnotation::Length(int line
) const {
477 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
478 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->length
;
483 int LineAnnotation::Lines(int line
) const {
484 if (annotations
.Length() && (line
>= 0) && (line
< annotations
.Length()) && annotations
[line
])
485 return reinterpret_cast<AnnotationHeader
*>(annotations
[line
])->lines
;
490 LineTabstops::~LineTabstops() {
494 void LineTabstops::Init() {
495 for (int line
= 0; line
< tabstops
.Length(); line
++) {
496 delete tabstops
[line
];
498 tabstops
.DeleteAll();
501 void LineTabstops::InsertLine(int line
) {
502 if (tabstops
.Length()) {
503 tabstops
.EnsureLength(line
);
504 tabstops
.Insert(line
, 0);
508 void LineTabstops::RemoveLine(int line
) {
509 if (tabstops
.Length() > line
) {
510 delete tabstops
[line
];
511 tabstops
.Delete(line
);
515 bool LineTabstops::ClearTabstops(int line
) {
516 if (line
< tabstops
.Length()) {
517 TabstopList
*tl
= tabstops
[line
];
526 bool LineTabstops::AddTabstop(int line
, int x
) {
527 tabstops
.EnsureLength(line
+ 1);
528 if (!tabstops
[line
]) {
529 tabstops
[line
] = new TabstopList();
532 TabstopList
*tl
= tabstops
[line
];
534 // tabstop positions are kept in order - insert in the right place
535 std::vector
<int>::iterator it
= std::lower_bound(tl
->begin(), tl
->end(), x
);
536 // don't insert duplicates
537 if (it
== tl
->end() || *it
!= x
) {
545 int LineTabstops::GetNextTabstop(int line
, int x
) const {
546 if (line
< tabstops
.Length()) {
547 TabstopList
*tl
= tabstops
[line
];
549 for (size_t i
= 0; i
< tl
->size(); i
++) {