aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/CellBuffer.cxx27
-rw-r--r--src/CellBuffer.h1
-rw-r--r--src/Document.cxx37
-rw-r--r--src/Document.h6
-rw-r--r--src/Editor.cxx6
-rw-r--r--test/unit/testCellBuffer.cxx52
6 files changed, 92 insertions, 37 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx
index ba11f1391..4b061db40 100644
--- a/src/CellBuffer.cxx
+++ b/src/CellBuffer.cxx
@@ -848,6 +848,33 @@ Sci::Position CellBuffer::LineStart(Sci::Line line) const noexcept {
return plv->LineStart(line);
}
+Sci::Position CellBuffer::LineEnd(Sci::Line line) const noexcept {
+ if (line >= Lines() - 1) {
+ return LineStart(line + 1);
+ } else {
+ Sci::Position position = LineStart(line + 1);
+ if (LineEndType::Unicode == GetLineEndTypes()) {
+ const unsigned char bytes[] = {
+ UCharAt(position - 3),
+ UCharAt(position - 2),
+ UCharAt(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)) && (CharAt(position - 1) == '\r')) {
+ position--;
+ }
+ return position;
+ }
+}
+
Sci::Line CellBuffer::LineFromPosition(Sci::Position pos) const noexcept {
return plv->LineFromPosition(pos);
}
diff --git a/src/CellBuffer.h b/src/CellBuffer.h
index 7f0b87c4d..f0aacf8ec 100644
--- a/src/CellBuffer.h
+++ b/src/CellBuffer.h
@@ -186,6 +186,7 @@ public:
Sci::Line Lines() const noexcept;
void AllocateLines(Sci::Line lines);
Sci::Position LineStart(Sci::Line line) const noexcept;
+ Sci::Position LineEnd(Sci::Line line) const noexcept;
Sci::Position IndexLineStart(Sci::Line line, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept;
Sci::Line LineFromPosition(Sci::Position pos) const noexcept;
Sci::Line LineFromPositionIndex(Sci::Position pos, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept;
diff --git a/src/Document.cxx b/src/Document.cxx
index a45479e4b..afe6717a1 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -458,30 +458,7 @@ bool Document::IsLineStartPosition(Sci::Position position) const {
}
Sci_Position SCI_METHOD Document::LineEnd(Sci_Position line) const {
- if (line >= LinesTotal() - 1) {
- return LineStart(line + 1);
- } else {
- Sci::Position position = LineStart(line + 1);
- if (LineEndType::Unicode == cb.GetLineEndTypes()) {
- const unsigned char bytes[] = {
- cb.UCharAt(position-3),
- cb.UCharAt(position-2),
- cb.UCharAt(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--;
- }
- return position;
- }
+ return cb.LineEnd(line);
}
void SCI_METHOD Document::SetErrorStatus(int status) {
@@ -500,16 +477,16 @@ Sci::Line Document::SciLineFromPosition(Sci::Position pos) const noexcept {
return cb.LineFromPosition(pos);
}
-Sci::Position Document::LineEndPosition(Sci::Position position) const {
- return LineEnd(LineFromPosition(position));
+Sci::Position Document::LineEndPosition(Sci::Position position) const noexcept {
+ return cb.LineEnd(cb.LineFromPosition(position));
}
-bool Document::IsLineEndPosition(Sci::Position position) const {
- return LineEnd(LineFromPosition(position)) == position;
+bool Document::IsLineEndPosition(Sci::Position position) const noexcept {
+ return LineEndPosition(position) == position;
}
-bool Document::IsPositionInLineEnd(Sci::Position position) const {
- return position >= LineEnd(LineFromPosition(position));
+bool Document::IsPositionInLineEnd(Sci::Position position) const noexcept {
+ return position >= LineEndPosition(position);
}
Sci::Position Document::VCHomePosition(Sci::Position position) const {
diff --git a/src/Document.h b/src/Document.h
index 72ed532b3..8889d6454 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -457,9 +457,9 @@ public:
[[nodiscard]] Range LineRange(Sci::Line line) const noexcept;
bool IsLineStartPosition(Sci::Position position) const;
Sci_Position SCI_METHOD LineEnd(Sci_Position line) const override;
- Sci::Position LineEndPosition(Sci::Position position) const;
- bool IsLineEndPosition(Sci::Position position) const;
- bool IsPositionInLineEnd(Sci::Position position) const;
+ Sci::Position LineEndPosition(Sci::Position position) const noexcept;
+ bool IsLineEndPosition(Sci::Position position) const noexcept;
+ bool IsPositionInLineEnd(Sci::Position position) const noexcept;
Sci::Position VCHomePosition(Sci::Position position) const;
Sci::Position IndexLineStart(Sci::Line line, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept;
Sci::Line LineFromPositionIndex(Sci::Position pos, Scintilla::LineCharacterIndexType lineCharacterIndex) const noexcept;
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 80436fd21..dd2fc7e98 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -625,13 +625,11 @@ SelectionRange Editor::LineSelectionRange(SelectionPosition currentPos_, Selecti
if (currentPos_ > anchor_) {
anchor_ = SelectionPosition(
pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position())));
- currentPos_ = SelectionPosition(
- pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position())));
+ currentPos_ = SelectionPosition(pdoc->LineEndPosition(currentPos_.Position()));
} else {
currentPos_ = SelectionPosition(
pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position())));
- anchor_ = SelectionPosition(
- pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position())));
+ anchor_ = SelectionPosition(pdoc->LineEndPosition(anchor_.Position()));
}
return SelectionRange(currentPos_, anchor_);
}
diff --git a/test/unit/testCellBuffer.cxx b/test/unit/testCellBuffer.cxx
index 690611d2f..b44f47735 100644
--- a/test/unit/testCellBuffer.cxx
+++ b/test/unit/testCellBuffer.cxx
@@ -72,6 +72,58 @@ TEST_CASE("CellBuffer") {
REQUIRE(!cb.CanRedo());
}
+ SECTION("LineEnds") {
+ // Check that various line ends produce correct result from LineEnd.
+ cb.SetLineEndTypes(LineEndType::Unicode);
+ bool startSequence = false;
+ {
+ // Unix \n
+ const char sText2[] = "Two\nLines";
+ const Sci::Position sLength2 = static_cast<Sci::Position>(strlen(sText2));
+ cb.InsertString(0, sText2, strlen(sText2), startSequence);
+ REQUIRE(3 == cb.LineEnd(0));
+ REQUIRE(sLength2 == cb.LineEnd(1));
+ cb.DeleteChars(0, sLength2, startSequence);
+ }
+ {
+ // Windows \r\n
+ const char sText2[] = "Two\r\nLines";
+ const Sci::Position sLength2 = static_cast<Sci::Position>(strlen(sText2));
+ cb.InsertString(0, sText2, sLength2, startSequence);
+ REQUIRE(3 == cb.LineEnd(0));
+ REQUIRE(sLength2 == cb.LineEnd(1));
+ cb.DeleteChars(0, sLength2, startSequence);
+ }
+ {
+ // Old macOS \r
+ const char sText2[] = "Two\rLines";
+ const Sci::Position sLength2 = static_cast<Sci::Position>(strlen(sText2));
+ cb.InsertString(0, sText2, strlen(sText2), startSequence);
+ REQUIRE(3 == cb.LineEnd(0));
+ REQUIRE(sLength2 == cb.LineEnd(1));
+ cb.DeleteChars(0, sLength2, startSequence);
+ }
+ {
+ // Unicode NEL is U+0085 \xc2\x85
+ const char sText2[] = "Two\xc2\x85Lines";
+ const Sci::Position sLength2 = static_cast<Sci::Position>(strlen(sText2));
+ cb.InsertString(0, sText2, sLength2, startSequence);
+ REQUIRE(3 == cb.LineEnd(0));
+ REQUIRE(sLength2 == cb.LineEnd(1));
+ cb.DeleteChars(0, sLength2, startSequence);
+ }
+ {
+ // Unicode LS line separator is U+2028 \xe2\x80\xa8
+ const char sText2[] = "Two\xe2\x80\xa8Lines";
+ const Sci::Position sLength2 = static_cast<Sci::Position>(strlen(sText2));
+ cb.InsertString(0, sText2, sLength2, startSequence);
+ REQUIRE(3 == cb.LineEnd(0));
+ REQUIRE(sLength2 == cb.LineEnd(1));
+ cb.DeleteChars(0, sLength2, startSequence);
+ }
+ cb.SetLineEndTypes(LineEndType::Default);
+ }
+
SECTION("UndoOff") {
REQUIRE(cb.IsCollectingUndo());
cb.SetUndoCollection(false);