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