diff options
-rw-r--r-- | src/Document.cxx | 16 | ||||
-rw-r--r-- | test/unit/testDocument.cxx | 57 |
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); + } + } |