aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2025-12-08 14:38:07 +1100
committerNeil <nyamatongwe@gmail.com>2025-12-08 14:38:07 +1100
commit724429a7c661eeafe3094a049f747267d0496a69 (patch)
tree5e61c00fe32ca0860f0f24446a1421622c13e6a7
parent3b9c68ac4239f07d7a9117010778987e5b98502c (diff)
downloadscintilla-mirror-724429a7c661eeafe3094a049f747267d0496a69.tar.gz
Bug [#2488]. Fix SCI_SETSELECTIONNSTART and SCI_SETSELECTIONNEND.
-rw-r--r--doc/ScintillaHistory.html12
-rw-r--r--src/Editor.cxx4
-rw-r--r--src/Selection.cxx28
-rw-r--r--src/Selection.h2
-rw-r--r--test/simpleTests.py22
-rw-r--r--test/unit/testSelection.cxx90
6 files changed, 156 insertions, 2 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 0cced840e..48529c8d6 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -595,6 +595,18 @@
</table>
<h2 id="Releases">Releases</h2>
<h3>
+ <a href="https://www.scintilla.org/scintilla559.zip">Release 5.5.9</a>
+ </h3>
+ <ul>
+ <li>
+ Released 10 November 2025.
+ </li>
+ <li>
+ Fix SCI_SETSELECTIONNSTART and SCI_SETSELECTIONNEND to behave more sensibly.
+ <a href="https://sourceforge.net/p/scintilla/bugs/2488/">Bug #2488</a>.
+ </li>
+ </ul>
+ <h3>
<a href="https://www.scintilla.org/scintilla558.zip">Release 5.5.8</a>
</h3>
<ul>
diff --git a/src/Editor.cxx b/src/Editor.cxx
index e7a309e67..1ad99c3ca 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -6178,11 +6178,11 @@ void Editor::SetSelectionNMessage(Message iMessage, uptr_t wParam, sptr_t lParam
break;
case Message::SetSelectionNStart:
- sel.Range(wParam).anchor.SetPosition(lParam);
+ sel.Range(wParam).StartSet(SelectionPosition(lParam));
break;
case Message::SetSelectionNEnd:
- sel.Range(wParam).caret.SetPosition(lParam);
+ sel.Range(wParam).EndSet(SelectionPosition(lParam));
break;
default:
diff --git a/src/Selection.cxx b/src/Selection.cxx
index 967033bff..e8d0148f5 100644
--- a/src/Selection.cxx
+++ b/src/Selection.cxx
@@ -182,6 +182,34 @@ SelectionSegment SelectionRange::Intersect(SelectionSegment check) const noexcep
};
}
+void SelectionRange::StartSet(SelectionPosition sp) noexcept {
+ if (anchor <= caret) {
+ anchor = sp;
+ if (caret < anchor) {
+ caret = anchor;
+ }
+ } else {
+ caret = sp;
+ if (anchor < caret) {
+ anchor = caret;
+ }
+ }
+}
+
+void SelectionRange::EndSet(SelectionPosition sp) noexcept {
+ if (caret >= anchor) {
+ caret = sp;
+ if (anchor > caret) {
+ anchor = caret;
+ }
+ } else {
+ anchor = sp;
+ if (caret > anchor) {
+ caret = anchor;
+ }
+ }
+}
+
void SelectionRange::Swap() noexcept {
std::swap(caret, anchor);
}
diff --git a/src/Selection.h b/src/Selection.h
index 1a57d2e78..0b3bb9159 100644
--- a/src/Selection.h
+++ b/src/Selection.h
@@ -156,6 +156,8 @@ struct SelectionRange {
SelectionPosition End() const noexcept {
return (anchor < caret) ? caret : anchor;
}
+ void StartSet(SelectionPosition sp) noexcept;
+ void EndSet(SelectionPosition sp) noexcept;
void Swap() noexcept;
bool Trim(SelectionRange range) noexcept;
void Truncate(Sci::Position length) noexcept;
diff --git a/test/simpleTests.py b/test/simpleTests.py
index 020b72e99..4e6a51d59 100644
--- a/test/simpleTests.py
+++ b/test/simpleTests.py
@@ -1967,6 +1967,28 @@ class TestMultiSelection(unittest.TestCase):
self.assertEqual(self.ed.GetSelectionNStart(0), 2)
self.assertEqual(self.ed.GetSelectionNEnd(0), 3)
+ self.ed.SetSelectionNStart(0, 1)
+ self.assertEqual(self.ed.GetSelectionNAnchor(0), 1)
+ self.assertEqual(self.ed.GetSelectionNCaret(0), 3)
+ self.assertEqual(self.ed.GetSelectionNStart(0), 1)
+ self.assertEqual(self.ed.GetSelectionNEnd(0), 3)
+
+ self.ed.SetSelectionNAnchor(0, 2)
+ self.ed.SetSelectionNCaret(0, 2)
+ self.ed.SetSelectionNStart(0, 9)
+ self.assertEqual(self.ed.GetSelectionNAnchor(0), 9)
+ self.assertEqual(self.ed.GetSelectionNCaret(0), 9)
+ self.assertEqual(self.ed.GetSelectionNStart(0), 9)
+ self.assertEqual(self.ed.GetSelectionNEnd(0), 9)
+
+ self.ed.SetSelectionNAnchor(0, 2)
+ self.ed.SetSelectionNCaret(0, 3)
+ self.ed.SetSelectionNStart(0, 9)
+ self.assertEqual(self.ed.GetSelectionNAnchor(0), 9)
+ self.assertEqual(self.ed.GetSelectionNCaret(0), 9)
+ self.assertEqual(self.ed.GetSelectionNStart(0), 9)
+ self.assertEqual(self.ed.GetSelectionNEnd(0), 9)
+
def test2Selections(self):
self.ed.SetSelection(1, 2)
self.ed.AddSelection(4, 5)
diff --git a/test/unit/testSelection.cxx b/test/unit/testSelection.cxx
index ab0065624..76eebca21 100644
--- a/test/unit/testSelection.cxx
+++ b/test/unit/testSelection.cxx
@@ -198,6 +198,96 @@ TEST_CASE("SelectionRange") {
REQUIRE(thin == single);
}
+ SECTION("StartEndSet") {
+ {
+ SelectionRange range;
+
+ range.StartSet(SelectionPosition(2));
+ range.EndSet(SelectionPosition(3));
+ REQUIRE(range.Start() == SelectionPosition(2));
+ REQUIRE(range.End() == SelectionPosition(3));
+ REQUIRE(range == SelectionRange(3, 2));
+
+ range.StartSet(SelectionPosition(1));
+ REQUIRE(range.Start() == SelectionPosition(1));
+ REQUIRE(range.End() == SelectionPosition(3));
+ REQUIRE(range == SelectionRange(3, 1));
+ }
+
+ {
+ // Outside after
+ SelectionRange range(2, 1);
+ range.StartSet(SelectionPosition(3));
+ REQUIRE(range.Start() == SelectionPosition(3));
+ REQUIRE(range.End() == SelectionPosition(3));
+ REQUIRE(range == SelectionRange(3, 3));
+ }
+
+ {
+ // Outside after
+ SelectionRange range(2, 1);
+ range.EndSet(SelectionPosition(3));
+ REQUIRE(range.Start() == SelectionPosition(1));
+ REQUIRE(range.End() == SelectionPosition(3));
+ REQUIRE(range == SelectionRange(3, 1));
+ }
+
+ {
+ // Outside before
+ SelectionRange range(2, 1);
+ range.StartSet(SelectionPosition(0));
+ REQUIRE(range.Start() == SelectionPosition(0));
+ REQUIRE(range.End() == SelectionPosition(2));
+ REQUIRE(range == SelectionRange(2, 0));
+ }
+
+ {
+ // Outside before
+ SelectionRange range(2, 1);
+ range.EndSet(SelectionPosition(0));
+ REQUIRE(range.Start() == SelectionPosition(0));
+ REQUIRE(range.End() == SelectionPosition(0));
+ REQUIRE(range == SelectionRange(0, 0));
+ }
+
+ {
+ // Inside
+ SelectionRange range(3, 1);
+ range.EndSet(SelectionPosition(2));
+ REQUIRE(range.Start() == SelectionPosition(1));
+ REQUIRE(range.End() == SelectionPosition(2));
+ REQUIRE(range == SelectionRange(2, 1));
+ }
+
+ {
+ // Inside
+ SelectionRange range(3, 1);
+ range.StartSet(SelectionPosition(2));
+ REQUIRE(range.Start() == SelectionPosition(2));
+ REQUIRE(range.End() == SelectionPosition(3));
+ REQUIRE(range == SelectionRange(3, 2));
+ }
+
+ {
+ // Empty then outside
+ SelectionRange range(2);
+ range.StartSet(SelectionPosition(9));
+ REQUIRE(range.Start() == SelectionPosition(9));
+ REQUIRE(range.End() == SelectionPosition(9));
+ REQUIRE(range == SelectionRange(9, 9));
+ }
+
+ {
+ // Empty then outside
+ SelectionRange range(2);
+ range.StartSet(SelectionPosition(0));
+ REQUIRE(range.Start() == SelectionPosition(0));
+ REQUIRE(range.End() == SelectionPosition(2));
+ REQUIRE(range == SelectionRange(2, 0));
+ }
+
+ }
+
}
TEST_CASE("Selection") {