1 // Scintilla source code edit control
2 // CellBuffer.cxx - manages a buffer of cells
3 // Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
4 // The License.txt file describes the conditions under which this software may be distributed.
13 #include "Scintilla.h"
15 #include "CellBuffer.h"
17 MarkerHandleSet::MarkerHandleSet() {
21 MarkerHandleSet::~MarkerHandleSet() {
22 MarkerHandleNumber
*mhn
= root
;
24 MarkerHandleNumber
*mhnToFree
= mhn
;
31 int MarkerHandleSet::Length() {
33 MarkerHandleNumber
*mhn
= root
;
41 int MarkerHandleSet::NumberFromHandle(int handle
) {
42 MarkerHandleNumber
*mhn
= root
;
44 if (mhn
->handle
== handle
) {
52 int MarkerHandleSet::MarkValue() {
54 MarkerHandleNumber
*mhn
= root
;
56 m
|= (1 << mhn
->number
);
62 bool MarkerHandleSet::Contains(int handle
) {
63 MarkerHandleNumber
*mhn
= root
;
65 if (mhn
->handle
== handle
) {
73 bool MarkerHandleSet::InsertHandle(int handle
, int markerNum
) {
74 MarkerHandleNumber
*mhn
= new MarkerHandleNumber
;
78 mhn
->number
= markerNum
;
84 void MarkerHandleSet::RemoveHandle(int handle
) {
85 MarkerHandleNumber
**pmhn
= &root
;
87 MarkerHandleNumber
*mhn
= *pmhn
;
88 if (mhn
->handle
== handle
) {
93 pmhn
= &((*pmhn
)->next
);
97 void MarkerHandleSet::RemoveNumber(int markerNum
) {
98 MarkerHandleNumber
**pmhn
= &root
;
100 MarkerHandleNumber
*mhn
= *pmhn
;
101 if (mhn
->number
== markerNum
) {
106 pmhn
= &((*pmhn
)->next
);
110 void MarkerHandleSet::CombineWith(MarkerHandleSet
*other
) {
111 MarkerHandleNumber
**pmhn
= &root
;
113 pmhn
= &((*pmhn
)->next
);
119 LineVector::LineVector() {
126 LineVector::~LineVector() {
127 for (int line
= 0; line
< lines
; line
++) {
128 delete linesData
[line
].handleSet
;
129 linesData
[line
].handleSet
= 0;
137 void LineVector::Init() {
138 for (int line
= 0; line
< lines
; line
++) {
139 delete linesData
[line
].handleSet
;
140 linesData
[line
].handleSet
= 0;
143 linesData
= new LineData
[static_cast<int>(growSize
)];
151 void LineVector::Expand(int sizeNew
) {
152 LineData
*linesDataNew
= new LineData
[sizeNew
];
154 for (int i
= 0; i
< size
; i
++)
155 linesDataNew
[i
] = linesData
[i
];
156 // Do not delete handleSets here as they are transferred to new linesData
158 linesData
= linesDataNew
;
161 Platform::DebugPrintf("No memory available\n");
166 void LineVector::ExpandLevels(int sizeNew
) {
169 int *levelsNew
= new int[sizeNew
];
172 for (; i
< sizeLevels
; i
++)
173 levelsNew
[i
] = levels
[i
];
174 for (; i
< sizeNew
; i
++)
175 levelsNew
[i
] = SC_FOLDLEVELBASE
;
178 sizeLevels
= sizeNew
;
180 Platform::DebugPrintf("No memory available\n");
185 void LineVector::InsertValue(int pos
, int value
) {
186 //Platform::DebugPrintf("InsertValue[%d] = %d\n", pos, value);
187 if ((lines
+ 2) >= size
) {
188 Expand(size
+ growSize
);
190 ExpandLevels(size
+ growSize
);
194 for (int i
= lines
; i
> pos
; i
--) {
195 linesData
[i
] = linesData
[i
- 1];
197 linesData
[pos
].startPosition
= value
;
198 linesData
[pos
].handleSet
= 0;
200 for (int j
= lines
; j
> pos
; j
--) {
201 levels
[j
] = levels
[j
- 1];
204 levels
[pos
] = SC_FOLDLEVELBASE
;
205 } else if (pos
== (lines
-1)) { // Last line will not be a folder
206 levels
[pos
] = SC_FOLDLEVELBASE
;
208 levels
[pos
] = levels
[pos
-1];
213 void LineVector::SetValue(int pos
, int value
) {
214 //Platform::DebugPrintf("SetValue[%d] = %d\n", pos, value);
215 if ((pos
+ 2) >= size
) {
216 //Platform::DebugPrintf("Resize %d %d\n", size,pos);
217 Expand(pos
+ growSize
);
218 //Platform::DebugPrintf("end Resize %d %d\n", size,pos);
221 ExpandLevels(pos
+ growSize
);
224 linesData
[pos
].startPosition
= value
;
227 void LineVector::Remove(int pos
) {
228 //Platform::DebugPrintf("Remove %d\n", pos);
229 // Retain the markers from the deleted line by oring them into the previous line
231 MergeMarkers(pos
- 1);
233 for (int i
= pos
; i
< lines
; i
++) {
234 linesData
[i
] = linesData
[i
+ 1];
237 // Level information merges back onto previous line
238 int posAbove
= pos
-1;
241 for (int j
= posAbove
; j
< lines
; j
++) {
242 levels
[j
] = levels
[j
+ 1];
248 int LineVector::LineFromPosition(int pos
) {
249 //Platform::DebugPrintf("LineFromPostion %d lines=%d end = %d\n", pos, lines, linesData[lines].startPosition);
252 //Platform::DebugPrintf("LineFromPosition %d\n", pos);
253 if (pos
>= linesData
[lines
].startPosition
)
258 int middle
= (upper
+ lower
+ 1) / 2; // Round high
259 if (pos
< linesData
[middle
].startPosition
) {
264 } while (lower
< upper
);
265 //Platform::DebugPrintf("LineFromPostion %d %d %d\n", pos, lower, linesData[lower].startPosition, linesData[lower > 1 ? lower - 1 : 0].startPosition);
269 int LineVector::AddMark(int line
, int markerNum
) {
271 if (!linesData
[line
].handleSet
) {
272 // Need new structure to hold marker handle
273 linesData
[line
].handleSet
= new MarkerHandleSet
;
274 if (!linesData
[line
].handleSet
)
277 linesData
[line
].handleSet
->InsertHandle(handleCurrent
, markerNum
);
279 return handleCurrent
;
282 void LineVector::MergeMarkers(int pos
) {
283 if (linesData
[pos
].handleSet
|| linesData
[pos
+ 1].handleSet
) {
284 if (linesData
[pos
].handleSet
&& linesData
[pos
+ 1].handleSet
) {
285 linesData
[pos
].handleSet
->CombineWith(linesData
[pos
].handleSet
);
286 linesData
[pos
].handleSet
= 0;
291 void LineVector::DeleteMark(int line
, int markerNum
) {
292 if (linesData
[line
].handleSet
) {
293 if (markerNum
== -1) {
294 delete linesData
[line
].handleSet
;
295 linesData
[line
].handleSet
= 0;
297 linesData
[line
].handleSet
->RemoveNumber(markerNum
);
298 if (linesData
[line
].handleSet
->Length() == 0) {
299 delete linesData
[line
].handleSet
;
300 linesData
[line
].handleSet
= 0;
306 void LineVector::DeleteMarkFromHandle(int markerHandle
) {
307 int line
= LineFromHandle(markerHandle
);
309 linesData
[line
].handleSet
->RemoveHandle(markerHandle
);
310 if (linesData
[line
].handleSet
->Length() == 0) {
311 delete linesData
[line
].handleSet
;
312 linesData
[line
].handleSet
= 0;
317 int LineVector::LineFromHandle(int markerHandle
) {
318 for (int line
= 0; line
< lines
; line
++) {
319 if (linesData
[line
].handleSet
) {
320 if (linesData
[line
].handleSet
->Contains(markerHandle
)) {
339 void Action::Create(actionType at_
, int position_
, char *data_
, int lenData_
, bool mayCoalesce_
) {
341 position
= position_
;
345 mayCoalesce
= mayCoalesce_
;
348 void Action::Destroy() {
353 void Action::Grab(Action
*source
) {
356 position
= source
->position
;
359 lenData
= source
->lenData
;
360 mayCoalesce
= source
->mayCoalesce
;
362 // Ownership of source data transferred to this
363 source
->position
= 0;
364 source
->at
= startAction
;
367 source
->mayCoalesce
= true;
370 // The undo history stores a sequence of user operations that represent the user's view of the
371 // commands executed on the text.
372 // Each user operation contains a sequence of text insertion and text deletion actions.
373 // All the user operations are stored in a list of individual actions with 'start' actions used
374 // as delimiters between user operations.
375 // Initially there is one start action in the history.
376 // As each action is performed, it is recorded in the history. The action may either become
377 // part of the current user operation or may start a new user operation. If it is to be part of the
378 // current operation, then it overwrites the current last action. If it is to be part of a new
379 // operation, it is appended after the current last action.
380 // After writing the new action, a new start action is appended at the end of the history.
381 // The decision of whether to start a new user operation is based upon two factors. If a
382 // compound operation has been explicitly started by calling BeginUndoAction and no matching
383 // EndUndoAction (these calls nest) has been called, then the action is coalesced into the current
384 // operation. If there is no outstanding BeginUndoAction call then a new operation is started
385 // unless it looks as if the new action is caused by the user typing or deleting a stream of text.
386 // Sequences that look like typing or deletion are coalesced into a single user operation.
388 UndoHistory::UndoHistory() {
391 actions
= new Action
[lenActions
];
394 undoSequenceDepth
= 0;
397 actions
[currentAction
].Create(startAction
);
400 UndoHistory::~UndoHistory() {
405 void UndoHistory::EnsureUndoRoom() {
406 //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, length, currentAction);
407 if (currentAction
>= 2) {
408 // Have to test that there is room for 2 more actions in the array
409 // as two actions may be created by this function
410 if (currentAction
>= (lenActions
- 2)) {
411 // Run out of undo nodes so extend the array
412 int lenActionsNew
= lenActions
* 2;
413 Action
*actionsNew
= new Action
[lenActionsNew
];
416 for (int act
= 0; act
<= currentAction
; act
++)
417 actionsNew
[act
].Grab(&actions
[act
]);
419 lenActions
= lenActionsNew
;
420 actions
= actionsNew
;
425 void UndoHistory::AppendAction(actionType at
, int position
, char *data
, int lengthData
) {
427 //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction);
428 //Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at,
429 // actions[currentAction - 1].position, actions[currentAction - 1].lenData);
430 if (currentAction
>= 1) {
431 if (0 == undoSequenceDepth
) {
432 // Top level actions may not always be coalesced
433 Action
&actPrevious
= actions
[currentAction
- 1];
434 // See if current action can be coalesced into previous action
435 // Will work if both are inserts or deletes and position is same
436 if (at
!= actPrevious
.at
) {
438 } else if (currentAction
== savePoint
) {
440 } else if ((at
== removeAction
) &&
441 ((position
+ lengthData
* 2) != actPrevious
.position
)) {
442 // Removals must be at same position to coalesce
444 } else if ((at
== insertAction
) &&
445 (position
!= (actPrevious
.position
+ actPrevious
.lenData
*2))) {
446 // Insertions must be immediately after to coalesce
449 //Platform::DebugPrintf("action coalesced\n");
452 // Actions not at top level are always coalesced unless this is after return to top level
453 if (!actions
[currentAction
].mayCoalesce
)
459 actions
[currentAction
].Create(at
, position
, data
, lengthData
);
461 actions
[currentAction
].Create(startAction
);
462 maxAction
= currentAction
;
465 void UndoHistory::BeginUndoAction() {
467 if (undoSequenceDepth
== 0) {
468 if (actions
[currentAction
].at
!= startAction
) {
470 actions
[currentAction
].Create(startAction
);
471 maxAction
= currentAction
;
473 actions
[currentAction
].mayCoalesce
= false;
478 void UndoHistory::EndUndoAction() {
481 if (0 == undoSequenceDepth
) {
482 if (actions
[currentAction
].at
!= startAction
) {
484 actions
[currentAction
].Create(startAction
);
485 maxAction
= currentAction
;
487 actions
[currentAction
].mayCoalesce
= false;
491 void UndoHistory::DropUndoSequence() {
492 undoSequenceDepth
= 0;
495 void UndoHistory::DeleteUndoHistory() {
496 for (int i
= 1; i
< maxAction
; i
++)
497 actions
[i
].Destroy();
500 actions
[currentAction
].Create(startAction
);
504 void UndoHistory::SetSavePoint() {
505 savePoint
= currentAction
;
508 bool UndoHistory::IsSavePoint() const {
509 return savePoint
== currentAction
;
512 bool UndoHistory::CanUndo() const {
513 return (currentAction
> 0) && (maxAction
> 0);
516 int UndoHistory::StartUndo() {
517 // Drop any trailing startAction
518 if (actions
[currentAction
].at
== startAction
&& currentAction
> 0)
521 // Count the steps in this action
522 int act
= currentAction
;
523 while (actions
[act
].at
!= startAction
&& act
> 0) {
526 return currentAction
- act
;
529 const Action
&UndoHistory::GetUndoStep() const {
530 return actions
[currentAction
];
533 void UndoHistory::CompletedUndoStep() {
537 bool UndoHistory::CanRedo() const {
538 return maxAction
> currentAction
;
541 int UndoHistory::StartRedo() {
542 // Drop any leading startAction
543 if (actions
[currentAction
].at
== startAction
&& currentAction
< maxAction
)
546 // Count the steps in this action
547 int act
= currentAction
;
548 while (actions
[act
].at
!= startAction
&& act
< maxAction
) {
551 return act
- currentAction
;
554 const Action
&UndoHistory::GetRedoStep() const {
555 return actions
[currentAction
];
558 void UndoHistory::CompletedRedoStep() {
562 CellBuffer::CellBuffer(int initialLength
) {
563 body
= new char[initialLength
];
564 size
= initialLength
;
567 gaplen
= initialLength
;
568 part2body
= body
+ gaplen
;
570 collectingUndo
= undoCollectAutoStart
;
573 CellBuffer::~CellBuffer() {
578 void CellBuffer::GapTo(int position
) {
579 if (position
== part1len
)
581 if (position
< part1len
) {
582 int diff
= part1len
- position
;
583 //Platform::DebugPrintf("Move gap backwards to %d diff = %d part1len=%d length=%d \n", position,diff, part1len, length);
584 for (int i
= 0; i
< diff
; i
++)
585 body
[part1len
+ gaplen
- i
- 1] = body
[part1len
- i
- 1];
586 } else { // position > part1len
587 int diff
= position
- part1len
;
588 //Platform::DebugPrintf("Move gap forwards to %d diff =%d\n", position,diff);
589 for (int i
= 0; i
< diff
; i
++)
590 body
[part1len
+ i
] = body
[part1len
+ gaplen
+ i
];
593 part2body
= body
+ gaplen
;
596 void CellBuffer::RoomFor(int insertionLength
) {
597 //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength);
598 if (gaplen
<= insertionLength
) {
599 //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength);
601 int newSize
= size
+ insertionLength
+ 4000;
602 //Platform::DebugPrintf("moved gap %d\n", newSize);
603 char *newBody
= new char[newSize
];
604 memcpy(newBody
, body
, size
);
607 gaplen
+= newSize
- size
;
608 part2body
= body
+ gaplen
;
610 //Platform::DebugPrintf("end need room %d %d - size=%d length=%d\n", gaplen, insertionLength,size,length);
614 // To make it easier to write code that uses ByteAt, a position outside the range of the buffer
615 // can be retrieved. All characters outside the range have the value '\0'.
616 char CellBuffer::ByteAt(int position
) {
617 if (position
< part1len
) {
621 return body
[position
];
624 if (position
>= length
) {
627 return part2body
[position
];
632 void CellBuffer::SetByteAt(int position
, char ch
) {
635 //Platform::DebugPrintf("Bad position %d\n",position);
638 if (position
>= length
+ 11) {
639 Platform::DebugPrintf("Very Bad position %d of %d\n", position
, length
);
643 if (position
>= length
) {
644 //Platform::DebugPrintf("Bad position %d of %d\n",position,length);
648 if (position
< part1len
) {
651 part2body
[position
] = ch
;
655 char CellBuffer::CharAt(int position
) {
656 return ByteAt(position
*2);
659 void CellBuffer::GetCharRange(char *buffer
, int position
, int lengthRetrieve
) {
660 if (lengthRetrieve
< 0)
664 int bytePos
= position
* 2;
665 if ((bytePos
+ lengthRetrieve
* 2) > length
) {
666 Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n",bytePos
,
667 lengthRetrieve
, length
);
670 GapTo(0); // Move the buffer so its easy to subscript into it
671 char *pb
= part2body
+ bytePos
;
672 while (lengthRetrieve
--) {
678 char CellBuffer::StyleAt(int position
) {
679 return ByteAt(position
*2 + 1);
682 const char *CellBuffer::InsertString(int position
, char *s
, int insertLength
) {
684 // InsertString and DeleteChars are the bottleneck though which all changes occur
686 if (collectingUndo
) {
687 // Save into the undo/redo stack, but only the characters - not the formatting
688 // This takes up about half load time
689 data
= new char[insertLength
/ 2];
690 for (int i
= 0; i
< insertLength
/ 2; i
++) {
693 uh
.AppendAction(insertAction
, position
, data
, insertLength
/ 2);
696 BasicInsertString(position
, s
, insertLength
);
701 void CellBuffer::InsertCharStyle(int position
, char ch
, char style
) {
705 InsertString(position
*2, s
, 2);
708 bool CellBuffer::SetStyleAt(int position
, char style
, char mask
) {
709 char curVal
= ByteAt(position
*2 + 1);
710 if ((curVal
& mask
) != style
) {
711 SetByteAt(position
*2 + 1, static_cast<char>((curVal
& ~mask
) | style
));
718 bool CellBuffer::SetStyleFor(int position
, int lengthStyle
, char style
, char mask
) {
719 int bytePos
= position
* 2 + 1;
720 bool changed
= false;
721 while (lengthStyle
--) {
722 char curVal
= ByteAt(bytePos
);
723 if ((curVal
& mask
) != style
) {
724 SetByteAt(bytePos
, static_cast<char>((curVal
& ~mask
) | style
));
732 const char *CellBuffer::DeleteChars(int position
, int deleteLength
) {
733 // InsertString and DeleteChars are the bottleneck though which all changes occur
736 if (collectingUndo
) {
737 // Save into the undo/redo stack, but only the characters - not the formatting
738 data
= new char[deleteLength
/ 2];
739 for (int i
= 0; i
< deleteLength
/ 2; i
++) {
740 data
[i
] = ByteAt(position
+ i
* 2);
742 uh
.AppendAction(removeAction
, position
, data
, deleteLength
/ 2);
745 BasicDeleteChars(position
, deleteLength
);
750 int CellBuffer::ByteLength() {
754 int CellBuffer::Length() {
755 return ByteLength() / 2;
758 int CellBuffer::Lines() {
759 //Platform::DebugPrintf("Lines = %d\n", lv.lines);
763 int CellBuffer::LineStart(int line
) {
766 else if (line
> lv
.lines
)
769 return lv
.linesData
[line
].startPosition
;
772 bool CellBuffer::IsReadOnly() {
776 void CellBuffer::SetReadOnly(bool set
) {
780 void CellBuffer::SetSavePoint() {
784 bool CellBuffer::IsSavePoint() {
785 return uh
.IsSavePoint();
788 int CellBuffer::AddMark(int line
, int markerNum
) {
789 if ((line
>= 0) && (line
< lv
.lines
)) {
790 return lv
.AddMark(line
, markerNum
);
795 void CellBuffer::DeleteMark(int line
, int markerNum
) {
796 if ((line
>= 0) && (line
< lv
.lines
)) {
797 lv
.DeleteMark(line
, markerNum
);
801 void CellBuffer::DeleteMarkFromHandle(int markerHandle
) {
802 lv
.DeleteMarkFromHandle(markerHandle
);
805 int CellBuffer::GetMark(int line
) {
806 if ((line
>= 0) && (line
< lv
.lines
) && (lv
.linesData
[line
].handleSet
))
807 return lv
.linesData
[line
].handleSet
->MarkValue();
811 void CellBuffer::DeleteAllMarks(int markerNum
) {
812 for (int line
= 0; line
< lv
.lines
; line
++) {
813 lv
.DeleteMark(line
, markerNum
);
817 int CellBuffer::LineFromHandle(int markerHandle
) {
818 return lv
.LineFromHandle(markerHandle
);
823 void CellBuffer::BasicInsertString(int position
, char *s
, int insertLength
) {
824 //Platform::DebugPrintf("Inserting at %d for %d\n", position, insertLength);
825 if (insertLength
== 0)
827 RoomFor(insertLength
);
830 memcpy(body
+ part1len
, s
, insertLength
);
831 length
+= insertLength
;
832 part1len
+= insertLength
;
833 gaplen
-= insertLength
;
834 part2body
= body
+ gaplen
;
836 int lineInsert
= lv
.LineFromPosition(position
/ 2) + 1;
837 // Point all the lines after the insertion point further along in the buffer
838 for (int lineAfter
= lineInsert
; lineAfter
<= lv
.lines
; lineAfter
++) {
839 lv
.linesData
[lineAfter
].startPosition
+= insertLength
/ 2;
842 if ((position
- 2) >= 0)
843 chPrev
= ByteAt(position
- 2);
845 if ((position
+ insertLength
) < length
)
846 chAfter
= ByteAt(position
+ insertLength
);
847 if (chPrev
== '\r' && chAfter
== '\n') {
848 //Platform::DebugPrintf("Splitting a crlf pair at %d\n", lineInsert);
849 // Splitting up a crlf pair at position
850 lv
.InsertValue(lineInsert
, position
/ 2);
854 for (int i
= 0; i
< insertLength
; i
+= 2) {
857 //Platform::DebugPrintf("Inserting cr at %d\n", lineInsert);
858 lv
.InsertValue(lineInsert
, (position
+ i
) / 2 + 1);
860 } else if (ch
== '\n') {
861 if (chPrev
== '\r') {
862 //Platform::DebugPrintf("Patching cr before lf at %d\n", lineInsert-1);
863 // Patch up what was end of line
864 lv
.SetValue(lineInsert
- 1, (position
+ i
) / 2 + 1);
866 //Platform::DebugPrintf("Inserting lf at %d\n", lineInsert);
867 lv
.InsertValue(lineInsert
, (position
+ i
) / 2 + 1);
873 // Joining two lines where last insertion is cr and following text starts with lf
874 if (chAfter
== '\n') {
876 //Platform::DebugPrintf("Joining cr before lf at %d\n", lineInsert-1);
877 // End of line already in buffer so drop the newly created one
878 lv
.Remove(lineInsert
- 1);
883 void CellBuffer::BasicDeleteChars(int position
, int deleteLength
) {
884 //Platform::DebugPrintf("Deleting at %d for %d\n", position, deleteLength);
885 if (deleteLength
== 0)
888 if ((position
== 0) && (deleteLength
== length
)) {
889 // If whole buffer is being deleted, faster to reinitialise lines data
890 // than to delete each line.
891 //printf("Whole buffer being deleted\n");
894 // Have to fix up line positions before doing deletion as looking at text in buffer
895 // to work out which lines have been removed
897 int lineRemove
= lv
.LineFromPosition(position
/ 2) + 1;
898 // Point all the lines after the insertion point further along in the buffer
899 for (int lineAfter
= lineRemove
; lineAfter
<= lv
.lines
; lineAfter
++) {
900 lv
.linesData
[lineAfter
].startPosition
-= deleteLength
/ 2;
904 chPrev
= ByteAt(position
- 2);
905 char chBefore
= chPrev
;
907 if (position
< length
)
908 chNext
= ByteAt(position
);
909 bool ignoreNL
= false;
910 if (chPrev
== '\r' && chNext
== '\n') {
911 //Platform::DebugPrintf("Deleting lf after cr, move line end to cr at %d\n", lineRemove);
913 lv
.SetValue(lineRemove
, position
/ 2);
915 ignoreNL
= true; // First \n is not real deletion
919 for (int i
= 0; i
< deleteLength
; i
+= 2) {
921 if ((position
+ i
+ 2) < length
)
922 chNext
= ByteAt(position
+ i
+ 2);
923 //Platform::DebugPrintf("Deleting %d %x\n", i, ch);
925 if (chNext
!= '\n') {
926 //Platform::DebugPrintf("Removing cr end of line\n");
927 lv
.Remove(lineRemove
);
929 } else if ((ch
== '\n') && !ignoreNL
) {
930 //Platform::DebugPrintf("Removing lf end of line\n");
931 lv
.Remove(lineRemove
);
932 ignoreNL
= false; // Further \n are not real deletions
937 // May have to fix up end if last deletion causes cr to be next to lf
938 // or removes one of a crlf pair
940 if ((position
+ deleteLength
) < length
)
941 chAfter
= ByteAt(position
+ deleteLength
);
942 if (chBefore
== '\r' && chAfter
== '\n') {
943 //d.printf("Joining cr before lf at %d\n", lineRemove);
944 // Using lineRemove-1 as cr ended line before start of deletion
945 lv
.Remove(lineRemove
- 1);
946 lv
.SetValue(lineRemove
- 1, position
/ 2 + 1);
950 length
-= deleteLength
;
951 gaplen
+= deleteLength
;
952 part2body
= body
+ gaplen
;
955 undoCollectionType
CellBuffer::SetUndoCollection(undoCollectionType collectUndo
) {
956 collectingUndo
= collectUndo
;
957 uh
.DropUndoSequence();
958 return collectingUndo
;
961 bool CellBuffer::IsCollectingUndo() {
962 return collectingUndo
;
965 void CellBuffer::BeginUndoAction() {
966 uh
.BeginUndoAction();
969 void CellBuffer::EndUndoAction() {
973 void CellBuffer::DeleteUndoHistory() {
974 uh
.DeleteUndoHistory();
977 bool CellBuffer::CanUndo() {
978 return (!readOnly
) && (uh
.CanUndo());
981 int CellBuffer::StartUndo() {
982 return uh
.StartUndo();
985 const Action
&CellBuffer::GetUndoStep() const {
986 return uh
.GetUndoStep();
989 void CellBuffer::PerformUndoStep() {
990 const Action
&actionStep
= uh
.GetUndoStep();
991 if (actionStep
.at
== insertAction
) {
992 BasicDeleteChars(actionStep
.position
, actionStep
.lenData
*2);
993 } else if (actionStep
.at
== removeAction
) {
994 char *styledData
= new char[actionStep
.lenData
* 2];
995 for (int i
= 0; i
< actionStep
.lenData
; i
++) {
996 styledData
[i
*2] = actionStep
.data
[i
];
997 styledData
[i
*2+1] = 0;
999 BasicInsertString(actionStep
.position
, styledData
, actionStep
.lenData
*2);
1000 delete []styledData
;
1002 uh
.CompletedUndoStep();
1005 bool CellBuffer::CanRedo() {
1006 return (!readOnly
) && (uh
.CanRedo());
1009 int CellBuffer::StartRedo() {
1010 return uh
.StartRedo();
1013 const Action
&CellBuffer::GetRedoStep() const {
1014 return uh
.GetRedoStep();
1017 void CellBuffer::PerformRedoStep() {
1018 const Action
&actionStep
= uh
.GetRedoStep();
1019 if (actionStep
.at
== insertAction
) {
1020 char *styledData
= new char[actionStep
.lenData
* 2];
1021 for (int i
= 0; i
< actionStep
.lenData
; i
++) {
1022 styledData
[i
*2] = actionStep
.data
[i
];
1023 styledData
[i
*2+1] = 0;
1025 BasicInsertString(actionStep
.position
, styledData
, actionStep
.lenData
*2);
1026 delete []styledData
;
1027 } else if (actionStep
.at
== removeAction
) {
1028 BasicDeleteChars(actionStep
.position
, actionStep
.lenData
*2);
1030 uh
.CompletedRedoStep();
1033 int CellBuffer::SetLineState(int line
, int state
) {
1034 int stateOld
= lineStates
[line
];
1035 lineStates
[line
] = state
;
1039 int CellBuffer::GetLineState(int line
) {
1040 return lineStates
[line
];
1043 int CellBuffer::GetMaxLineState() {
1044 return lineStates
.Length();
1047 int CellBuffer::SetLevel(int line
, int level
) {
1049 if ((line
>= 0) && (line
< lv
.lines
)) {
1053 prev
= lv
.levels
[line
];
1054 if (lv
.levels
[line
] != level
) {
1055 lv
.levels
[line
] = level
;
1061 int CellBuffer::GetLevel(int line
) {
1062 if (lv
.levels
&& (line
>= 0) && (line
< lv
.lines
)) {
1063 return lv
.levels
[line
];
1065 return SC_FOLDLEVELBASE
;