]>
git.saurik.com Git - wxWidgets.git/blob - contrib/src/stc/scintilla/src/CellBuffer.cxx
8183e4d8d3ca9fffc41ddbc983c85cb1b8557146
1 // Scintilla source code edit control
2 /** @file CellBuffer.cxx
3 ** Manages a buffer of cells.
5 // Copyright 1998-2001 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"
17 #include "CellBuffer.h"
19 MarkerHandleSet::MarkerHandleSet() {
23 MarkerHandleSet::~MarkerHandleSet() {
24 MarkerHandleNumber
*mhn
= root
;
26 MarkerHandleNumber
*mhnToFree
= mhn
;
33 int MarkerHandleSet::Length() {
35 MarkerHandleNumber
*mhn
= root
;
43 int MarkerHandleSet::NumberFromHandle(int handle
) {
44 MarkerHandleNumber
*mhn
= root
;
46 if (mhn
->handle
== handle
) {
54 int MarkerHandleSet::MarkValue() {
56 MarkerHandleNumber
*mhn
= root
;
58 m
|= (1 << mhn
->number
);
64 bool MarkerHandleSet::Contains(int handle
) {
65 MarkerHandleNumber
*mhn
= root
;
67 if (mhn
->handle
== handle
) {
75 bool MarkerHandleSet::InsertHandle(int handle
, int markerNum
) {
76 MarkerHandleNumber
*mhn
= new MarkerHandleNumber
;
80 mhn
->number
= markerNum
;
86 void MarkerHandleSet::RemoveHandle(int handle
) {
87 MarkerHandleNumber
**pmhn
= &root
;
89 MarkerHandleNumber
*mhn
= *pmhn
;
90 if (mhn
->handle
== handle
) {
95 pmhn
= &((*pmhn
)->next
);
99 bool MarkerHandleSet::RemoveNumber(int markerNum
) {
100 bool performedDeletion
= false;
101 MarkerHandleNumber
**pmhn
= &root
;
103 MarkerHandleNumber
*mhn
= *pmhn
;
104 if (mhn
->number
== markerNum
) {
107 performedDeletion
= true;
109 pmhn
= &((*pmhn
)->next
);
112 return performedDeletion
;
115 void MarkerHandleSet::CombineWith(MarkerHandleSet
*other
) {
116 MarkerHandleNumber
**pmhn
= &root
;
118 pmhn
= &((*pmhn
)->next
);
124 LineVector::LineVector() {
136 LineVector::~LineVector() {
137 for (int line
= 0; line
< lines
; line
++) {
138 delete linesData
[line
].handleSet
;
139 linesData
[line
].handleSet
= 0;
147 void LineVector::Init() {
148 for (int line
= 0; line
< lines
; line
++) {
149 delete linesData
[line
].handleSet
;
150 linesData
[line
].handleSet
= 0;
153 linesData
= new LineData
[static_cast<int>(growSize
)];
161 void LineVector::Expand(int sizeNew
) {
162 LineData
*linesDataNew
= new LineData
[sizeNew
];
164 for (int i
= 0; i
< size
; i
++)
165 linesDataNew
[i
] = linesData
[i
];
166 // Do not delete handleSets here as they are transferred to new linesData
168 linesData
= linesDataNew
;
171 Platform::DebugPrintf("No memory available\n");
177 void LineVector::ExpandLevels(int sizeNew
) {
180 int *levelsNew
= new int[sizeNew
];
183 for (; i
< sizeLevels
; i
++)
184 levelsNew
[i
] = levels
[i
];
185 for (; i
< sizeNew
; i
++)
186 levelsNew
[i
] = SC_FOLDLEVELBASE
;
189 sizeLevels
= sizeNew
;
191 Platform::DebugPrintf("No memory available\n");
197 void LineVector::ClearLevels() {
203 void LineVector::InsertValue(int pos
, int value
) {
204 //Platform::DebugPrintf("InsertValue[%d] = %d\n", pos, value);
205 if ((lines
+ 2) >= size
) {
206 if (growSize
* 6 < size
)
208 Expand(size
+ growSize
);
210 ExpandLevels(size
+ growSize
);
214 for (int i
= lines
; i
> pos
; i
--) {
215 linesData
[i
] = linesData
[i
- 1];
217 linesData
[pos
].startPosition
= value
;
218 linesData
[pos
].handleSet
= 0;
220 for (int j
= lines
; j
> pos
; j
--) {
221 levels
[j
] = levels
[j
- 1];
224 levels
[pos
] = SC_FOLDLEVELBASE
;
225 } else if (pos
== (lines
- 1)) { // Last line will not be a folder
226 levels
[pos
] = SC_FOLDLEVELBASE
;
228 levels
[pos
] = levels
[pos
- 1];
233 void LineVector::SetValue(int pos
, int value
) {
234 //Platform::DebugPrintf("SetValue[%d] = %d\n", pos, value);
235 if ((pos
+ 2) >= size
) {
236 //Platform::DebugPrintf("Resize %d %d\n", size,pos);
237 Expand(pos
+ growSize
);
238 //Platform::DebugPrintf("end Resize %d %d\n", size,pos);
241 ExpandLevels(pos
+ growSize
);
244 linesData
[pos
].startPosition
= value
;
247 void LineVector::Remove(int pos
) {
248 //Platform::DebugPrintf("Remove %d\n", pos);
249 // Retain the markers from the deleted line by oring them into the previous line
251 MergeMarkers(pos
- 1);
253 for (int i
= pos
; i
< lines
; i
++) {
254 linesData
[i
] = linesData
[i
+ 1];
257 // Level information merges back onto previous line
258 int posAbove
= pos
- 1;
261 for (int j
= posAbove
; j
< lines
; j
++) {
262 levels
[j
] = levels
[j
+ 1];
268 int LineVector::LineFromPosition(int pos
) {
269 //Platform::DebugPrintf("LineFromPostion %d lines=%d end = %d\n", pos, lines, linesData[lines].startPosition);
272 //Platform::DebugPrintf("LineFromPosition %d\n", pos);
273 if (pos
>= linesData
[lines
].startPosition
)
278 int middle
= (upper
+ lower
+ 1) / 2; // Round high
279 if (pos
< linesData
[middle
].startPosition
) {
284 } while (lower
< upper
);
285 //Platform::DebugPrintf("LineFromPostion %d %d %d\n", pos, lower, linesData[lower].startPosition, linesData[lower > 1 ? lower - 1 : 0].startPosition);
289 int LineVector::AddMark(int line
, int markerNum
) {
291 if (!linesData
[line
].handleSet
) {
292 // Need new structure to hold marker handle
293 linesData
[line
].handleSet
= new MarkerHandleSet
;
294 if (!linesData
[line
].handleSet
)
297 linesData
[line
].handleSet
->InsertHandle(handleCurrent
, markerNum
);
299 return handleCurrent
;
302 void LineVector::MergeMarkers(int pos
) {
303 if (linesData
[pos
+ 1].handleSet
!= NULL
) {
304 if (linesData
[pos
].handleSet
== NULL
)
305 linesData
[pos
].handleSet
= new MarkerHandleSet
;
306 linesData
[pos
].handleSet
->CombineWith(linesData
[pos
+ 1].handleSet
);
307 delete linesData
[pos
+ 1].handleSet
;
308 linesData
[pos
+ 1].handleSet
= NULL
;
312 void LineVector::DeleteMark(int line
, int markerNum
, bool all
) {
313 if (linesData
[line
].handleSet
) {
314 if (markerNum
== -1) {
315 delete linesData
[line
].handleSet
;
316 linesData
[line
].handleSet
= 0;
318 bool performedDeletion
=
319 linesData
[line
].handleSet
->RemoveNumber(markerNum
);
320 while (all
&& performedDeletion
) {
322 linesData
[line
].handleSet
->RemoveNumber(markerNum
);
324 if (linesData
[line
].handleSet
->Length() == 0) {
325 delete linesData
[line
].handleSet
;
326 linesData
[line
].handleSet
= 0;
332 void LineVector::DeleteMarkFromHandle(int markerHandle
) {
333 int line
= LineFromHandle(markerHandle
);
335 linesData
[line
].handleSet
->RemoveHandle(markerHandle
);
336 if (linesData
[line
].handleSet
->Length() == 0) {
337 delete linesData
[line
].handleSet
;
338 linesData
[line
].handleSet
= 0;
343 int LineVector::LineFromHandle(int markerHandle
) {
344 for (int line
= 0; line
< lines
; line
++) {
345 if (linesData
[line
].handleSet
) {
346 if (linesData
[line
].handleSet
->Contains(markerHandle
)) {
365 void Action::Create(actionType at_
, int position_
, char *data_
, int lenData_
, bool mayCoalesce_
) {
367 position
= position_
;
371 mayCoalesce
= mayCoalesce_
;
374 void Action::Destroy() {
379 void Action::Grab(Action
*source
) {
382 position
= source
->position
;
385 lenData
= source
->lenData
;
386 mayCoalesce
= source
->mayCoalesce
;
388 // Ownership of source data transferred to this
389 source
->position
= 0;
390 source
->at
= startAction
;
393 source
->mayCoalesce
= true;
396 // The undo history stores a sequence of user operations that represent the user's view of the
397 // commands executed on the text.
398 // Each user operation contains a sequence of text insertion and text deletion actions.
399 // All the user operations are stored in a list of individual actions with 'start' actions used
400 // as delimiters between user operations.
401 // Initially there is one start action in the history.
402 // As each action is performed, it is recorded in the history. The action may either become
403 // part of the current user operation or may start a new user operation. If it is to be part of the
404 // current operation, then it overwrites the current last action. If it is to be part of a new
405 // operation, it is appended after the current last action.
406 // After writing the new action, a new start action is appended at the end of the history.
407 // The decision of whether to start a new user operation is based upon two factors. If a
408 // compound operation has been explicitly started by calling BeginUndoAction and no matching
409 // EndUndoAction (these calls nest) has been called, then the action is coalesced into the current
410 // operation. If there is no outstanding BeginUndoAction call then a new operation is started
411 // unless it looks as if the new action is caused by the user typing or deleting a stream of text.
412 // Sequences that look like typing or deletion are coalesced into a single user operation.
414 UndoHistory::UndoHistory() {
417 actions
= new Action
[lenActions
];
420 undoSequenceDepth
= 0;
423 actions
[currentAction
].Create(startAction
);
426 UndoHistory::~UndoHistory() {
431 void UndoHistory::EnsureUndoRoom() {
432 // Have to test that there is room for 2 more actions in the array
433 // as two actions may be created by the calling function
434 if (currentAction
>= (lenActions
- 2)) {
435 // Run out of undo nodes so extend the array
436 int lenActionsNew
= lenActions
* 2;
437 Action
*actionsNew
= new Action
[lenActionsNew
];
440 for (int act
= 0; act
<= currentAction
; act
++)
441 actionsNew
[act
].Grab(&actions
[act
]);
443 lenActions
= lenActionsNew
;
444 actions
= actionsNew
;
448 void UndoHistory::AppendAction(actionType at
, int position
, char *data
, int lengthData
) {
450 //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction);
451 //Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at,
452 // actions[currentAction - 1].position, actions[currentAction - 1].lenData);
453 if (currentAction
< savePoint
) {
456 if (currentAction
>= 1) {
457 if (0 == undoSequenceDepth
) {
458 // Top level actions may not always be coalesced
459 Action
&actPrevious
= actions
[currentAction
- 1];
460 // See if current action can be coalesced into previous action
461 // Will work if both are inserts or deletes and position is same
462 if (at
!= actPrevious
.at
) {
464 } else if (currentAction
== savePoint
) {
466 } else if ((at
== insertAction
) &&
467 (position
!= (actPrevious
.position
+ actPrevious
.lenData
*2))) {
468 // Insertions must be immediately after to coalesce
470 } else if (!actions
[currentAction
].mayCoalesce
) {
471 // Not allowed to coalesce if this set
473 } else if (at
== removeAction
) {
474 if ((lengthData
== 1) || (lengthData
== 2)){
475 if ((position
+ lengthData
* 2) == actPrevious
.position
) {
477 } else if (position
== actPrevious
.position
) {
480 // Removals must be at same position to coalesce
484 // Removals must be of one character to coalesce
488 //Platform::DebugPrintf("action coalesced\n");
492 // Actions not at top level are always coalesced unless this is after return to top level
493 if (!actions
[currentAction
].mayCoalesce
)
499 actions
[currentAction
].Create(at
, position
, data
, lengthData
);
501 actions
[currentAction
].Create(startAction
);
502 maxAction
= currentAction
;
505 void UndoHistory::BeginUndoAction() {
507 if (undoSequenceDepth
== 0) {
508 if (actions
[currentAction
].at
!= startAction
) {
510 actions
[currentAction
].Create(startAction
);
511 maxAction
= currentAction
;
513 actions
[currentAction
].mayCoalesce
= false;
518 void UndoHistory::EndUndoAction() {
521 if (0 == undoSequenceDepth
) {
522 if (actions
[currentAction
].at
!= startAction
) {
524 actions
[currentAction
].Create(startAction
);
525 maxAction
= currentAction
;
527 actions
[currentAction
].mayCoalesce
= false;
531 void UndoHistory::DropUndoSequence() {
532 undoSequenceDepth
= 0;
535 void UndoHistory::DeleteUndoHistory() {
536 for (int i
= 1; i
< maxAction
; i
++)
537 actions
[i
].Destroy();
540 actions
[currentAction
].Create(startAction
);
544 void UndoHistory::SetSavePoint() {
545 savePoint
= currentAction
;
548 bool UndoHistory::IsSavePoint() const {
549 return savePoint
== currentAction
;
552 bool UndoHistory::CanUndo() const {
553 return (currentAction
> 0) && (maxAction
> 0);
556 int UndoHistory::StartUndo() {
557 // Drop any trailing startAction
558 if (actions
[currentAction
].at
== startAction
&& currentAction
> 0)
561 // Count the steps in this action
562 int act
= currentAction
;
563 while (actions
[act
].at
!= startAction
&& act
> 0) {
566 return currentAction
- act
;
569 const Action
&UndoHistory::GetUndoStep() const {
570 return actions
[currentAction
];
573 void UndoHistory::CompletedUndoStep() {
577 bool UndoHistory::CanRedo() const {
578 return maxAction
> currentAction
;
581 int UndoHistory::StartRedo() {
582 // Drop any leading startAction
583 if (actions
[currentAction
].at
== startAction
&& currentAction
< maxAction
)
586 // Count the steps in this action
587 int act
= currentAction
;
588 while (actions
[act
].at
!= startAction
&& act
< maxAction
) {
591 return act
- currentAction
;
594 const Action
&UndoHistory::GetRedoStep() const {
595 return actions
[currentAction
];
598 void UndoHistory::CompletedRedoStep() {
602 CellBuffer::CellBuffer(int initialLength
) {
603 body
= new char[initialLength
];
604 size
= initialLength
;
607 gaplen
= initialLength
;
608 part2body
= body
+ gaplen
;
610 collectingUndo
= true;
614 CellBuffer::~CellBuffer() {
619 void CellBuffer::GapTo(int position
) {
620 if (position
== part1len
)
622 if (position
< part1len
) {
623 int diff
= part1len
- position
;
624 //Platform::DebugPrintf("Move gap backwards to %d diff = %d part1len=%d length=%d \n", position,diff, part1len, length);
625 for (int i
= 0; i
< diff
; i
++)
626 body
[part1len
+ gaplen
- i
- 1] = body
[part1len
- i
- 1];
627 } else { // position > part1len
628 int diff
= position
- part1len
;
629 //Platform::DebugPrintf("Move gap forwards to %d diff =%d\n", position,diff);
630 for (int i
= 0; i
< diff
; i
++)
631 body
[part1len
+ i
] = body
[part1len
+ gaplen
+ i
];
634 part2body
= body
+ gaplen
;
637 void CellBuffer::RoomFor(int insertionLength
) {
638 //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength);
639 if (gaplen
<= insertionLength
) {
640 //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength);
641 if (growSize
* 6 < size
)
643 int newSize
= size
+ insertionLength
+ growSize
;
648 // To make it easier to write code that uses ByteAt, a position outside the range of the buffer
649 // can be retrieved. All characters outside the range have the value '\0'.
650 char CellBuffer::ByteAt(int position
) {
651 if (position
< part1len
) {
655 return body
[position
];
658 if (position
>= length
) {
661 return part2body
[position
];
666 void CellBuffer::SetByteAt(int position
, char ch
) {
669 //Platform::DebugPrintf("Bad position %d\n",position);
672 if (position
>= length
+ 11) {
673 Platform::DebugPrintf("Very Bad position %d of %d\n", position
, length
);
677 if (position
>= length
) {
678 //Platform::DebugPrintf("Bad position %d of %d\n",position,length);
682 if (position
< part1len
) {
685 part2body
[position
] = ch
;
689 char CellBuffer::CharAt(int position
) {
690 return ByteAt(position
*2);
693 void CellBuffer::GetCharRange(char *buffer
, int position
, int lengthRetrieve
) {
694 if (lengthRetrieve
< 0)
698 int bytePos
= position
* 2;
699 if ((bytePos
+ lengthRetrieve
* 2) > length
) {
700 Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n", bytePos
,
701 lengthRetrieve
, length
);
704 GapTo(0); // Move the buffer so its easy to subscript into it
705 char *pb
= part2body
+ bytePos
;
706 while (lengthRetrieve
--) {
712 char CellBuffer::StyleAt(int position
) {
713 return ByteAt(position
*2 + 1);
716 const char *CellBuffer::InsertString(int position
, char *s
, int insertLength
) {
718 // InsertString and DeleteChars are the bottleneck though which all changes occur
720 if (collectingUndo
) {
721 // Save into the undo/redo stack, but only the characters - not the formatting
722 // This takes up about half load time
723 data
= new char[insertLength
/ 2];
724 for (int i
= 0; i
< insertLength
/ 2; i
++) {
727 uh
.AppendAction(insertAction
, position
, data
, insertLength
/ 2);
730 BasicInsertString(position
, s
, insertLength
);
735 void CellBuffer::InsertCharStyle(int position
, char ch
, char style
) {
739 InsertString(position
*2, s
, 2);
742 bool CellBuffer::SetStyleAt(int position
, char style
, char mask
) {
744 char curVal
= ByteAt(position
* 2 + 1);
745 if ((curVal
& mask
) != style
) {
746 SetByteAt(position
*2 + 1, static_cast<char>((curVal
& ~mask
) | style
));
753 bool CellBuffer::SetStyleFor(int position
, int lengthStyle
, char style
, char mask
) {
754 int bytePos
= position
* 2 + 1;
755 bool changed
= false;
756 PLATFORM_ASSERT(lengthStyle
== 0 ||
757 (lengthStyle
> 0 && lengthStyle
+ position
< length
));
758 while (lengthStyle
--) {
759 char curVal
= ByteAt(bytePos
);
760 if ((curVal
& mask
) != style
) {
761 SetByteAt(bytePos
, static_cast<char>((curVal
& ~mask
) | style
));
769 const char *CellBuffer::DeleteChars(int position
, int deleteLength
) {
770 // InsertString and DeleteChars are the bottleneck though which all changes occur
773 if (collectingUndo
) {
774 // Save into the undo/redo stack, but only the characters - not the formatting
775 data
= new char[deleteLength
/ 2];
776 for (int i
= 0; i
< deleteLength
/ 2; i
++) {
777 data
[i
] = ByteAt(position
+ i
* 2);
779 uh
.AppendAction(removeAction
, position
, data
, deleteLength
/ 2);
782 BasicDeleteChars(position
, deleteLength
);
787 int CellBuffer::ByteLength() {
791 int CellBuffer::Length() {
792 return ByteLength() / 2;
795 void CellBuffer::Allocate(int newSize
) {
796 if (newSize
> length
) {
798 char *newBody
= new char[newSize
];
799 memcpy(newBody
, body
, length
);
802 gaplen
+= newSize
- size
;
803 part2body
= body
+ gaplen
;
808 int CellBuffer::Lines() {
809 //Platform::DebugPrintf("Lines = %d\n", lv.lines);
813 int CellBuffer::LineStart(int line
) {
816 else if (line
> lv
.lines
)
819 return lv
.linesData
[line
].startPosition
;
822 bool CellBuffer::IsReadOnly() {
826 void CellBuffer::SetReadOnly(bool set
) {
830 void CellBuffer::SetSavePoint() {
834 bool CellBuffer::IsSavePoint() {
835 return uh
.IsSavePoint();
838 int CellBuffer::AddMark(int line
, int markerNum
) {
839 if ((line
>= 0) && (line
< lv
.lines
)) {
840 return lv
.AddMark(line
, markerNum
);
845 void CellBuffer::DeleteMark(int line
, int markerNum
) {
846 if ((line
>= 0) && (line
< lv
.lines
)) {
847 lv
.DeleteMark(line
, markerNum
, false);
851 void CellBuffer::DeleteMarkFromHandle(int markerHandle
) {
852 lv
.DeleteMarkFromHandle(markerHandle
);
855 int CellBuffer::GetMark(int line
) {
856 if ((line
>= 0) && (line
< lv
.lines
) && (lv
.linesData
[line
].handleSet
))
857 return lv
.linesData
[line
].handleSet
->MarkValue();
861 void CellBuffer::DeleteAllMarks(int markerNum
) {
862 for (int line
= 0; line
< lv
.lines
; line
++) {
863 lv
.DeleteMark(line
, markerNum
, true);
867 int CellBuffer::LineFromHandle(int markerHandle
) {
868 return lv
.LineFromHandle(markerHandle
);
873 void CellBuffer::BasicInsertString(int position
, char *s
, int insertLength
) {
874 //Platform::DebugPrintf("Inserting at %d for %d\n", position, insertLength);
875 if (insertLength
== 0)
877 RoomFor(insertLength
);
880 memcpy(body
+ part1len
, s
, insertLength
);
881 length
+= insertLength
;
882 part1len
+= insertLength
;
883 gaplen
-= insertLength
;
884 part2body
= body
+ gaplen
;
886 int lineInsert
= lv
.LineFromPosition(position
/ 2) + 1;
887 // Point all the lines after the insertion point further along in the buffer
888 for (int lineAfter
= lineInsert
; lineAfter
<= lv
.lines
; lineAfter
++) {
889 lv
.linesData
[lineAfter
].startPosition
+= insertLength
/ 2;
892 if ((position
- 2) >= 0)
893 chPrev
= ByteAt(position
- 2);
895 if ((position
+ insertLength
) < length
)
896 chAfter
= ByteAt(position
+ insertLength
);
897 if (chPrev
== '\r' && chAfter
== '\n') {
898 //Platform::DebugPrintf("Splitting a crlf pair at %d\n", lineInsert);
899 // Splitting up a crlf pair at position
900 lv
.InsertValue(lineInsert
, position
/ 2);
904 for (int i
= 0; i
< insertLength
; i
+= 2) {
907 //Platform::DebugPrintf("Inserting cr at %d\n", lineInsert);
908 lv
.InsertValue(lineInsert
, (position
+ i
) / 2 + 1);
910 } else if (ch
== '\n') {
911 if (chPrev
== '\r') {
912 //Platform::DebugPrintf("Patching cr before lf at %d\n", lineInsert-1);
913 // Patch up what was end of line
914 lv
.SetValue(lineInsert
- 1, (position
+ i
) / 2 + 1);
916 //Platform::DebugPrintf("Inserting lf at %d\n", lineInsert);
917 lv
.InsertValue(lineInsert
, (position
+ i
) / 2 + 1);
923 // Joining two lines where last insertion is cr and following text starts with lf
924 if (chAfter
== '\n') {
926 //Platform::DebugPrintf("Joining cr before lf at %d\n", lineInsert-1);
927 // End of line already in buffer so drop the newly created one
928 lv
.Remove(lineInsert
- 1);
933 void CellBuffer::BasicDeleteChars(int position
, int deleteLength
) {
934 //Platform::DebugPrintf("Deleting at %d for %d\n", position, deleteLength);
935 if (deleteLength
== 0)
938 if ((position
== 0) && (deleteLength
== length
)) {
939 // If whole buffer is being deleted, faster to reinitialise lines data
940 // than to delete each line.
941 //printf("Whole buffer being deleted\n");
944 // Have to fix up line positions before doing deletion as looking at text in buffer
945 // to work out which lines have been removed
947 int lineRemove
= lv
.LineFromPosition(position
/ 2) + 1;
948 // Point all the lines after the insertion point further along in the buffer
949 for (int lineAfter
= lineRemove
; lineAfter
<= lv
.lines
; lineAfter
++) {
950 lv
.linesData
[lineAfter
].startPosition
-= deleteLength
/ 2;
954 chPrev
= ByteAt(position
- 2);
955 char chBefore
= chPrev
;
957 if (position
< length
)
958 chNext
= ByteAt(position
);
959 bool ignoreNL
= false;
960 if (chPrev
== '\r' && chNext
== '\n') {
961 //Platform::DebugPrintf("Deleting lf after cr, move line end to cr at %d\n", lineRemove);
963 lv
.SetValue(lineRemove
, position
/ 2);
965 ignoreNL
= true; // First \n is not real deletion
969 for (int i
= 0; i
< deleteLength
; i
+= 2) {
971 if ((position
+ i
+ 2) < length
)
972 chNext
= ByteAt(position
+ i
+ 2);
973 //Platform::DebugPrintf("Deleting %d %x\n", i, ch);
975 if (chNext
!= '\n') {
976 //Platform::DebugPrintf("Removing cr end of line\n");
977 lv
.Remove(lineRemove
);
979 } else if (ch
== '\n') {
981 ignoreNL
= false; // Further \n are real deletions
983 //Platform::DebugPrintf("Removing lf end of line\n");
984 lv
.Remove(lineRemove
);
990 // May have to fix up end if last deletion causes cr to be next to lf
991 // or removes one of a crlf pair
993 if ((position
+ deleteLength
) < length
)
994 chAfter
= ByteAt(position
+ deleteLength
);
995 if (chBefore
== '\r' && chAfter
== '\n') {
996 //d.printf("Joining cr before lf at %d\n", lineRemove);
997 // Using lineRemove-1 as cr ended line before start of deletion
998 lv
.Remove(lineRemove
- 1);
999 lv
.SetValue(lineRemove
- 1, position
/ 2 + 1);
1003 length
-= deleteLength
;
1004 gaplen
+= deleteLength
;
1005 part2body
= body
+ gaplen
;
1008 bool CellBuffer::SetUndoCollection(bool collectUndo
) {
1009 collectingUndo
= collectUndo
;
1010 uh
.DropUndoSequence();
1011 return collectingUndo
;
1014 bool CellBuffer::IsCollectingUndo() {
1015 return collectingUndo
;
1018 void CellBuffer::BeginUndoAction() {
1019 uh
.BeginUndoAction();
1022 void CellBuffer::EndUndoAction() {
1026 void CellBuffer::DeleteUndoHistory() {
1027 uh
.DeleteUndoHistory();
1030 bool CellBuffer::CanUndo() {
1031 return (!readOnly
) && (uh
.CanUndo());
1034 int CellBuffer::StartUndo() {
1035 return uh
.StartUndo();
1038 const Action
&CellBuffer::GetUndoStep() const {
1039 return uh
.GetUndoStep();
1042 void CellBuffer::PerformUndoStep() {
1043 const Action
&actionStep
= uh
.GetUndoStep();
1044 if (actionStep
.at
== insertAction
) {
1045 BasicDeleteChars(actionStep
.position
, actionStep
.lenData
*2);
1046 } else if (actionStep
.at
== removeAction
) {
1047 char *styledData
= new char[actionStep
.lenData
* 2];
1048 for (int i
= 0; i
< actionStep
.lenData
; i
++) {
1049 styledData
[i
*2] = actionStep
.data
[i
];
1050 styledData
[i
*2 + 1] = 0;
1052 BasicInsertString(actionStep
.position
, styledData
, actionStep
.lenData
*2);
1053 delete []styledData
;
1055 uh
.CompletedUndoStep();
1058 bool CellBuffer::CanRedo() {
1059 return (!readOnly
) && (uh
.CanRedo());
1062 int CellBuffer::StartRedo() {
1063 return uh
.StartRedo();
1066 const Action
&CellBuffer::GetRedoStep() const {
1067 return uh
.GetRedoStep();
1070 void CellBuffer::PerformRedoStep() {
1071 const Action
&actionStep
= uh
.GetRedoStep();
1072 if (actionStep
.at
== insertAction
) {
1073 char *styledData
= new char[actionStep
.lenData
* 2];
1074 for (int i
= 0; i
< actionStep
.lenData
; i
++) {
1075 styledData
[i
*2] = actionStep
.data
[i
];
1076 styledData
[i
*2 + 1] = 0;
1078 BasicInsertString(actionStep
.position
, styledData
, actionStep
.lenData
*2);
1079 delete []styledData
;
1080 } else if (actionStep
.at
== removeAction
) {
1081 BasicDeleteChars(actionStep
.position
, actionStep
.lenData
*2);
1083 uh
.CompletedRedoStep();
1086 int CellBuffer::SetLineState(int line
, int state
) {
1087 int stateOld
= lineStates
[line
];
1088 lineStates
[line
] = state
;
1092 int CellBuffer::GetLineState(int line
) {
1093 return lineStates
[line
];
1096 int CellBuffer::GetMaxLineState() {
1097 return lineStates
.Length();
1100 int CellBuffer::SetLevel(int line
, int level
) {
1102 if ((line
>= 0) && (line
< lv
.lines
)) {
1106 prev
= lv
.levels
[line
];
1107 if (lv
.levels
[line
] != level
) {
1108 lv
.levels
[line
] = level
;
1114 int CellBuffer::GetLevel(int line
) {
1115 if (lv
.levels
&& (line
>= 0) && (line
< lv
.lines
)) {
1116 return lv
.levels
[line
];
1118 return SC_FOLDLEVELBASE
;
1122 void CellBuffer::ClearLevels() {