diff options
Diffstat (limited to 'src/CellBuffer.cxx')
-rw-r--r-- | src/CellBuffer.cxx | 115 |
1 files changed, 108 insertions, 7 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; |