diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/CellBuffer.cxx | 151 | 
1 files changed, 122 insertions, 29 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx index 2715be13f..4298cf7d5 100644 --- a/src/CellBuffer.cxx +++ b/src/CellBuffer.cxx @@ -65,6 +65,7 @@ public:  	virtual void SetPerLine(PerLine *pl) noexcept = 0;  	virtual void InsertText(Sci::Line line, Sci::Position delta) noexcept = 0;  	virtual void InsertLine(Sci::Line line, Sci::Position position, bool lineStart) = 0; +	virtual void InsertLines(Sci::Line line, const Sci::Position *positions, size_t lines, bool lineStart) = 0;  	virtual void SetLineStart(Sci::Line line, Sci::Position position) noexcept = 0;  	virtual void RemoveLine(Sci::Line line) = 0;  	virtual Sci::Line Lines() const noexcept = 0; @@ -128,6 +129,15 @@ public:  		const Sci::Position widthCurrent = LineWidth(line);  		starts.InsertText(static_cast<POS>(line), static_cast<POS>(width - widthCurrent));  	} +	void InsertLines(Sci::Line line, Sci::Line lines) { +		// Insert multiple lines with each temporarily 1 character wide. +		// The line widths will be fixed up by later measuring code. +		const POS lineAsPos = static_cast<POS>(line); +		const POS lineStart = starts.PositionFromPartition(lineAsPos - 1) + 1; +		for (POS l = 0; l < static_cast<POS>(lines); l++) { +			starts.InsertPartition(lineAsPos + l, lineStart + l); +		} +	}  };  template <typename POS> @@ -172,12 +182,10 @@ public:  		starts.InsertPartition(lineAsPos, static_cast<POS>(position));  		if (activeIndices) {  			if (activeIndices & SC_LINECHARACTERINDEX_UTF32) { -				startsUTF32.starts.InsertPartition(lineAsPos, -					static_cast<POS>(startsUTF32.starts.PositionFromPartition(lineAsPos - 1) + 1)); +				startsUTF32.InsertLines(line, 1);  			}  			if (activeIndices & SC_LINECHARACTERINDEX_UTF16) { -				startsUTF16.starts.InsertPartition(lineAsPos, -					static_cast<POS>(startsUTF16.starts.PositionFromPartition(lineAsPos - 1) + 1)); +				startsUTF16.InsertLines(line, 1);  			}  		}  		if (perLine) { @@ -186,6 +194,27 @@ public:  			perLine->InsertLine(line);  		}  	} +	void InsertLines(Sci::Line line, const Sci::Position *positions, size_t lines, bool lineStart) override { +		const POS lineAsPos = static_cast<POS>(line); +		if constexpr (sizeof(Sci::Position) == sizeof(POS)) { +			starts.InsertPartitions(lineAsPos, positions, lines); +		} else { +			starts.InsertPartitionsWithCast(lineAsPos, positions, lines); +		} +		if (activeIndices) { +			if (activeIndices & SC_LINECHARACTERINDEX_UTF32) { +				startsUTF32.InsertLines(line, lines); +			} +			if (activeIndices & SC_LINECHARACTERINDEX_UTF16) { +				startsUTF16.InsertLines(line, lines); +			} +		} +		if (perLine) { +			if ((line > 0) && lineStart) +				line--; +			perLine->InsertLines(line, lines); +		} +	}  	void SetLineStart(Sci::Line line, Sci::Position position) noexcept override {  		starts.SetPartitionStartPosition(static_cast<POS>(line), static_cast<POS>(position));  	} @@ -971,33 +1000,97 @@ void CellBuffer::BasicInsertString(Sci::Position position, const char *s, Sci::P  	if (breakingUTF8LineEnd) {  		RemoveLine(lineInsert);  	} -	unsigned char ch = ' '; -	for (Sci::Position i = 0; i < insertLength; i++) { -		ch = s[i]; -		if (ch == '\r') { -			InsertLine(lineInsert, (position + i) + 1, atLineStart); -			lineInsert++; -			simpleInsertion = false; -		} else if (ch == '\n') { -			if (chPrev == '\r') { -				// Patch up what was end of line -				plv->SetLineStart(lineInsert - 1, (position + i) + 1); -			} else { -				InsertLine(lineInsert, (position + i) + 1, atLineStart); -				lineInsert++; + +	constexpr size_t PositionBlockSize = 128; +	Sci::Position positions[PositionBlockSize]{}; +	size_t nPositions = 0; +	const Sci::Line lineStart = lineInsert; + +	// s may not NULL-terminated, ensure *ptr == '\n' or *next == '\n' is valid. +	const char * const end = s + insertLength - 1; +	const char *ptr = s; +	unsigned char ch = 0; + +	if (chPrev == '\r' && *ptr == '\n') { +		++ptr; +		// Patch up what was end of line +		plv->SetLineStart(lineInsert - 1, (position + ptr - s)); +		simpleInsertion = false; +	} + +	if (ptr < end) { +		uint8_t eolTable[256]{}; +		eolTable[static_cast<uint8_t>('\n')] = 1; +		eolTable[static_cast<uint8_t>('\r')] = 2; +		if (utf8LineEnds) { +			// see UniConversion.h for LS, PS and NEL +			eolTable[0x85] = 4; +			eolTable[0xa8] = 3; +			eolTable[0xa9] = 3; +		} + +		do { +			// skip to line end +			ch = *ptr++; +			uint8_t type; +			while ((type = eolTable[ch]) == 0 && ptr < end) { +				chBeforePrev = chPrev; +				chPrev = ch; +				ch = *ptr++;  			} -			simpleInsertion = false; -		} else if (utf8LineEnds) { -			const unsigned char back3[3] = {chBeforePrev, chPrev, ch}; -			if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) { -				InsertLine(lineInsert, (position + i) + 1, atLineStart); +			switch (type) { +			case 2: // '\r' +				if (*ptr == '\n') { +					++ptr; +				} +				[[fallthrough]]; +			case 1: // '\n' +				positions[nPositions++] = position + ptr - s; +				if (nPositions == PositionBlockSize) { +					plv->InsertLines(lineInsert, positions, nPositions, atLineStart); +					lineInsert += nPositions; +					nPositions = 0; +				} +				break; +			case 3: +			case 4: +				// LS, PS and NEL +				if ((type == 3 && chPrev == 0x80 && chBeforePrev == 0xe2) || (type == 4 && chPrev == 0xc2)) { +					positions[nPositions++] = position + ptr - s; +					if (nPositions == PositionBlockSize) { +						plv->InsertLines(lineInsert, positions, nPositions, atLineStart); +						lineInsert += nPositions; +						nPositions = 0; +					} +				} +				break; +			} + +			chBeforePrev = chPrev; +			chPrev = ch; +		} while (ptr < end); +	} + +	if (nPositions != 0) { +		plv->InsertLines(lineInsert, positions, nPositions, atLineStart); +		lineInsert += nPositions; +	} + +	ch = *end; +	if (ptr == end) { +		++ptr; +		if (ch == '\r' || ch == '\n') { +			InsertLine(lineInsert, (position + ptr - s), atLineStart); +			lineInsert++; +		} else if (utf8LineEnds && !UTF8IsAscii(ch)) { +			const unsigned char back3[3] = { chBeforePrev, chPrev, ch }; +			if (UTF8IsSeparator(back3) || UTF8IsNEL(back3 + 1)) { +				InsertLine(lineInsert, (position + ptr - s), atLineStart);  				lineInsert++; -				simpleInsertion = false;  			}  		} -		chBeforePrev = chPrev; -		chPrev = ch;  	} +  	// Joining two lines where last insertion is cr and following substance starts with lf  	if (chAfter == '\n') {  		if (ch == '\r') { @@ -1006,6 +1099,8 @@ void CellBuffer::BasicInsertString(Sci::Position position, const char *s, Sci::P  			simpleInsertion = false;  		}  	} else if (utf8LineEnds && !UTF8IsAscii(chAfter)) { +		chBeforePrev = chPrev; +		chPrev = ch;  		// May have end of UTF-8 line end in buffer and start in insertion  		for (int j = 0; j < UTF8SeparatorLength-1; j++) {  			const unsigned char chAt = substance.ValueAt(position + insertLength + j); @@ -1013,19 +1108,17 @@ void CellBuffer::BasicInsertString(Sci::Position position, const char *s, Sci::P  			if (UTF8IsSeparator(back3)) {  				InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart);  				lineInsert++; -				simpleInsertion = false;  			}  			if ((j == 0) && UTF8IsNEL(back3+1)) {  				InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart);  				lineInsert++; -				simpleInsertion = false;  			}  			chBeforePrev = chPrev;  			chPrev = chAt;  		}  	}  	if (maintainingIndex) { -		if (simpleInsertion) { +		if (simpleInsertion && (lineInsert == lineStart)) {  			const CountWidths cw = CountCharacterWidthsUTF8(std::string_view(s, insertLength));  			plv->InsertCharacters(linePosition, cw);  		} else {  | 
