aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--doc/ScintillaHistory.html4
-rw-r--r--src/Editor.cxx22
-rw-r--r--test/simpleTests.py43
3 files changed, 57 insertions, 12 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 344c230c6..d668a4a2c 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -585,6 +585,10 @@
<li>
Released 6 December 2022.
</li>
+ <li>
+ Fix SCI_LINESJOIN bug where carriage returns were incorrectly retained.
+ <a href="https://sourceforge.net/p/scintilla/bugs/2372/">Bug #2372</a>.
+ </li>
</ul>
<h3>
<a href="https://www.scintilla.org/scintilla532.zip">Release 5.3.2</a>
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 3bf50b09e..fac808e54 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -1623,19 +1623,17 @@ bool Editor::WrapLines(WrapScope ws) {
void Editor::LinesJoin() {
if (!RangeContainsProtected(targetRange.start.Position(), targetRange.end.Position())) {
UndoGroup ug(pdoc);
- bool prevNonWS = true;
- for (Sci::Position pos = targetRange.start.Position(); pos < targetRange.end.Position(); pos++) {
- if (pdoc->IsPositionInLineEnd(pos)) {
- targetRange.end.Add(-pdoc->LenChar(pos));
- pdoc->DelChar(pos);
- if (prevNonWS) {
- // Ensure at least one space separating previous lines
- const Sci::Position lengthInserted = pdoc->InsertString(pos, " ", 1);
- targetRange.end.Add(lengthInserted);
- }
- } else {
- prevNonWS = pdoc->CharAt(pos) != ' ';
+ for (Sci::Position pos = pdoc->LineEndPosition(targetRange.start.Position()); pos < targetRange.end.Position();) {
+ const char chPrev = pdoc->CharAt(pos - 1);
+ const Sci::Position widthChar = pdoc->LenChar(pos);
+ targetRange.end.Add(-widthChar);
+ pdoc->DeleteChars(pos, widthChar);
+ if (chPrev != ' ') {
+ // Ensure at least one space separating previous lines
+ const Sci::Position lengthInserted = pdoc->InsertString(pos, " ", 1);
+ targetRange.end.Add(lengthInserted);
}
+ pos = pdoc->LineEndPosition(pos);
}
}
}
diff --git a/test/simpleTests.py b/test/simpleTests.py
index a16b940fd..5383911ee 100644
--- a/test/simpleTests.py
+++ b/test/simpleTests.py
@@ -2960,6 +2960,49 @@ class TestDirectAccess(unittest.TestCase):
cpBuffer = ctypes.c_char_p(rangePointer)
self.assertEquals(cpBuffer.value, text[1:])
+class TestJoin(unittest.TestCase):
+ def setUp(self):
+ self.xite = Xite.xiteFrame
+ self.ed = self.xite.ed
+ self.ed.ClearAll()
+ self.ed.EmptyUndoBuffer()
+
+ def tearDown(self):
+ self.ed.ClearAll()
+ self.ed.EmptyUndoBuffer()
+
+ def testJoin(self):
+ text = b"a\r\nb\r\nc"
+ self.ed.SetContents(text)
+ self.ed.TargetWholeDocument()
+ self.ed.LinesJoin()
+ self.assertEquals(self.ed.Contents(), b"a b c")
+
+ def testJoinEndLine(self):
+ text = b"a\r\nb\r\nc"
+ self.ed.SetContents(text)
+ # Select a..b
+ self.ed.SetTargetRange(0, 4)
+ self.ed.LinesJoin()
+ self.assertEquals(self.ed.Contents(), b"a b\r\nc")
+
+ def testJoinSpace(self):
+ # Demonstration of bug #2372 which produced b"a \r"
+ text = b"a \r\n\r\n"
+ self.ed.SetContents(text)
+ self.ed.TargetWholeDocument()
+ self.ed.LinesJoin()
+ self.assertEquals(self.ed.Contents(), b"a ")
+
+ def testJoinOutOfBounds(self):
+ text = b"a\r\nb\r\nc"
+ self.ed.SetContents(text)
+ # Setting end of target after document end encourages non-termination.
+ self.ed.SetTargetRange(-10, 16)
+ self.ed.LinesJoin()
+ # Out-of-bounds leaves extra space as 'c' is processed
+ self.assertEquals(self.ed.Contents(), b"a b c ")
+
class TestWordChars(unittest.TestCase):
def setUp(self):
self.xite = Xite.xiteFrame