13
13
#include "Platform.h"
15
15
#include "Scintilla.h"
16
#include "SplitVector.h"
17
#include "Partitioning.h"
18
#include "RunStyles.h"
17
19
#include "CellBuffer.h"
18
20
#include "CharClassify.h"
21
#include "Decoration.h"
19
22
#include "Document.h"
20
23
#include "RESearch.h"
26
using namespace Scintilla;
22
29
// This is ASCII specific but is safe with chars >= 0x80
23
30
static inline bool isspacechar(unsigned char ch) {
24
31
return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
104
112
int Document::AddMark(int line, int markerNum) {
105
113
int prev = cb.AddMark(line, markerNum);
106
114
DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line);
108
115
NotifyModified(mh);
116
123
cb.AddMark(line, i);
117
124
DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line);
119
125
NotifyModified(mh);
122
128
void Document::DeleteMark(int line, int markerNum) {
123
129
cb.DeleteMark(line, markerNum);
124
130
DocModification mh(SC_MOD_CHANGEMARKER, LineStart(line), 0, 0, 0, line);
126
131
NotifyModified(mh);
140
145
NotifyModified(mh);
143
int Document::LineStart(int line) {
148
int Document::LineStart(int line) const {
144
149
return cb.LineStart(line);
147
int Document::LineEnd(int line) {
152
int Document::LineEnd(int line) const {
148
153
if (line == LinesTotal() - 1) {
149
154
return LineStart(line + 1);
182
187
int prev = cb.SetLevel(line, level);
183
188
if (prev != level) {
184
189
DocModification mh(SC_MOD_CHANGEFOLD | SC_MOD_CHANGEMARKER,
185
LineStart(line), 0, 0, 0);
190
LineStart(line), 0, 0, 0, line);
187
191
mh.foldLevelNow = level;
188
192
mh.foldLevelPrev = prev;
189
193
NotifyModified(mh);
264
if (ch >= (0x80 + 0x40 + 0x20))
268
if (ch >= (0x80 + 0x40 + 0x20 + 0x10))
270
else if (ch >= (0x80 + 0x40 + 0x20))
266
272
int lengthDoc = Length();
267
273
if ((pos + len) > lengthDoc)
290
static bool IsTrailByte(int ch) {
291
return (ch >= 0x80) && (ch < (0x80 + 0x40));
294
static int BytesFromLead(int leadByte) {
295
if (leadByte > 0xF4) {
296
// Characters longer than 4 bytes not possible in current UTF-8
298
} else if (leadByte >= 0xF0) {
300
} else if (leadByte >= 0xE0) {
302
} else if (leadByte >= 0xC2) {
308
bool Document::InGoodUTF8(int pos, int &start, int &end) {
310
while ((lead>0) && (pos-lead < 4) && IsTrailByte(static_cast<unsigned char>(cb.CharAt(lead-1))))
316
int leadByte = static_cast<unsigned char>(cb.CharAt(start));
317
int bytes = BytesFromLead(leadByte);
321
int trailBytes = bytes - 1;
322
int len = pos - lead + 1;
323
if (len > trailBytes)
324
// pos too far from lead
326
// Check that there are enough trails for this lead
328
while ((trail-lead<trailBytes) && (trail < Length())) {
329
if (!IsTrailByte(static_cast<unsigned char>(cb.CharAt(trail)))) {
284
339
// Normalise a position so that it is not halfway through a two byte character.
285
340
// This can occur in two situations -
286
341
// When lines are terminated with \r\n pairs which should be treated as one character.
307
362
if (dbcsCodePage) {
308
363
if (SC_CP_UTF8 == dbcsCodePage) {
309
364
unsigned char ch = static_cast<unsigned char>(cb.CharAt(pos));
310
while ((pos > 0) && (pos < Length()) && (ch >= 0x80) && (ch < (0x80 + 0x40))) {
311
// ch is a trail byte
367
if (IsTrailByte(ch) && InGoodUTF8(pos, startUTF, endUTF)) {
368
// ch is a trail byte within a UTF-8 character
316
ch = static_cast<unsigned char>(cb.CharAt(pos));
319
375
// Anchor DBCS calculations at start of line because start of line can
361
// Document only modified by gateways DeleteChars, InsertStyledString, Undo, Redo, and SetStyleAt.
417
// Document only modified by gateways DeleteChars, InsertString, Undo, Redo, and SetStyleAt.
362
418
// SetStyleAt does not change the persistent state of a document
364
// Unlike Undo, Redo, and InsertStyledString, the pos argument is a cell number not a char number
365
420
bool Document::DeleteChars(int pos, int len) {
368
423
if ((pos + len) > Length())
371
if (enteredCount != 0) {
426
if (enteredModification != 0) {
429
enteredModification++;
375
430
if (!cb.IsReadOnly()) {
381
436
int prevLinesTotal = LinesTotal();
382
437
bool startSavePoint = cb.IsSavePoint();
383
const char *text = cb.DeleteChars(pos * 2, len * 2);
438
bool startSequence = false;
439
const char *text = cb.DeleteChars(pos, len, startSequence);
384
440
if (startSavePoint && cb.IsCollectingUndo())
385
441
NotifySavePoint(!startSavePoint);
386
442
if ((pos < Length()) || (pos == 0))
389
445
ModifiedAt(pos-1);
392
SC_MOD_DELETETEXT | SC_PERFORMED_USER,
448
SC_MOD_DELETETEXT | SC_PERFORMED_USER | (startSequence?SC_STARTACTION:0),
394
450
LinesTotal() - prevLinesTotal, text));
452
enteredModification--;
398
454
return !cb.IsReadOnly();
402
* Insert a styled string (char/style pairs) with a length.
458
* Insert a string with a length.
404
bool Document::InsertStyledString(int position, char *s, int insertLength) {
460
bool Document::InsertString(int position, const char *s, int insertLength) {
461
if (insertLength <= 0) {
406
if (enteredCount != 0) {
465
if (enteredModification != 0) {
468
enteredModification++;
410
469
if (!cb.IsReadOnly()) {
413
472
SC_MOD_BEFOREINSERT | SC_PERFORMED_USER,
414
position / 2, insertLength / 2,
473
position, insertLength,
416
475
int prevLinesTotal = LinesTotal();
417
476
bool startSavePoint = cb.IsSavePoint();
418
const char *text = cb.InsertString(position, s, insertLength);
477
bool startSequence = false;
478
const char *text = cb.InsertString(position, s, insertLength, startSequence);
419
479
if (startSavePoint && cb.IsCollectingUndo())
420
480
NotifySavePoint(!startSavePoint);
421
ModifiedAt(position / 2);
481
ModifiedAt(position);
424
SC_MOD_INSERTTEXT | SC_PERFORMED_USER,
425
position / 2, insertLength / 2,
484
SC_MOD_INSERTTEXT | SC_PERFORMED_USER | (startSequence?SC_STARTACTION:0),
485
position, insertLength,
426
486
LinesTotal() - prevLinesTotal, text));
488
enteredModification--;
430
490
return !cb.IsReadOnly();
544
604
* Insert a single character.
546
606
bool Document::InsertChar(int pos, char ch) {
550
return InsertStyledString(pos*2, chs, 2);
609
return InsertString(pos, chs, 1);
554
613
* Insert a null terminated string.
556
bool Document::InsertString(int position, const char *s) {
615
bool Document::InsertCString(int position, const char *s) {
557
616
return InsertString(position, s, strlen(s));
561
* Insert a string with a length.
563
bool Document::InsertString(int position, const char *s, size_t insertLength) {
564
bool changed = false;
565
if (insertLength > 0) {
566
char *sWithStyle = new char[insertLength * 2];
568
for (size_t i = 0; i < insertLength; i++) {
569
sWithStyle[i*2] = s[i];
570
sWithStyle[i*2 + 1] = 0;
572
changed = InsertStyledString(position*2, sWithStyle,
573
static_cast<int>(insertLength*2));
580
619
void Document::ChangeChar(int pos, char ch) {
581
620
DeleteChars(pos, 1);
582
621
InsertChar(pos, ch);
653
692
int indentPos = GetLineIndentPosition(line);
654
693
BeginUndoAction();
655
694
DeleteChars(thisLineStart, indentPos - thisLineStart);
656
InsertString(thisLineStart, linebuf);
695
InsertCString(thisLineStart, linebuf);
661
int Document::GetLineIndentPosition(int line) {
700
int Document::GetLineIndentPosition(int line) const {
664
703
int pos = LineStart(line);
683
722
} else if (ch == '\n') {
724
} else if (i >= Length()) {
687
i = MovePositionOutsideChar(i + 1, 1);
728
i = MovePositionOutsideChar(i + 1, 1, false);
800
bool Document::IsWhiteLine(int line) {
841
bool Document::IsWhiteLine(int line) const {
801
842
int currentChar = LineStart(line);
802
843
int endLine = LineEnd(line);
803
844
while (currentChar < endLine) {
854
895
while (pos > 0 && (WordCharClass(cb.CharAt(pos - 1)) == ccStart))
857
if (!onlyWordCharacters)
898
if (!onlyWordCharacters && pos < Length())
858
899
ccStart = WordCharClass(cb.CharAt(pos));
859
900
while (pos < (Length()) && (WordCharClass(cb.CharAt(pos)) == ccStart))
1276
1317
void Document::SetStylingBits(int bits) {
1277
1318
stylingBits = bits;
1278
stylingBitsMask = 0;
1279
for (int bit = 0; bit < stylingBits; bit++) {
1280
stylingBitsMask <<= 1;
1281
stylingBitsMask |= 1;
1319
stylingBitsMask = (1 << stylingBits) - 1;
1285
1322
void Document::StartStyling(int position, char mask) {
1290
1327
bool Document::SetStyleFor(int length, char style) {
1291
if (enteredCount != 0) {
1328
if (enteredStyling != 0) {
1295
1332
style &= stylingMask;
1296
1333
int prevEndStyled = endStyled;
1297
1334
if (cb.SetStyleFor(endStyled, length, style, stylingMask)) {
1328
1365
startMod, endMod - startMod + 1);
1329
1366
NotifyModified(mh);
1336
bool Document::EnsureStyledTo(int pos) {
1337
if (pos > GetEndStyled()) {
1373
void Document::EnsureStyledTo(int pos) {
1374
if ((enteredStyling == 0) && (pos > GetEndStyled())) {
1338
1375
IncrementStyleClock();
1339
1376
// Ask the watchers to style, and stop as soon as one responds.
1340
1377
for (int i = 0; pos > GetEndStyled() && i < lenWatchers; i++) {
1341
1378
watchers[i].watcher->NotifyStyleNeeded(this, watchers[i].userData, pos);
1344
return pos <= GetEndStyled();
1383
int Document::SetLineState(int line, int state) {
1384
int statePrevious = cb.SetLineState(line, state);
1385
if (state != statePrevious) {
1386
DocModification mh(SC_MOD_CHANGELINESTATE, 0, 0, 0, 0, line);
1389
return statePrevious;
1347
1392
void Document::IncrementStyleClock() {
1349
if (styleClock > 0x100000) {
1393
styleClock = (styleClock + 1) % 0x100000;
1396
void Document::DecorationFillRange(int position, int value, int fillLength) {
1397
if (decorations.FillRange(position, value, fillLength)) {
1398
DocModification mh(SC_MOD_CHANGEINDICATOR | SC_PERFORMED_USER,
1399
position, fillLength);
1410
1460
void Document::NotifyModified(DocModification mh) {
1461
if (mh.modificationType & SC_MOD_INSERTTEXT) {
1462
decorations.InsertSpace(mh.position, mh.length);
1463
} else if (mh.modificationType & SC_MOD_DELETETEXT) {
1464
decorations.DeleteRange(mh.position, mh.length);
1411
1466
for (int i = 0; i < lenWatchers; i++) {
1412
1467
watchers[i].watcher->NotifyModified(this, mh, watchers[i].userData);