aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CellBuffer.cxx115
-rw-r--r--src/CellBuffer.h5
-rw-r--r--src/Document.cxx34
-rw-r--r--src/Document.h4
-rw-r--r--src/Editor.cxx18
-rw-r--r--src/UniConversion.h13
6 files changed, 181 insertions, 8 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx
index 11b8b4acd..7bb96ca76 100644
--- a/src/CellBuffer.cxx
+++ b/src/CellBuffer.cxx
@@ -16,6 +16,7 @@
#include "SplitVector.h"
#include "Partitioning.h"
#include "CellBuffer.h"
+#include "UniConversion.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
@@ -331,6 +332,7 @@ void UndoHistory::CompletedRedoStep() {
CellBuffer::CellBuffer() {
readOnly = false;
+ utf8LineEnds = 0;
collectingUndo = true;
}
@@ -458,6 +460,13 @@ void CellBuffer::Allocate(int newSize) {
style.ReAllocate(newSize);
}
+void CellBuffer::SetLineEndTypes(int utf8LineEnds_) {
+ if (utf8LineEnds != utf8LineEnds_) {
+ utf8LineEnds = utf8LineEnds_;
+ ResetLineEnds();
+ }
+}
+
void CellBuffer::SetPerLine(PerLine *pl) {
lv.SetPerLine(pl);
}
@@ -501,11 +510,64 @@ void CellBuffer::RemoveLine(int line) {
lv.RemoveLine(line);
}
+bool CellBuffer::UTF8LineEndOverlaps(int position) const {
+ unsigned char bytes[] = {
+ static_cast<unsigned char>(substance.ValueAt(position-2)),
+ static_cast<unsigned char>(substance.ValueAt(position-1)),
+ static_cast<unsigned char>(substance.ValueAt(position)),
+ static_cast<unsigned char>(substance.ValueAt(position+1)),
+ };
+ return UTF8IsSeparator(bytes) || UTF8IsSeparator(bytes+1) || UTF8IsNEL(bytes+1);
+}
+
+void CellBuffer::ResetLineEnds() {
+ // Reinitialize line data -- too much work to preserve
+ lv.Init();
+
+ int position = 0;
+ int length = Length();
+ int lineInsert = 1;
+ bool atLineStart = true;
+ lv.InsertText(lineInsert-1, length);
+ unsigned char chBeforePrev = 0;
+ unsigned char chPrev = 0;
+ unsigned char ch = ' ';
+ for (int i = 0; i < length; i++) {
+ ch = substance.ValueAt(position + i);
+ if (ch == '\r') {
+ InsertLine(lineInsert, (position + i) + 1, atLineStart);
+ lineInsert++;
+ } else if (ch == '\n') {
+ if (chPrev == '\r') {
+ // Patch up what was end of line
+ lv.SetLineStart(lineInsert - 1, (position + i) + 1);
+ } else {
+ InsertLine(lineInsert, (position + i) + 1, atLineStart);
+ lineInsert++;
+ }
+ } else if (utf8LineEnds) {
+ unsigned char back3[3] = {chBeforePrev, chPrev, ch};
+ if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) {
+ InsertLine(lineInsert, (position + i) + 1, atLineStart);
+ lineInsert++;
+ }
+ }
+ chBeforePrev = chPrev;
+ chPrev = ch;
+ }
+}
+
void CellBuffer::BasicInsertString(int position, const char *s, int insertLength) {
if (insertLength == 0)
return;
PLATFORM_ASSERT(insertLength > 0);
+ unsigned char chAfter = substance.ValueAt(position);
+ bool breakingUTF8LineEnd = false;
+ if (utf8LineEnds && UTF8IsTrailByte(chAfter)) {
+ breakingUTF8LineEnd = UTF8LineEndOverlaps(position);
+ }
+
substance.InsertFromArray(position, s, 0, insertLength);
style.InsertValue(position, insertLength, 0);
@@ -513,14 +575,17 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength
bool atLineStart = lv.LineStart(lineInsert-1) == position;
// Point all the lines after the insertion point further along in the buffer
lv.InsertText(lineInsert-1, insertLength);
- char chPrev = substance.ValueAt(position - 1);
- char chAfter = substance.ValueAt(position + insertLength);
+ unsigned char chBeforePrev = substance.ValueAt(position - 2);
+ unsigned char chPrev = substance.ValueAt(position - 1);
if (chPrev == '\r' && chAfter == '\n') {
// Splitting up a crlf pair at position
InsertLine(lineInsert, position, false);
lineInsert++;
}
- char ch = ' ';
+ if (breakingUTF8LineEnd) {
+ RemoveLine(lineInsert);
+ }
+ unsigned char ch = ' ';
for (int i = 0; i < insertLength; i++) {
ch = s[i];
if (ch == '\r') {
@@ -534,7 +599,14 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength
InsertLine(lineInsert, (position + i) + 1, atLineStart);
lineInsert++;
}
+ } else if (utf8LineEnds) {
+ unsigned char back3[3] = {chBeforePrev, chPrev, ch};
+ if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) {
+ InsertLine(lineInsert, (position + i) + 1, atLineStart);
+ lineInsert++;
+ }
}
+ chBeforePrev = chPrev;
chPrev = ch;
}
// Joining two lines where last insertion is cr and following substance starts with lf
@@ -543,6 +615,22 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength
// End of line already in buffer so drop the newly created one
RemoveLine(lineInsert - 1);
}
+ } else if (utf8LineEnds && !UTF8IsAscii(chAfter)) {
+ // May have end of UTF-8 line end in buffer and start in insertion
+ for (int j = 0; j < UTF8SeparatorLength-1; j++) {
+ unsigned char chAt = substance.ValueAt(position + insertLength + j);
+ unsigned char back3[3] = {chBeforePrev, chPrev, chAt};
+ if (UTF8IsSeparator(back3)) {
+ InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart);
+ lineInsert++;
+ }
+ if ((j == 0) && UTF8IsNEL(back3+1)) {
+ InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart);
+ lineInsert++;
+ }
+ chBeforePrev = chPrev;
+ chPrev = chAt;
+ }
}
}
@@ -560,9 +648,9 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
int lineRemove = lv.LineFromPosition(position) + 1;
lv.InsertText(lineRemove-1, - (deleteLength));
- char chPrev = substance.ValueAt(position - 1);
- char chBefore = chPrev;
- char chNext = substance.ValueAt(position);
+ unsigned char chPrev = substance.ValueAt(position - 1);
+ unsigned char chBefore = chPrev;
+ unsigned char chNext = substance.ValueAt(position);
bool ignoreNL = false;
if (chPrev == '\r' && chNext == '\n') {
// Move back one
@@ -570,8 +658,13 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
lineRemove++;
ignoreNL = true; // First \n is not real deletion
}
+ if (utf8LineEnds && UTF8IsTrailByte(chNext)) {
+ if (UTF8LineEndOverlaps(position)) {
+ RemoveLine(lineRemove);
+ }
+ }
- char ch = chNext;
+ unsigned char ch = chNext;
for (int i = 0; i < deleteLength; i++) {
chNext = substance.ValueAt(position + i + 1);
if (ch == '\r') {
@@ -584,6 +677,14 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) {
} else {
RemoveLine(lineRemove);
}
+ } else if (utf8LineEnds) {
+ if (!UTF8IsAscii(ch)) {
+ unsigned char next3[3] = {ch, chNext,
+ static_cast<unsigned char>(substance.ValueAt(position + i + 2))};
+ if (UTF8IsSeparator(next3) || UTF8IsNEL(next3)) {
+ RemoveLine(lineRemove);
+ }
+ }
}
ch = chNext;
diff --git a/src/CellBuffer.h b/src/CellBuffer.h
index 388b9027b..bfbb121de 100644
--- a/src/CellBuffer.h
+++ b/src/CellBuffer.h
@@ -136,12 +136,15 @@ private:
SplitVector<char> substance;
SplitVector<char> style;
bool readOnly;
+ int utf8LineEnds;
bool collectingUndo;
UndoHistory uh;
LineVector lv;
+ bool UTF8LineEndOverlaps(int position) const;
+ void ResetLineEnds();
/// Actions without undo
void BasicInsertString(int position, const char *s, int insertLength);
void BasicDeleteChars(int position, int deleteLength);
@@ -162,6 +165,8 @@ public:
int Length() const;
void Allocate(int newSize);
+ int GetLineEndTypes() const { return utf8LineEnds; }
+ void SetLineEndTypes(int utf8LineEnds_);
void SetPerLine(PerLine *pl);
int Lines() const;
int LineStart(int line) const;
diff --git a/src/Document.cxx b/src/Document.cxx
index 2036f383c..b75c754ac 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -87,6 +87,7 @@ Document::Document() {
eolMode = SC_EOL_LF;
#endif
dbcsCodePage = 0;
+ lineEndBitSet = SC_LINE_END_TYPE_DEFAULT;
stylingBits = 5;
stylingBitsMask = 0x1F;
stylingMask = 0;
@@ -157,12 +158,29 @@ bool Document::SetDBCSCodePage(int dbcsCodePage_) {
if (dbcsCodePage != dbcsCodePage_) {
dbcsCodePage = dbcsCodePage_;
SetCaseFolder(NULL);
+ cb.SetLineEndTypes(lineEndBitSet & LineEndTypesSupported());
return true;
} else {
return false;
}
}
+bool Document::SetLineEndTypesAllowed(int lineEndBitSet_) {
+ if (lineEndBitSet != lineEndBitSet_) {
+ lineEndBitSet = lineEndBitSet_;
+ int lineEndBitSetActive = lineEndBitSet & LineEndTypesSupported();
+ if (lineEndBitSetActive != cb.GetLineEndTypes()) {
+ ModifiedAt(0);
+ cb.SetLineEndTypes(lineEndBitSetActive);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
void Document::InsertLine(int line) {
for (int j=0; j<ldSize; j++) {
if (perLineData[j])
@@ -267,7 +285,21 @@ int SCI_METHOD Document::LineEnd(int line) const {
if (line == LinesTotal() - 1) {
return LineStart(line + 1);
} else {
- int position = LineStart(line + 1) - 1;
+ int position = LineStart(line + 1);
+ if (SC_CP_UTF8 == dbcsCodePage) {
+ unsigned char bytes[] = {
+ static_cast<unsigned char>(cb.CharAt(position-3)),
+ static_cast<unsigned char>(cb.CharAt(position-2)),
+ static_cast<unsigned char>(cb.CharAt(position-1)),
+ };
+ if (UTF8IsSeparator(bytes)) {
+ return position - UTF8SeparatorLength;
+ }
+ if (UTF8IsNEL(bytes+1)) {
+ return position - UTF8NELLength;
+ }
+ }
+ position--; // Back over CR or LF
// When line terminator is CR+LF, may need to go back one more
if ((position > LineStart(line)) && (cb.CharAt(position - 1) == '\r')) {
position--;
diff --git a/src/Document.h b/src/Document.h
index 592d2ecb9..16804d3a1 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -241,6 +241,7 @@ public:
int eolMode;
/// Can also be SC_CP_UTF8 to enable UTF-8 mode
int dbcsCodePage;
+ int lineEndBitSet;
int tabInChars;
int indentInChars;
int actualIndentInChars;
@@ -259,6 +260,9 @@ public:
virtual void Init();
int LineEndTypesSupported() const;
bool SetDBCSCodePage(int dbcsCodePage_);
+ int GetLineEndTypesAllowed() { return cb.GetLineEndTypes(); }
+ bool SetLineEndTypesAllowed(int lineEndBitSet_);
+ int GetLineEndTypesActive() { return cb.GetLineEndTypes(); }
virtual void InsertLine(int line);
virtual void RemoveLine(int line);
diff --git a/src/Editor.cxx b/src/Editor.cxx
index e4ae6060e..f150aa202 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -7784,6 +7784,21 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
pdoc->eolMode = wParam;
break;
+ case SCI_SETLINEENDTYPESALLOWED:
+ if (pdoc->SetLineEndTypesAllowed(wParam)) {
+ cs.Clear();
+ cs.InsertLines(0, pdoc->LinesTotal() - 1);
+ SetAnnotationHeights(0, pdoc->LinesTotal());
+ InvalidateStyleRedraw();
+ }
+ break;
+
+ case SCI_GETLINEENDTYPESALLOWED:
+ return pdoc->GetLineEndTypesAllowed();
+
+ case SCI_GETLINEENDTYPESACTIVE:
+ return pdoc->GetLineEndTypesActive();
+
case SCI_STARTSTYLING:
pdoc->StartStyling(wParam, static_cast<char>(lParam));
break;
@@ -8080,6 +8095,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_SETCODEPAGE:
if (ValidCodePage(wParam)) {
if (pdoc->SetDBCSCodePage(wParam)) {
+ cs.Clear();
+ cs.InsertLines(0, pdoc->LinesTotal() - 1);
+ SetAnnotationHeights(0, pdoc->LinesTotal());
InvalidateStyleRedraw();
}
}
diff --git a/src/UniConversion.h b/src/UniConversion.h
index 704f16239..70e8a9517 100644
--- a/src/UniConversion.h
+++ b/src/UniConversion.h
@@ -26,3 +26,16 @@ inline bool UTF8IsAscii(int ch) {
enum { UTF8MaskWidth=0x7, UTF8MaskInvalid=0x8 };
int UTF8Classify(const unsigned char *us, int len);
+
+// Line separator is U+2028 \xe2\x80\xa8
+// Paragraph separator is U+2029 \xe2\x80\xa9
+const int UTF8SeparatorLength = 3;
+inline bool UTF8IsSeparator(const unsigned char *us) {
+ return (us[0] == 0xe2) && (us[1] == 0x80) && ((us[2] == 0xa8) || (us[2] == 0xa9));
+}
+
+// NEL is U+0085 \xc2\x85
+const int UTF8NELLength = 2;
+inline bool UTF8IsNEL(const unsigned char *us) {
+ return (us[0] == 0xc2) && (us[1] == 0x85);
+}