aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/Editor.cxx22
-rw-r--r--test/simpleTests.py35
2 files changed, 51 insertions, 6 deletions
diff --git a/src/Editor.cxx b/src/Editor.cxx
index f778ea933..f925beab7 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -5000,18 +5000,28 @@ void Editor::ChangeCaseOfSelection(int caseMapping) {
size_t firstDifference = 0;
while (sMapped[firstDifference] == sText[firstDifference])
firstDifference++;
- size_t lastDifference = sMapped.size() - 1;
- while (sMapped[lastDifference] == sText[lastDifference])
- lastDifference--;
- size_t endSame = sMapped.size() - 1 - lastDifference;
+ size_t lastDifferenceText = sText.size() - 1;
+ size_t lastDifferenceMapped = sMapped.size() - 1;
+ while (sMapped[lastDifferenceMapped] == sText[lastDifferenceText]) {
+ lastDifferenceText--;
+ lastDifferenceMapped--;
+ }
+ size_t endDifferenceText = sText.size() - 1 - lastDifferenceText;
pdoc->DeleteChars(
static_cast<int>(currentNoVS.Start().Position() + firstDifference),
- static_cast<int>(rangeBytes - firstDifference - endSame));
+ static_cast<int>(rangeBytes - firstDifference - endDifferenceText));
pdoc->InsertString(
static_cast<int>(currentNoVS.Start().Position() + firstDifference),
sMapped.c_str() + firstDifference,
- static_cast<int>(lastDifference - firstDifference + 1));
+ static_cast<int>(lastDifferenceMapped - firstDifference + 1));
// Automatic movement changes selection so reset to exactly the same as it was.
+ int diffSizes = sMapped.size() - sText.size();
+ if (diffSizes != 0) {
+ if (current.anchor > current.caret)
+ current.anchor.Add(diffSizes);
+ else
+ current.caret.Add(diffSizes);
+ }
sel.Range(r) = current;
}
}
diff --git a/test/simpleTests.py b/test/simpleTests.py
index a101857f8..e9aef81e2 100644
--- a/test/simpleTests.py
+++ b/test/simpleTests.py
@@ -1413,6 +1413,41 @@ class TestCaseMapping(unittest.TestCase):
self.assertEquals(self.ed.Length, 1)
self.assertEquals(self.ed.Contents(), r)
+ def testUTFGrows(self):
+ # FIXME: change to using Unicode compliant case conversion on Windows
+ if sys.platform != "win32":
+ # This crashed at one point in debug builds due to looking past end of shorter string
+ self.ed.SetCodePage(65001)
+ # ﬖ is a single character ligature taking 3 bytes in UTF8: EF AC 96
+ t = 'ﬖﬖ'.encode("UTF-8")
+ self.ed.SetText(len(t), t)
+ self.assertEquals(self.ed.Length, 6)
+ self.ed.SetSel(0,self.ed.Length)
+ self.ed.UpperCase()
+ # To convert to upper case the ligature is separated into վ and ն then uppercased to Վ and Ն
+ # each of which takes 2 bytes in UTF-8: D5 8E D5 86
+ r = 'ՎՆՎՆ'.encode("UTF-8")
+ self.assertEquals(self.ed.Length, 8)
+ self.assertEquals(self.ed.Contents(), r)
+ self.assertEquals(self.ed.SelectionEnd, self.ed.Length)
+
+ def testUTFShrinks(self):
+ # FIXME: change to using Unicode compliant case conversion on Windows
+ if sys.platform != "win32":
+ self.ed.SetCodePage(65001)
+ # fi is a single character ligature taking 3 bytes in UTF8: EF AC 81
+ t = 'fifi'.encode("UTF-8")
+ self.ed.SetText(len(t), t)
+ self.assertEquals(self.ed.Length, 6)
+ self.ed.SetSel(0,self.ed.Length)
+ self.ed.UpperCase()
+ # To convert to upper case the ligature is separated into f and i then uppercased to F and I
+ # each of which takes 1 byte in UTF-8: 46 49
+ r = 'FIFI'.encode("UTF-8")
+ self.assertEquals(self.ed.Length, 4)
+ self.assertEquals(self.ed.Contents(), r)
+ self.assertEquals(self.ed.SelectionEnd, self.ed.Length)
+
class TestCaseInsensitiveSearch(unittest.TestCase):
def setUp(self):
self.xite = Xite.xiteFrame