1 // Scintilla source code edit control
2 /** @file CellBuffer.cxx
3 ** Manages a buffer of cells.
4 **/
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.
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <stdarg.h>
12
13 #include "Platform.h"
14
15 #include "Scintilla.h"
16 #include "SVector.h"
17 #include "CellBuffer.h"
18
MarkerHandleSet()19 MarkerHandleSet::MarkerHandleSet() {
20 root = 0;
21 }
22
~MarkerHandleSet()23 MarkerHandleSet::~MarkerHandleSet() {
24 MarkerHandleNumber *mhn = root;
25 while (mhn) {
26 MarkerHandleNumber *mhnToFree = mhn;
27 mhn = mhn->next;
28 delete mhnToFree;
29 }
30 root = 0;
31 }
32
Length()33 int MarkerHandleSet::Length() {
34 int c = 0;
35 MarkerHandleNumber *mhn = root;
36 while (mhn) {
37 c++;
38 mhn = mhn->next;
39 }
40 return c;
41 }
42
NumberFromHandle(int handle)43 int MarkerHandleSet::NumberFromHandle(int handle) {
44 MarkerHandleNumber *mhn = root;
45 while (mhn) {
46 if (mhn->handle == handle) {
47 return mhn->number;
48 }
49 mhn = mhn->next;
50 }
51 return - 1;
52 }
53
MarkValue()54 int MarkerHandleSet::MarkValue() {
55 unsigned int m = 0;
56 MarkerHandleNumber *mhn = root;
57 while (mhn) {
58 m |= (1 << mhn->number);
59 mhn = mhn->next;
60 }
61 return m;
62 }
63
Contains(int handle)64 bool MarkerHandleSet::Contains(int handle) {
65 MarkerHandleNumber *mhn = root;
66 while (mhn) {
67 if (mhn->handle == handle) {
68 return true;
69 }
70 mhn = mhn->next;
71 }
72 return false;
73 }
74
InsertHandle(int handle,int markerNum)75 bool MarkerHandleSet::InsertHandle(int handle, int markerNum) {
76 MarkerHandleNumber *mhn = new MarkerHandleNumber;
77 if (!mhn)
78 return false;
79 mhn->handle = handle;
80 mhn->number = markerNum;
81 mhn->next = root;
82 root = mhn;
83 return true;
84 }
85
RemoveHandle(int handle)86 void MarkerHandleSet::RemoveHandle(int handle) {
87 MarkerHandleNumber **pmhn = &root;
88 while (*pmhn) {
89 MarkerHandleNumber *mhn = *pmhn;
90 if (mhn->handle == handle) {
91 *pmhn = mhn->next;
92 delete mhn;
93 return ;
94 }
95 pmhn = &((*pmhn)->next);
96 }
97 }
98
RemoveNumber(int markerNum)99 bool MarkerHandleSet::RemoveNumber(int markerNum) {
100 bool performedDeletion = false;
101 MarkerHandleNumber **pmhn = &root;
102 while (*pmhn) {
103 MarkerHandleNumber *mhn = *pmhn;
104 if (mhn->number == markerNum) {
105 *pmhn = mhn->next;
106 delete mhn;
107 performedDeletion = true;
108 } else {
109 pmhn = &((*pmhn)->next);
110 }
111 }
112 return performedDeletion;
113 }
114
CombineWith(MarkerHandleSet * other)115 void MarkerHandleSet::CombineWith(MarkerHandleSet *other) {
116 MarkerHandleNumber **pmhn = &root;
117 while (*pmhn) {
118 pmhn = &((*pmhn)->next);
119 }
120 *pmhn = other->root;
121 other->root = 0;
122 }
123
LineVector()124 LineVector::LineVector() {
125 linesData = 0;
126 lines = 0;
127 size = 0;
128 levels = 0;
129 sizeLevels = 0;
130 handleCurrent = 1;
131 growSize = 1000;
132
133 Init();
134 }
135
~LineVector()136 LineVector::~LineVector() {
137 for (int line = 0; line < lines; line++) {
138 delete linesData[line].handleSet;
139 linesData[line].handleSet = 0;
140 }
141 delete []linesData;
142 linesData = 0;
143 delete []levels;
144 levels = 0;
145 }
146
Init()147 void LineVector::Init() {
148 for (int line = 0; line < lines; line++) {
149 delete linesData[line].handleSet;
150 linesData[line].handleSet = 0;
151 }
152 delete []linesData;
153 linesData = new LineData[static_cast<int>(growSize)];
154 size = growSize;
155 lines = 1;
156 delete []levels;
157 levels = 0;
158 sizeLevels = 0;
159 }
160
Expand(int sizeNew)161 void LineVector::Expand(int sizeNew) {
162 LineData *linesDataNew = new LineData[sizeNew];
163 if (linesDataNew) {
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
167 delete []linesData;
168 linesData = linesDataNew;
169 size = sizeNew;
170 } else {
171 Platform::DebugPrintf("No memory available\n");
172 // TODO: Blow up
173 }
174
175 }
176
ExpandLevels(int sizeNew)177 void LineVector::ExpandLevels(int sizeNew) {
178 if (sizeNew == -1)
179 sizeNew = size;
180 int *levelsNew = new int[sizeNew];
181 if (levelsNew) {
182 int i = 0;
183 for (; i < sizeLevels; i++)
184 levelsNew[i] = levels[i];
185 for (; i < sizeNew; i++)
186 levelsNew[i] = SC_FOLDLEVELBASE;
187 delete []levels;
188 levels = levelsNew;
189 sizeLevels = sizeNew;
190 } else {
191 Platform::DebugPrintf("No memory available\n");
192 // TODO: Blow up
193 }
194
195 }
196
ClearLevels()197 void LineVector::ClearLevels() {
198 delete []levels;
199 levels = 0;
200 sizeLevels = 0;
201 }
202
InsertValue(int pos,int value)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)
207 growSize *= 2;
208 Expand(size + growSize);
209 if (levels) {
210 ExpandLevels(size + growSize);
211 }
212 }
213 lines++;
214 for (int i = lines; i > pos; i--) {
215 linesData[i] = linesData[i - 1];
216 }
217 linesData[pos].startPosition = value;
218 linesData[pos].handleSet = 0;
219 if (levels) {
220 for (int j = lines; j > pos; j--) {
221 levels[j] = levels[j - 1];
222 }
223 if (pos == 0) {
224 levels[pos] = SC_FOLDLEVELBASE;
225 } else if (pos == (lines - 1)) { // Last line will not be a folder
226 levels[pos] = SC_FOLDLEVELBASE;
227 } else {
228 levels[pos] = levels[pos - 1];
229 }
230 }
231 }
232
SetValue(int pos,int value)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);
239 lines = pos;
240 if (levels) {
241 ExpandLevels(pos + growSize);
242 }
243 }
244 linesData[pos].startPosition = value;
245 }
246
Remove(int pos)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
250 if (pos > 0) {
251 MergeMarkers(pos - 1);
252 }
253 for (int i = pos; i < lines; i++) {
254 linesData[i] = linesData[i + 1];
255 }
256 if (levels) {
257 // Move up following lines but merge header flag from this line
258 // to line before to avoid a temporary disappearence causing expansion.
259 int firstHeader = levels[pos] & SC_FOLDLEVELHEADERFLAG;
260 for (int j = pos; j < lines; j++) {
261 levels[j] = levels[j + 1];
262 }
263 if (pos > 0)
264 levels[pos-1] |= firstHeader;
265 }
266 lines--;
267 }
268
LineFromPosition(int pos)269 int LineVector::LineFromPosition(int pos) {
270 //Platform::DebugPrintf("LineFromPostion %d lines=%d end = %d\n", pos, lines, linesData[lines].startPosition);
271 if (lines == 0)
272 return 0;
273 //Platform::DebugPrintf("LineFromPosition %d\n", pos);
274 if (pos >= linesData[lines].startPosition)
275 return lines - 1;
276 int lower = 0;
277 int upper = lines;
278 do {
279 int middle = (upper + lower + 1) / 2; // Round high
280 if (pos < linesData[middle].startPosition) {
281 upper = middle - 1;
282 } else {
283 lower = middle;
284 }
285 } while (lower < upper);
286 //Platform::DebugPrintf("LineFromPostion %d %d %d\n", pos, lower, linesData[lower].startPosition, linesData[lower > 1 ? lower - 1 : 0].startPosition);
287 return lower;
288 }
289
AddMark(int line,int markerNum)290 int LineVector::AddMark(int line, int markerNum) {
291 handleCurrent++;
292 if (!linesData[line].handleSet) {
293 // Need new structure to hold marker handle
294 linesData[line].handleSet = new MarkerHandleSet;
295 if (!linesData[line].handleSet)
296 return - 1;
297 }
298 linesData[line].handleSet->InsertHandle(handleCurrent, markerNum);
299
300 return handleCurrent;
301 }
302
MergeMarkers(int pos)303 void LineVector::MergeMarkers(int pos) {
304 if (linesData[pos + 1].handleSet != NULL) {
305 if (linesData[pos].handleSet == NULL )
306 linesData[pos].handleSet = new MarkerHandleSet;
307 linesData[pos].handleSet->CombineWith(linesData[pos + 1].handleSet);
308 delete linesData[pos + 1].handleSet;
309 linesData[pos + 1].handleSet = NULL;
310 }
311 }
312
DeleteMark(int line,int markerNum,bool all)313 void LineVector::DeleteMark(int line, int markerNum, bool all) {
314 if (linesData[line].handleSet) {
315 if (markerNum == -1) {
316 delete linesData[line].handleSet;
317 linesData[line].handleSet = 0;
318 } else {
319 bool performedDeletion =
320 linesData[line].handleSet->RemoveNumber(markerNum);
321 while (all && performedDeletion) {
322 performedDeletion =
323 linesData[line].handleSet->RemoveNumber(markerNum);
324 }
325 if (linesData[line].handleSet->Length() == 0) {
326 delete linesData[line].handleSet;
327 linesData[line].handleSet = 0;
328 }
329 }
330 }
331 }
332
DeleteMarkFromHandle(int markerHandle)333 void LineVector::DeleteMarkFromHandle(int markerHandle) {
334 int line = LineFromHandle(markerHandle);
335 if (line >= 0) {
336 linesData[line].handleSet->RemoveHandle(markerHandle);
337 if (linesData[line].handleSet->Length() == 0) {
338 delete linesData[line].handleSet;
339 linesData[line].handleSet = 0;
340 }
341 }
342 }
343
LineFromHandle(int markerHandle)344 int LineVector::LineFromHandle(int markerHandle) {
345 for (int line = 0; line < lines; line++) {
346 if (linesData[line].handleSet) {
347 if (linesData[line].handleSet->Contains(markerHandle)) {
348 return line;
349 }
350 }
351 }
352 return - 1;
353 }
354
Action()355 Action::Action() {
356 at = startAction;
357 position = 0;
358 data = 0;
359 lenData = 0;
360 }
361
~Action()362 Action::~Action() {
363 Destroy();
364 }
365
Create(actionType at_,int position_,char * data_,int lenData_,bool mayCoalesce_)366 void Action::Create(actionType at_, int position_, char *data_, int lenData_, bool mayCoalesce_) {
367 delete []data;
368 position = position_;
369 at = at_;
370 data = data_;
371 lenData = lenData_;
372 mayCoalesce = mayCoalesce_;
373 }
374
Destroy()375 void Action::Destroy() {
376 delete []data;
377 data = 0;
378 }
379
Grab(Action * source)380 void Action::Grab(Action *source) {
381 delete []data;
382
383 position = source->position;
384 at = source->at;
385 data = source->data;
386 lenData = source->lenData;
387 mayCoalesce = source->mayCoalesce;
388
389 // Ownership of source data transferred to this
390 source->position = 0;
391 source->at = startAction;
392 source->data = 0;
393 source->lenData = 0;
394 source->mayCoalesce = true;
395 }
396
397 // The undo history stores a sequence of user operations that represent the user's view of the
398 // commands executed on the text.
399 // Each user operation contains a sequence of text insertion and text deletion actions.
400 // All the user operations are stored in a list of individual actions with 'start' actions used
401 // as delimiters between user operations.
402 // Initially there is one start action in the history.
403 // As each action is performed, it is recorded in the history. The action may either become
404 // part of the current user operation or may start a new user operation. If it is to be part of the
405 // current operation, then it overwrites the current last action. If it is to be part of a new
406 // operation, it is appended after the current last action.
407 // After writing the new action, a new start action is appended at the end of the history.
408 // The decision of whether to start a new user operation is based upon two factors. If a
409 // compound operation has been explicitly started by calling BeginUndoAction and no matching
410 // EndUndoAction (these calls nest) has been called, then the action is coalesced into the current
411 // operation. If there is no outstanding BeginUndoAction call then a new operation is started
412 // unless it looks as if the new action is caused by the user typing or deleting a stream of text.
413 // Sequences that look like typing or deletion are coalesced into a single user operation.
414
UndoHistory()415 UndoHistory::UndoHistory() {
416
417 lenActions = 100;
418 actions = new Action[lenActions];
419 maxAction = 0;
420 currentAction = 0;
421 undoSequenceDepth = 0;
422 savePoint = 0;
423
424 actions[currentAction].Create(startAction);
425 }
426
~UndoHistory()427 UndoHistory::~UndoHistory() {
428 delete []actions;
429 actions = 0;
430 }
431
EnsureUndoRoom()432 void UndoHistory::EnsureUndoRoom() {
433 // Have to test that there is room for 2 more actions in the array
434 // as two actions may be created by the calling function
435 if (currentAction >= (lenActions - 2)) {
436 // Run out of undo nodes so extend the array
437 int lenActionsNew = lenActions * 2;
438 Action *actionsNew = new Action[lenActionsNew];
439 if (!actionsNew)
440 return ;
441 for (int act = 0; act <= currentAction; act++)
442 actionsNew[act].Grab(&actions[act]);
443 delete []actions;
444 lenActions = lenActionsNew;
445 actions = actionsNew;
446 }
447 }
448
AppendAction(actionType at,int position,char * data,int lengthData)449 void UndoHistory::AppendAction(actionType at, int position, char *data, int lengthData) {
450 EnsureUndoRoom();
451 //Platform::DebugPrintf("%% %d action %d %d %d\n", at, position, lengthData, currentAction);
452 //Platform::DebugPrintf("^ %d action %d %d\n", actions[currentAction - 1].at,
453 // actions[currentAction - 1].position, actions[currentAction - 1].lenData);
454 if (currentAction < savePoint) {
455 savePoint = -1;
456 }
457 if (currentAction >= 1) {
458 if (0 == undoSequenceDepth) {
459 // Top level actions may not always be coalesced
460 Action &actPrevious = actions[currentAction - 1];
461 // See if current action can be coalesced into previous action
462 // Will work if both are inserts or deletes and position is same
463 if (at != actPrevious.at) {
464 currentAction++;
465 } else if (currentAction == savePoint) {
466 currentAction++;
467 } else if ((at == insertAction) &&
468 (position != (actPrevious.position + actPrevious.lenData))) {
469 // Insertions must be immediately after to coalesce
470 currentAction++;
471 } else if (!actions[currentAction].mayCoalesce) {
472 // Not allowed to coalesce if this set
473 currentAction++;
474 } else if (at == removeAction) {
475 if ((lengthData == 1) || (lengthData == 2)){
476 if ((position + lengthData) == actPrevious.position) {
477 ; // Backspace -> OK
478 } else if (position == actPrevious.position) {
479 ; // Delete -> OK
480 } else {
481 // Removals must be at same position to coalesce
482 currentAction++;
483 }
484 } else {
485 // Removals must be of one character to coalesce
486 currentAction++;
487 }
488 } else {
489 //Platform::DebugPrintf("action coalesced\n");
490 }
491
492 } else {
493 // Actions not at top level are always coalesced unless this is after return to top level
494 if (!actions[currentAction].mayCoalesce)
495 currentAction++;
496 }
497 } else {
498 currentAction++;
499 }
500 actions[currentAction].Create(at, position, data, lengthData);
501 currentAction++;
502 actions[currentAction].Create(startAction);
503 maxAction = currentAction;
504 }
505
BeginUndoAction()506 void UndoHistory::BeginUndoAction() {
507 EnsureUndoRoom();
508 if (undoSequenceDepth == 0) {
509 if (actions[currentAction].at != startAction) {
510 currentAction++;
511 actions[currentAction].Create(startAction);
512 maxAction = currentAction;
513 }
514 actions[currentAction].mayCoalesce = false;
515 }
516 undoSequenceDepth++;
517 }
518
EndUndoAction()519 void UndoHistory::EndUndoAction() {
520 EnsureUndoRoom();
521 undoSequenceDepth--;
522 if (0 == undoSequenceDepth) {
523 if (actions[currentAction].at != startAction) {
524 currentAction++;
525 actions[currentAction].Create(startAction);
526 maxAction = currentAction;
527 }
528 actions[currentAction].mayCoalesce = false;
529 }
530 }
531
DropUndoSequence()532 void UndoHistory::DropUndoSequence() {
533 undoSequenceDepth = 0;
534 }
535
DeleteUndoHistory()536 void UndoHistory::DeleteUndoHistory() {
537 for (int i = 1; i < maxAction; i++)
538 actions[i].Destroy();
539 maxAction = 0;
540 currentAction = 0;
541 actions[currentAction].Create(startAction);
542 savePoint = 0;
543 }
544
SetSavePoint()545 void UndoHistory::SetSavePoint() {
546 savePoint = currentAction;
547 }
548
IsSavePoint() const549 bool UndoHistory::IsSavePoint() const {
550 return savePoint == currentAction;
551 }
552
CanUndo() const553 bool UndoHistory::CanUndo() const {
554 return (currentAction > 0) && (maxAction > 0);
555 }
556
StartUndo()557 int UndoHistory::StartUndo() {
558 // Drop any trailing startAction
559 if (actions[currentAction].at == startAction && currentAction > 0)
560 currentAction--;
561
562 // Count the steps in this action
563 int act = currentAction;
564 while (actions[act].at != startAction && act > 0) {
565 act--;
566 }
567 return currentAction - act;
568 }
569
GetUndoStep() const570 const Action &UndoHistory::GetUndoStep() const {
571 return actions[currentAction];
572 }
573
CompletedUndoStep()574 void UndoHistory::CompletedUndoStep() {
575 currentAction--;
576 }
577
CanRedo() const578 bool UndoHistory::CanRedo() const {
579 return maxAction > currentAction;
580 }
581
StartRedo()582 int UndoHistory::StartRedo() {
583 // Drop any leading startAction
584 if (actions[currentAction].at == startAction && currentAction < maxAction)
585 currentAction++;
586
587 // Count the steps in this action
588 int act = currentAction;
589 while (actions[act].at != startAction && act < maxAction) {
590 act++;
591 }
592 return act - currentAction;
593 }
594
GetRedoStep() const595 const Action &UndoHistory::GetRedoStep() const {
596 return actions[currentAction];
597 }
598
CompletedRedoStep()599 void UndoHistory::CompletedRedoStep() {
600 currentAction++;
601 }
602
CellBuffer(int initialLength)603 CellBuffer::CellBuffer(int initialLength) {
604 body = new char[initialLength];
605 size = initialLength;
606 length = 0;
607 part1len = 0;
608 gaplen = initialLength;
609 part2body = body + gaplen;
610 readOnly = false;
611 collectingUndo = true;
612 growSize = 4000;
613 }
614
~CellBuffer()615 CellBuffer::~CellBuffer() {
616 delete []body;
617 body = 0;
618 }
619
GapTo(int position)620 void CellBuffer::GapTo(int position) {
621 if (position == part1len)
622 return ;
623 if (position < part1len) {
624 int diff = part1len - position;
625 //Platform::DebugPrintf("Move gap backwards to %d diff = %d part1len=%d length=%d \n", position,diff, part1len, length);
626 for (int i = 0; i < diff; i++)
627 body[part1len + gaplen - i - 1] = body[part1len - i - 1];
628 } else { // position > part1len
629 int diff = position - part1len;
630 //Platform::DebugPrintf("Move gap forwards to %d diff =%d\n", position,diff);
631 for (int i = 0; i < diff; i++)
632 body[part1len + i] = body[part1len + gaplen + i];
633 }
634 part1len = position;
635 part2body = body + gaplen;
636 }
637
RoomFor(int insertionLength)638 void CellBuffer::RoomFor(int insertionLength) {
639 //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength);
640 if (gaplen <= insertionLength) {
641 //Platform::DebugPrintf("need room %d %d\n", gaplen, insertionLength);
642 if (growSize * 6 < size)
643 growSize *= 2;
644 int newSize = size + insertionLength + growSize;
645 Allocate(newSize);
646 }
647 }
648
649 // To make it easier to write code that uses ByteAt, a position outside the range of the buffer
650 // can be retrieved. All characters outside the range have the value '\0'.
ByteAt(int position)651 char CellBuffer::ByteAt(int position) {
652 if (position < part1len) {
653 if (position < 0) {
654 return '\0';
655 } else {
656 return body[position];
657 }
658 } else {
659 if (position >= length) {
660 return '\0';
661 } else {
662 return part2body[position];
663 }
664 }
665 }
666
SetByteAt(int position,char ch)667 void CellBuffer::SetByteAt(int position, char ch) {
668
669 if (position < 0) {
670 //Platform::DebugPrintf("Bad position %d\n",position);
671 return ;
672 }
673 if (position >= length + 11) {
674 Platform::DebugPrintf("Very Bad position %d of %d\n", position, length);
675 //exit(2);
676 return ;
677 }
678 if (position >= length) {
679 //Platform::DebugPrintf("Bad position %d of %d\n",position,length);
680 return ;
681 }
682
683 if (position < part1len) {
684 body[position] = ch;
685 } else {
686 part2body[position] = ch;
687 }
688 }
689
CharAt(int position)690 char CellBuffer::CharAt(int position) {
691 return ByteAt(position*2);
692 }
693
GetCharRange(char * buffer,int position,int lengthRetrieve)694 void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) {
695 if (lengthRetrieve < 0)
696 return ;
697 if (position < 0)
698 return ;
699 int bytePos = position * 2;
700 if ((bytePos + lengthRetrieve * 2) > length) {
701 Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n", bytePos,
702 lengthRetrieve, length);
703 return ;
704 }
705 GapTo(0); // Move the buffer so its easy to subscript into it
706 char *pb = part2body + bytePos;
707 while (lengthRetrieve--) {
708 *buffer++ = *pb;
709 pb += 2;
710 }
711 }
712
StyleAt(int position)713 char CellBuffer::StyleAt(int position) {
714 return ByteAt(position*2 + 1);
715 }
716
InsertString(int position,char * s,int insertLength)717 const char *CellBuffer::InsertString(int position, char *s, int insertLength) {
718 char *data = 0;
719 // InsertString and DeleteChars are the bottleneck though which all changes occur
720 if (!readOnly) {
721 if (collectingUndo) {
722 // Save into the undo/redo stack, but only the characters - not the formatting
723 // This takes up about half load time
724 data = new char[insertLength / 2];
725 for (int i = 0; i < insertLength / 2; i++) {
726 data[i] = s[i * 2];
727 }
728 uh.AppendAction(insertAction, position / 2, data, insertLength / 2);
729 }
730
731 BasicInsertString(position, s, insertLength);
732 }
733 return data;
734 }
735
SetStyleAt(int position,char style,char mask)736 bool CellBuffer::SetStyleAt(int position, char style, char mask) {
737 style &= mask;
738 char curVal = ByteAt(position * 2 + 1);
739 if ((curVal & mask) != style) {
740 SetByteAt(position*2 + 1, static_cast<char>((curVal & ~mask) | style));
741 return true;
742 } else {
743 return false;
744 }
745 }
746
SetStyleFor(int position,int lengthStyle,char style,char mask)747 bool CellBuffer::SetStyleFor(int position, int lengthStyle, char style, char mask) {
748 int bytePos = position * 2 + 1;
749 bool changed = false;
750 PLATFORM_ASSERT(lengthStyle == 0 ||
751 (lengthStyle > 0 && lengthStyle + position < length));
752 while (lengthStyle--) {
753 char curVal = ByteAt(bytePos);
754 if ((curVal & mask) != style) {
755 SetByteAt(bytePos, static_cast<char>((curVal & ~mask) | style));
756 changed = true;
757 }
758 bytePos += 2;
759 }
760 return changed;
761 }
762
DeleteChars(int position,int deleteLength)763 const char *CellBuffer::DeleteChars(int position, int deleteLength) {
764 // InsertString and DeleteChars are the bottleneck though which all changes occur
765 PLATFORM_ASSERT(deleteLength > 0);
766 char *data = 0;
767 if (!readOnly) {
768 if (collectingUndo) {
769 // Save into the undo/redo stack, but only the characters - not the formatting
770 data = new char[deleteLength / 2];
771 for (int i = 0; i < deleteLength / 2; i++) {
772 data[i] = ByteAt(position + i * 2);
773 }
774 uh.AppendAction(removeAction, position / 2, data, deleteLength / 2);
775 }
776
777 BasicDeleteChars(position, deleteLength);
778 }
779 return data;
780 }
781
ByteLength()782 int CellBuffer::ByteLength() {
783 return length;
784 }
785
Length()786 int CellBuffer::Length() {
787 return ByteLength() / 2;
788 }
789
Allocate(int newSize)790 void CellBuffer::Allocate(int newSize) {
791 if (newSize > length) {
792 GapTo(length);
793 char *newBody = new char[newSize];
794 memcpy(newBody, body, length);
795 delete []body;
796 body = newBody;
797 gaplen += newSize - size;
798 part2body = body + gaplen;
799 size = newSize;
800 }
801 }
802
Lines()803 int CellBuffer::Lines() {
804 //Platform::DebugPrintf("Lines = %d\n", lv.lines);
805 return lv.lines;
806 }
807
LineStart(int line)808 int CellBuffer::LineStart(int line) {
809 if (line < 0)
810 return 0;
811 else if (line > lv.lines)
812 return Length();
813 else
814 return lv.linesData[line].startPosition;
815 }
816
IsReadOnly()817 bool CellBuffer::IsReadOnly() {
818 return readOnly;
819 }
820
SetReadOnly(bool set)821 void CellBuffer::SetReadOnly(bool set) {
822 readOnly = set;
823 }
824
SetSavePoint()825 void CellBuffer::SetSavePoint() {
826 uh.SetSavePoint();
827 }
828
IsSavePoint()829 bool CellBuffer::IsSavePoint() {
830 return uh.IsSavePoint();
831 }
832
AddMark(int line,int markerNum)833 int CellBuffer::AddMark(int line, int markerNum) {
834 if ((line >= 0) && (line < lv.lines)) {
835 return lv.AddMark(line, markerNum);
836 }
837 return - 1;
838 }
839
DeleteMark(int line,int markerNum)840 void CellBuffer::DeleteMark(int line, int markerNum) {
841 if ((line >= 0) && (line < lv.lines)) {
842 lv.DeleteMark(line, markerNum, false);
843 }
844 }
845
DeleteMarkFromHandle(int markerHandle)846 void CellBuffer::DeleteMarkFromHandle(int markerHandle) {
847 lv.DeleteMarkFromHandle(markerHandle);
848 }
849
GetMark(int line)850 int CellBuffer::GetMark(int line) {
851 if ((line >= 0) && (line < lv.lines) && (lv.linesData[line].handleSet))
852 return lv.linesData[line].handleSet->MarkValue();
853 return 0;
854 }
855
DeleteAllMarks(int markerNum)856 void CellBuffer::DeleteAllMarks(int markerNum) {
857 for (int line = 0; line < lv.lines; line++) {
858 lv.DeleteMark(line, markerNum, true);
859 }
860 }
861
LineFromHandle(int markerHandle)862 int CellBuffer::LineFromHandle(int markerHandle) {
863 return lv.LineFromHandle(markerHandle);
864 }
865
866 // Without undo
867
BasicInsertString(int position,char * s,int insertLength)868 void CellBuffer::BasicInsertString(int position, char *s, int insertLength) {
869 //Platform::DebugPrintf("Inserting at %d for %d\n", position, insertLength);
870 if (insertLength == 0)
871 return ;
872 PLATFORM_ASSERT(insertLength > 0);
873 RoomFor(insertLength);
874 GapTo(position);
875
876 memcpy(body + part1len, s, insertLength);
877 length += insertLength;
878 part1len += insertLength;
879 gaplen -= insertLength;
880 part2body = body + gaplen;
881
882 int lineInsert = lv.LineFromPosition(position / 2) + 1;
883 // Point all the lines after the insertion point further along in the buffer
884 for (int lineAfter = lineInsert; lineAfter <= lv.lines; lineAfter++) {
885 lv.linesData[lineAfter].startPosition += insertLength / 2;
886 }
887 char chPrev = ' ';
888 if ((position - 2) >= 0)
889 chPrev = ByteAt(position - 2);
890 char chAfter = ' ';
891 if ((position + insertLength) < length)
892 chAfter = ByteAt(position + insertLength);
893 if (chPrev == '\r' && chAfter == '\n') {
894 //Platform::DebugPrintf("Splitting a crlf pair at %d\n", lineInsert);
895 // Splitting up a crlf pair at position
896 lv.InsertValue(lineInsert, position / 2);
897 lineInsert++;
898 }
899 char ch = ' ';
900 for (int i = 0; i < insertLength; i += 2) {
901 ch = s[i];
902 if (ch == '\r') {
903 //Platform::DebugPrintf("Inserting cr at %d\n", lineInsert);
904 lv.InsertValue(lineInsert, (position + i) / 2 + 1);
905 lineInsert++;
906 } else if (ch == '\n') {
907 if (chPrev == '\r') {
908 //Platform::DebugPrintf("Patching cr before lf at %d\n", lineInsert-1);
909 // Patch up what was end of line
910 lv.SetValue(lineInsert - 1, (position + i) / 2 + 1);
911 } else {
912 //Platform::DebugPrintf("Inserting lf at %d\n", lineInsert);
913 lv.InsertValue(lineInsert, (position + i) / 2 + 1);
914 lineInsert++;
915 }
916 }
917 chPrev = ch;
918 }
919 // Joining two lines where last insertion is cr and following text starts with lf
920 if (chAfter == '\n') {
921 if (ch == '\r') {
922 //Platform::DebugPrintf("Joining cr before lf at %d\n", lineInsert-1);
923 // End of line already in buffer so drop the newly created one
924 lv.Remove(lineInsert - 1);
925 }
926 }
927 }
928
BasicDeleteChars(int position,int deleteLength)929 void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
930 //Platform::DebugPrintf("Deleting at %d for %d\n", position, deleteLength);
931 if (deleteLength == 0)
932 return ;
933
934 if ((position == 0) && (deleteLength == length)) {
935 // If whole buffer is being deleted, faster to reinitialise lines data
936 // than to delete each line.
937 //printf("Whole buffer being deleted\n");
938 lv.Init();
939 } else {
940 // Have to fix up line positions before doing deletion as looking at text in buffer
941 // to work out which lines have been removed
942
943 int lineRemove = lv.LineFromPosition(position / 2) + 1;
944 // Point all the lines after the insertion point further along in the buffer
945 for (int lineAfter = lineRemove; lineAfter <= lv.lines; lineAfter++) {
946 lv.linesData[lineAfter].startPosition -= deleteLength / 2;
947 }
948 char chPrev = ' ';
949 if (position >= 2)
950 chPrev = ByteAt(position - 2);
951 char chBefore = chPrev;
952 char chNext = ' ';
953 if (position < length)
954 chNext = ByteAt(position);
955 bool ignoreNL = false;
956 if (chPrev == '\r' && chNext == '\n') {
957 //Platform::DebugPrintf("Deleting lf after cr, move line end to cr at %d\n", lineRemove);
958 // Move back one
959 lv.SetValue(lineRemove, position / 2);
960 lineRemove++;
961 ignoreNL = true; // First \n is not real deletion
962 }
963
964 char ch = chNext;
965 for (int i = 0; i < deleteLength; i += 2) {
966 chNext = ' ';
967 if ((position + i + 2) < length)
968 chNext = ByteAt(position + i + 2);
969 //Platform::DebugPrintf("Deleting %d %x\n", i, ch);
970 if (ch == '\r') {
971 if (chNext != '\n') {
972 //Platform::DebugPrintf("Removing cr end of line\n");
973 lv.Remove(lineRemove);
974 }
975 } else if (ch == '\n') {
976 if (ignoreNL) {
977 ignoreNL = false; // Further \n are real deletions
978 } else {
979 //Platform::DebugPrintf("Removing lf end of line\n");
980 lv.Remove(lineRemove);
981 }
982 }
983
984 ch = chNext;
985 }
986 // May have to fix up end if last deletion causes cr to be next to lf
987 // or removes one of a crlf pair
988 char chAfter = ' ';
989 if ((position + deleteLength) < length)
990 chAfter = ByteAt(position + deleteLength);
991 if (chBefore == '\r' && chAfter == '\n') {
992 //d.printf("Joining cr before lf at %d\n", lineRemove);
993 // Using lineRemove-1 as cr ended line before start of deletion
994 lv.Remove(lineRemove - 1);
995 lv.SetValue(lineRemove - 1, position / 2 + 1);
996 }
997 }
998 GapTo(position);
999 length -= deleteLength;
1000 gaplen += deleteLength;
1001 part2body = body + gaplen;
1002 }
1003
SetUndoCollection(bool collectUndo)1004 bool CellBuffer::SetUndoCollection(bool collectUndo) {
1005 collectingUndo = collectUndo;
1006 uh.DropUndoSequence();
1007 return collectingUndo;
1008 }
1009
IsCollectingUndo()1010 bool CellBuffer::IsCollectingUndo() {
1011 return collectingUndo;
1012 }
1013
BeginUndoAction()1014 void CellBuffer::BeginUndoAction() {
1015 uh.BeginUndoAction();
1016 }
1017
EndUndoAction()1018 void CellBuffer::EndUndoAction() {
1019 uh.EndUndoAction();
1020 }
1021
DeleteUndoHistory()1022 void CellBuffer::DeleteUndoHistory() {
1023 uh.DeleteUndoHistory();
1024 }
1025
CanUndo()1026 bool CellBuffer::CanUndo() {
1027 return uh.CanUndo();
1028 }
1029
StartUndo()1030 int CellBuffer::StartUndo() {
1031 return uh.StartUndo();
1032 }
1033
GetUndoStep() const1034 const Action &CellBuffer::GetUndoStep() const {
1035 return uh.GetUndoStep();
1036 }
1037
PerformUndoStep()1038 void CellBuffer::PerformUndoStep() {
1039 const Action &actionStep = uh.GetUndoStep();
1040 if (actionStep.at == insertAction) {
1041 BasicDeleteChars(actionStep.position*2, actionStep.lenData*2);
1042 } else if (actionStep.at == removeAction) {
1043 char *styledData = new char[actionStep.lenData * 2];
1044 for (int i = 0; i < actionStep.lenData; i++) {
1045 styledData[i*2] = actionStep.data[i];
1046 styledData[i*2 + 1] = 0;
1047 }
1048 BasicInsertString(actionStep.position*2, styledData, actionStep.lenData*2);
1049 delete []styledData;
1050 }
1051 uh.CompletedUndoStep();
1052 }
1053
CanRedo()1054 bool CellBuffer::CanRedo() {
1055 return uh.CanRedo();
1056 }
1057
StartRedo()1058 int CellBuffer::StartRedo() {
1059 return uh.StartRedo();
1060 }
1061
GetRedoStep() const1062 const Action &CellBuffer::GetRedoStep() const {
1063 return uh.GetRedoStep();
1064 }
1065
PerformRedoStep()1066 void CellBuffer::PerformRedoStep() {
1067 const Action &actionStep = uh.GetRedoStep();
1068 if (actionStep.at == insertAction) {
1069 char *styledData = new char[actionStep.lenData * 2];
1070 for (int i = 0; i < actionStep.lenData; i++) {
1071 styledData[i*2] = actionStep.data[i];
1072 styledData[i*2 + 1] = 0;
1073 }
1074 BasicInsertString(actionStep.position*2, styledData, actionStep.lenData*2);
1075 delete []styledData;
1076 } else if (actionStep.at == removeAction) {
1077 BasicDeleteChars(actionStep.position*2, actionStep.lenData*2);
1078 }
1079 uh.CompletedRedoStep();
1080 }
1081
SetLineState(int line,int state)1082 int CellBuffer::SetLineState(int line, int state) {
1083 int stateOld = lineStates[line];
1084 lineStates[line] = state;
1085 return stateOld;
1086 }
1087
GetLineState(int line)1088 int CellBuffer::GetLineState(int line) {
1089 return lineStates[line];
1090 }
1091
GetMaxLineState()1092 int CellBuffer::GetMaxLineState() {
1093 return lineStates.Length();
1094 }
1095
SetLevel(int line,int level)1096 int CellBuffer::SetLevel(int line, int level) {
1097 int prev = 0;
1098 if ((line >= 0) && (line < lv.lines)) {
1099 if (!lv.levels) {
1100 lv.ExpandLevels();
1101 }
1102 prev = lv.levels[line];
1103 if (lv.levels[line] != level) {
1104 lv.levels[line] = level;
1105 }
1106 }
1107 return prev;
1108 }
1109
GetLevel(int line)1110 int CellBuffer::GetLevel(int line) {
1111 if (lv.levels && (line >= 0) && (line < lv.lines)) {
1112 return lv.levels[line];
1113 } else {
1114 return SC_FOLDLEVELBASE;
1115 }
1116 }
1117
ClearLevels()1118 void CellBuffer::ClearLevels() {
1119 lv.ClearLevels();
1120 }
1121