124
LineVector::LineVector() {
129
LineVector::LineVector() : starts(256) {
130
130
handleCurrent = 1;
136
135
LineVector::~LineVector() {
137
for (int line = 0; line < lines; line++) {
138
delete linesData[line].handleSet;
139
linesData[line].handleSet = 0;
137
for (int line = 0; line < markers.Length(); line++) {
138
delete markers[line];
147
145
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");
147
for (int line = 0; line < markers.Length(); line++) {
148
delete markers[line];
177
155
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");
156
levels.InsertValue(levels.Length(), sizeNew - levels.Length(), SC_FOLDLEVELBASE);
197
159
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);
163
int LineVector::SetLevel(int line, int level) {
165
if ((line >= 0) && (line < Lines())) {
166
if (!levels.Length()) {
167
ExpandLevels(Lines() + 1);
171
levels[line] = level;
177
int LineVector::GetLevel(int line) {
178
if (levels.Length() && (line >= 0) && (line < Lines())) {
181
return SC_FOLDLEVELBASE;
185
void LineVector::InsertText(int line, int delta) {
186
starts.InsertText(line, delta);
189
void LineVector::InsertLine(int line, int position) {
190
starts.InsertPartition(line, position);
191
if (markers.Length()) {
192
markers.Insert(line, 0);
194
if (levels.Length()) {
195
int level = SC_FOLDLEVELBASE;
196
if ((line > 0) && (line < Lines())) {
197
level = levels[line-1] & ~SC_FOLDLEVELWHITEFLAG;
199
levels.InsertValue(line, 1, level);
203
void LineVector::SetLineStart(int line, int position) {
204
starts.SetPartitionStartPosition(line, position);
207
void LineVector::RemoveLine(int line) {
208
starts.RemovePartition(line);
249
209
// 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];
210
if (markers.Length()) {
212
MergeMarkers(line - 1);
214
markers.Delete(line);
216
if (levels.Length()) {
257
217
// Move up following lines but merge header flag from this line
258
218
// 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];
264
levels[pos-1] |= firstHeader;
219
int firstHeader = levels[line] & SC_FOLDLEVELHEADERFLAG;
222
levels[line-1] |= firstHeader;
269
226
int LineVector::LineFromPosition(int pos) {
270
//Platform::DebugPrintf("LineFromPostion %d lines=%d end = %d\n", pos, lines, linesData[lines].startPosition);
227
return starts.PartitionFromPosition(pos);
230
int LineVector::MarkValue(int line) {
231
if (markers.Length() && markers[line])
232
return markers[line]->MarkValue();
273
//Platform::DebugPrintf("LineFromPosition %d\n", pos);
274
if (pos >= linesData[lines].startPosition)
279
int middle = (upper + lower + 1) / 2; // Round high
280
if (pos < linesData[middle].startPosition) {
285
} while (lower < upper);
286
//Platform::DebugPrintf("LineFromPostion %d %d %d\n", pos, lower, linesData[lower].startPosition, linesData[lower > 1 ? lower - 1 : 0].startPosition);
290
237
int LineVector::AddMark(int line, int markerNum) {
292
if (!linesData[line].handleSet) {
239
if (!markers.Length()) {
240
// No existing markers so allocate one element per line
241
markers.InsertValue(0, Lines(), 0);
243
if (!markers[line]) {
293
244
// Need new structure to hold marker handle
294
linesData[line].handleSet = new MarkerHandleSet;
295
if (!linesData[line].handleSet)
245
markers[line] = new MarkerHandleSet();
298
linesData[line].handleSet->InsertHandle(handleCurrent, markerNum);
249
markers[line]->InsertHandle(handleCurrent, markerNum);
300
251
return handleCurrent;
303
254
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;
255
if (markers[pos + 1] != NULL) {
256
if (markers[pos] == NULL)
257
markers[pos] = new MarkerHandleSet;
258
markers[pos]->CombineWith(markers[pos + 1]);
259
delete markers[pos + 1];
260
markers[pos + 1] = NULL;
313
264
void LineVector::DeleteMark(int line, int markerNum, bool all) {
314
if (linesData[line].handleSet) {
265
if (markers.Length() && markers[line]) {
315
266
if (markerNum == -1) {
316
delete linesData[line].handleSet;
317
linesData[line].handleSet = 0;
267
delete markers[line];
268
markers[line] = NULL;
319
bool performedDeletion =
320
linesData[line].handleSet->RemoveNumber(markerNum);
270
bool performedDeletion = markers[line]->RemoveNumber(markerNum);
321
271
while (all && performedDeletion) {
323
linesData[line].handleSet->RemoveNumber(markerNum);
272
performedDeletion = markers[line]->RemoveNumber(markerNum);
325
if (linesData[line].handleSet->Length() == 0) {
326
delete linesData[line].handleSet;
327
linesData[line].handleSet = 0;
274
if (markers[line]->Length() == 0) {
275
delete markers[line];
276
markers[line] = NULL;
603
CellBuffer::CellBuffer(int initialLength) {
604
body = new char[initialLength];
605
size = initialLength;
608
gaplen = initialLength;
609
part2body = body + gaplen;
558
CellBuffer::CellBuffer() {
610
559
readOnly = false;
611
560
collectingUndo = true;
615
563
CellBuffer::~CellBuffer() {
620
void CellBuffer::GapTo(int position) {
621
if (position == part1len)
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];
635
part2body = body + gaplen;
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)
644
int newSize = size + insertionLength + growSize;
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'.
651
char CellBuffer::ByteAt(int position) {
652
if (position < part1len) {
656
return body[position];
659
if (position >= length) {
662
return part2body[position];
667
void CellBuffer::SetByteAt(int position, char ch) {
670
//Platform::DebugPrintf("Bad position %d\n",position);
673
if (position >= length + 11) {
674
Platform::DebugPrintf("Very Bad position %d of %d\n", position, length);
678
if (position >= length) {
679
//Platform::DebugPrintf("Bad position %d of %d\n",position,length);
683
if (position < part1len) {
686
part2body[position] = ch;
690
char CellBuffer::CharAt(int position) {
691
return ByteAt(position*2);
566
char CellBuffer::CharAt(int position) const {
567
return substance.ValueAt(position);
694
570
void CellBuffer::GetCharRange(char *buffer, int position, int lengthRetrieve) {
695
571
if (lengthRetrieve < 0)
697
573
if (position < 0)
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);
575
if ((position + lengthRetrieve) > substance.Length()) {
576
Platform::DebugPrintf("Bad GetCharRange %d for %d of %d\n", position,
577
lengthRetrieve, substance.Length());
705
GapTo(0); // Move the buffer so its easy to subscript into it
706
char *pb = part2body + bytePos;
707
while (lengthRetrieve--) {
581
for (int i=0; i<lengthRetrieve; i++) {
582
*buffer++ = substance.ValueAt(position + i);
713
586
char CellBuffer::StyleAt(int position) {
714
return ByteAt(position*2 + 1);
587
return style.ValueAt(position);
717
const char *CellBuffer::InsertString(int position, char *s, int insertLength) {
590
// The char* returned is to an allocation owned by the undo history
591
const char *CellBuffer::InsertString(int position, const char *s, int insertLength, bool &startSequence) {
719
593
// InsertString and DeleteChars are the bottleneck though which all changes occur
721
595
if (collectingUndo) {
722
596
// Save into the undo/redo stack, but only the characters - not the formatting
723
597
// This takes up about half load time
724
data = new char[insertLength / 2];
725
for (int i = 0; i < insertLength / 2; i++) {
598
data = new char[insertLength];
599
for (int i = 0; i < insertLength; i++) {
728
uh.AppendAction(insertAction, position / 2, data, insertLength / 2);
602
uh.AppendAction(insertAction, position, data, insertLength, startSequence);
731
605
BasicInsertString(position, s, insertLength);
736
bool CellBuffer::SetStyleAt(int position, char style, char mask) {
738
char curVal = ByteAt(position * 2 + 1);
739
if ((curVal & mask) != style) {
740
SetByteAt(position*2 + 1, static_cast<char>((curVal & ~mask) | style));
610
bool CellBuffer::SetStyleAt(int position, char styleValue, char mask) {
612
char curVal = style.ValueAt(position);
613
if ((curVal & mask) != styleValue) {
614
style.SetValueAt(position, static_cast<char>((curVal & ~mask) | styleValue));
747
bool CellBuffer::SetStyleFor(int position, int lengthStyle, char style, char mask) {
748
int bytePos = position * 2 + 1;
621
bool CellBuffer::SetStyleFor(int position, int lengthStyle, char styleValue, char mask) {
749
622
bool changed = false;
750
623
PLATFORM_ASSERT(lengthStyle == 0 ||
751
(lengthStyle > 0 && lengthStyle + position < length));
624
(lengthStyle > 0 && lengthStyle + position <= style.Length()));
752
625
while (lengthStyle--) {
753
char curVal = ByteAt(bytePos);
754
if ((curVal & mask) != style) {
755
SetByteAt(bytePos, static_cast<char>((curVal & ~mask) | style));
626
char curVal = style.ValueAt(position);
627
if ((curVal & mask) != styleValue) {
628
style.SetValueAt(position, static_cast<char>((curVal & ~mask) | styleValue));
763
const char *CellBuffer::DeleteChars(int position, int deleteLength) {
636
// The char* returned is to an allocation owned by the undo history
637
const char *CellBuffer::DeleteChars(int position, int deleteLength, bool &startSequence) {
764
638
// InsertString and DeleteChars are the bottleneck though which all changes occur
765
639
PLATFORM_ASSERT(deleteLength > 0);
768
642
if (collectingUndo) {
769
643
// 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);
644
data = new char[deleteLength];
645
for (int i = 0; i < deleteLength; i++) {
646
data[i] = substance.ValueAt(position + i);
774
uh.AppendAction(removeAction, position / 2, data, deleteLength / 2);
648
uh.AppendAction(removeAction, position, data, deleteLength, startSequence);
777
651
BasicDeleteChars(position, deleteLength);
868
void CellBuffer::BasicInsertString(int position, char *s, int insertLength) {
869
//Platform::DebugPrintf("Inserting at %d for %d\n", position, insertLength);
729
void CellBuffer::InsertLine(int line, int position) {
730
lv.InsertLine(line, position);
731
if (lineStates.Length()) {
732
lineStates.EnsureLength(line);
733
lineStates.Insert(line, 0);
737
void CellBuffer::RemoveLine(int line) {
739
if (lineStates.Length() > line) {
740
lineStates.Delete(line);
744
void CellBuffer::BasicInsertString(int position, const char *s, int insertLength) {
870
745
if (insertLength == 0)
872
747
PLATFORM_ASSERT(insertLength > 0);
873
RoomFor(insertLength);
876
memcpy(body + part1len, s, insertLength);
877
length += insertLength;
878
part1len += insertLength;
879
gaplen -= insertLength;
880
part2body = body + gaplen;
882
int lineInsert = lv.LineFromPosition(position / 2) + 1;
749
substance.InsertFromArray(position, s, 0, insertLength);
750
style.InsertValue(position, insertLength, 0);
752
int lineInsert = lv.LineFromPosition(position) + 1;
883
753
// 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;
888
if ((position - 2) >= 0)
889
chPrev = ByteAt(position - 2);
891
if ((position + insertLength) < length)
892
chAfter = ByteAt(position + insertLength);
754
lv.InsertText(lineInsert-1, insertLength);
755
char chPrev = substance.ValueAt(position - 1);
756
char chAfter = substance.ValueAt(position + insertLength);
893
757
if (chPrev == '\r' && chAfter == '\n') {
894
//Platform::DebugPrintf("Splitting a crlf pair at %d\n", lineInsert);
895
758
// Splitting up a crlf pair at position
896
lv.InsertValue(lineInsert, position / 2);
759
InsertLine(lineInsert, position);
900
for (int i = 0; i < insertLength; i += 2) {
763
for (int i = 0; i < insertLength; i++) {
902
765
if (ch == '\r') {
903
//Platform::DebugPrintf("Inserting cr at %d\n", lineInsert);
904
lv.InsertValue(lineInsert, (position + i) / 2 + 1);
766
InsertLine(lineInsert, (position + i) + 1);
906
768
} else if (ch == '\n') {
907
769
if (chPrev == '\r') {
908
//Platform::DebugPrintf("Patching cr before lf at %d\n", lineInsert-1);
909
770
// Patch up what was end of line
910
lv.SetValue(lineInsert - 1, (position + i) / 2 + 1);
771
lv.SetLineStart(lineInsert - 1, (position + i) + 1);
912
//Platform::DebugPrintf("Inserting lf at %d\n", lineInsert);
913
lv.InsertValue(lineInsert, (position + i) / 2 + 1);
773
InsertLine(lineInsert, (position + i) + 1);
919
// Joining two lines where last insertion is cr and following text starts with lf
779
// Joining two lines where last insertion is cr and following substance starts with lf
920
780
if (chAfter == '\n') {
921
781
if (ch == '\r') {
922
//Platform::DebugPrintf("Joining cr before lf at %d\n", lineInsert-1);
923
782
// End of line already in buffer so drop the newly created one
924
lv.Remove(lineInsert - 1);
783
RemoveLine(lineInsert - 1);
929
788
void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
930
//Platform::DebugPrintf("Deleting at %d for %d\n", position, deleteLength);
931
789
if (deleteLength == 0)
934
if ((position == 0) && (deleteLength == length)) {
792
if ((position == 0) && (deleteLength == substance.Length())) {
935
793
// If whole buffer is being deleted, faster to reinitialise lines data
936
794
// than to delete each line.
937
//printf("Whole buffer being deleted\n");
940
797
// Have to fix up line positions before doing deletion as looking at text in buffer
941
798
// to work out which lines have been removed
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;
950
chPrev = ByteAt(position - 2);
800
int lineRemove = lv.LineFromPosition(position) + 1;
801
lv.InsertText(lineRemove-1, - (deleteLength));
802
char chPrev = substance.ValueAt(position - 1);
951
803
char chBefore = chPrev;
953
if (position < length)
954
chNext = ByteAt(position);
804
char chNext = substance.ValueAt(position);
955
805
bool ignoreNL = false;
956
806
if (chPrev == '\r' && chNext == '\n') {
957
//Platform::DebugPrintf("Deleting lf after cr, move line end to cr at %d\n", lineRemove);
959
lv.SetValue(lineRemove, position / 2);
808
lv.SetLineStart(lineRemove, position);
961
810
ignoreNL = true; // First \n is not real deletion
964
813
char ch = chNext;
965
for (int i = 0; i < deleteLength; i += 2) {
967
if ((position + i + 2) < length)
968
chNext = ByteAt(position + i + 2);
969
//Platform::DebugPrintf("Deleting %d %x\n", i, ch);
814
for (int i = 0; i < deleteLength; i++) {
815
chNext = substance.ValueAt(position + i + 1);
970
816
if (ch == '\r') {
971
817
if (chNext != '\n') {
972
//Platform::DebugPrintf("Removing cr end of line\n");
973
lv.Remove(lineRemove);
818
RemoveLine(lineRemove);
975
820
} else if (ch == '\n') {
977
822
ignoreNL = false; // Further \n are real deletions
979
//Platform::DebugPrintf("Removing lf end of line\n");
980
lv.Remove(lineRemove);
824
RemoveLine(lineRemove);