aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/Document.cxx16
-rw-r--r--test/unit/testDocument.cxx57
2 files changed, 64 insertions, 9 deletions
diff --git a/src/Document.cxx b/src/Document.cxx
index 6dc14238f..e0fd78eda 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -838,8 +838,13 @@ Sci::Position Document::NextPosition(Sci::Position pos, int moveDir) const noexc
if ((pos - 1) <= posStartLine) {
return pos - 1;
} else if (IsDBCSLeadByteNoExcept(cb.CharAt(pos - 1))) {
- // Must actually be trail byte
- return pos - 2;
+ // Should actually be trail byte
+ if (IsDBCSDualByteAt(pos - 2)) {
+ return pos - 2;
+ } else {
+ // Invalid byte pair so treat as one byte wide
+ return pos - 1;
+ }
} else {
// Otherwise, step back until a non-lead-byte is found.
Sci::Position posTemp = pos - 1;
@@ -848,7 +853,12 @@ Sci::Position Document::NextPosition(Sci::Position pos, int moveDir) const noexc
// Now posTemp+1 must point to the beginning of a character,
// so figure out whether we went back an even or an odd
// number of bytes and go back 1 or 2 bytes, respectively.
- return (pos - 1 - ((pos - posTemp) & 1));
+ const Sci::Position widthLast = ((pos - posTemp) & 1) + 1;
+ if ((widthLast == 2) && (IsDBCSDualByteAt(pos - widthLast))) {
+ return pos - widthLast;
+ }
+ // Byte before pos may be valid character or may be an invalid second byte
+ return pos - 1;
}
}
}
diff --git a/test/unit/testDocument.cxx b/test/unit/testDocument.cxx
index c91868165..a48ab3fcb 100644
--- a/test/unit/testDocument.cxx
+++ b/test/unit/testDocument.cxx
@@ -380,14 +380,59 @@ TEST_CASE("Document") {
REQUIRE(pos == 5);
pos = doc.NextPosition(1, -1);
REQUIRE(pos == 0);
- // The next two tests are commented out because the implementation of NextPosition
- // cannot yet handle character fragments correctly when moving backwards.
- //pos = doc.NextPosition(2, -1);
- //REQUIRE(pos == 1);
- //pos = doc.NextPosition(3, -1);
- //REQUIRE(pos == 2);
+ pos = doc.NextPosition(2, -1);
+ REQUIRE(pos == 1);
+ pos = doc.NextPosition(3, -1);
+ REQUIRE(pos == 2);
pos = doc.NextPosition(5, -1);
REQUIRE(pos == 3);
}
+ SECTION("NextPosition Valid DBCS") {
+ Document doc(DocumentOption::Default);
+ doc.SetDBCSCodePage(932);
+ REQUIRE(doc.CodePage() == 932);
+ // This text is valid in code page 932.
+ // O p e n = U+958B Ku ( O ) U+7DE8 -
+ // U+958B open
+ // U+7DE8 arrange
+ const std::string japaneseText = "Open=\x8aJ\x82\xad(O)\x95\xd2-";
+ const Sci::Position length = doc.InsertString(0, japaneseText.c_str(), japaneseText.length());
+ REQUIRE(length == 15);
+ // Forwards
+ REQUIRE(doc.NextPosition( 0, 1) == 1);
+ REQUIRE(doc.NextPosition( 1, 1) == 2);
+ REQUIRE(doc.NextPosition( 2, 1) == 3);
+ REQUIRE(doc.NextPosition( 3, 1) == 4);
+ REQUIRE(doc.NextPosition( 4, 1) == 5);
+ REQUIRE(doc.NextPosition( 5, 1) == 7); // Double byte
+ REQUIRE(doc.NextPosition( 6, 1) == 7);
+ REQUIRE(doc.NextPosition( 7, 1) == 9); // Double byte
+ REQUIRE(doc.NextPosition( 8, 1) == 9);
+ REQUIRE(doc.NextPosition( 9, 1) == 10);
+ REQUIRE(doc.NextPosition(10, 1) == 11);
+ REQUIRE(doc.NextPosition(11, 1) == 12);
+ REQUIRE(doc.NextPosition(12, 1) == 14); // Double byte
+ REQUIRE(doc.NextPosition(13, 1) == 14);
+ REQUIRE(doc.NextPosition(14, 1) == 15);
+ REQUIRE(doc.NextPosition(15, 1) == 15);
+ // Backwards
+ REQUIRE(doc.NextPosition( 0, -1) == 0);
+ REQUIRE(doc.NextPosition( 1, -1) == 0);
+ REQUIRE(doc.NextPosition( 2, -1) == 1);
+ REQUIRE(doc.NextPosition( 3, -1) == 2);
+ REQUIRE(doc.NextPosition( 4, -1) == 3);
+ REQUIRE(doc.NextPosition( 5, -1) == 4);
+ REQUIRE(doc.NextPosition( 6, -1) == 5); // Double byte
+ REQUIRE(doc.NextPosition( 7, -1) == 5);
+ REQUIRE(doc.NextPosition( 8, -1) == 7); // Double byte
+ REQUIRE(doc.NextPosition( 9, -1) == 7);
+ REQUIRE(doc.NextPosition(10, -1) == 9);
+ REQUIRE(doc.NextPosition(11, -1) == 10);
+ REQUIRE(doc.NextPosition(12, -1) == 11);
+ REQUIRE(doc.NextPosition(13, -1) == 12); // Double byte
+ REQUIRE(doc.NextPosition(14, -1) == 12);
+ REQUIRE(doc.NextPosition(15, -1) == 14);
+ }
+
}