aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2025-02-01 14:43:22 +1100
committerNeil <nyamatongwe@gmail.com>2025-02-01 14:43:22 +1100
commitf54fd2019dd648b29a80ec7429833ab546d3a428 (patch)
tree231bebba7db25fccf798340bdd908f28fd504c26
parentdb6332fa9933244c45c44063afbdcccb462cfc03 (diff)
downloadscintilla-mirror-f54fd2019dd648b29a80ec7429833ab546d3a428.tar.gz
Serialize selection type and ranges with SCI_GETSELECTIONSERIALIZED and
SCI_SETSELECTIONSERIALIZED.
-rw-r--r--call/ScintillaCall.cxx12
-rw-r--r--doc/ScintillaDoc.html12
-rw-r--r--doc/ScintillaHistory.html3
-rw-r--r--include/Scintilla.h2
-rw-r--r--include/Scintilla.iface6
-rw-r--r--include/ScintillaCall.h3
-rw-r--r--include/ScintillaMessages.h2
-rw-r--r--src/Editor.cxx18
-rw-r--r--src/Editor.h1
-rw-r--r--src/Selection.cxx17
-rw-r--r--src/Selection.h2
-rw-r--r--test/simpleTests.py33
12 files changed, 110 insertions, 1 deletions
diff --git a/call/ScintillaCall.cxx b/call/ScintillaCall.cxx
index 550adc710..57b050805 100644
--- a/call/ScintillaCall.cxx
+++ b/call/ScintillaCall.cxx
@@ -1267,6 +1267,18 @@ UndoSelectionHistoryOption ScintillaCall::UndoSelectionHistory() {
return static_cast<Scintilla::UndoSelectionHistoryOption>(Call(Message::GetUndoSelectionHistory));
}
+void ScintillaCall::SetSelectionSerialized(const char *selectionString) {
+ CallString(Message::SetSelectionSerialized, 0, selectionString);
+}
+
+Position ScintillaCall::SelectionSerialized(char *selectionString) {
+ return CallPointer(Message::GetSelectionSerialized, 0, selectionString);
+}
+
+std::string ScintillaCall::SelectionSerialized() {
+ return CallReturnString(Message::GetSelectionSerialized, 0);
+}
+
Line ScintillaCall::FirstVisibleLine() {
return Call(Message::GetFirstVisibleLine);
}
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html
index 886786484..dda900b7c 100644
--- a/doc/ScintillaDoc.html
+++ b/doc/ScintillaDoc.html
@@ -130,7 +130,7 @@
<h1>Scintilla Documentation</h1>
- <p>Last edited 26 October 2024 NH</p>
+ <p>Last edited 1 February 2025 NH</p>
<p style="background:#90F0C0">Scintilla 5 has moved the lexers from Scintilla into a new
<a href="Lexilla.html">Lexilla</a> project.<br />
@@ -1239,6 +1239,10 @@ struct Sci_TextRangeFull {
<a class="message" href="#SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE">SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE &rarr; position</a><br />
<br />
+ <a class="message" href="#SCI_SETSELECTIONSERIALIZED">SCI_SETSELECTIONSERIALIZED(&lt;unused&gt;, const char *selectionString)</a><br />
+ <a class="message" href="#SCI_GETSELECTIONSERIALIZED">SCI_GETSELECTIONSERIALIZED(&lt;unused&gt;, char *selectionString) &rarr; position</a><br />
+ <br />
+
<a class="element" href="#SC_ELEMENT_SELECTION_ADDITIONAL_TEXT">SC_ELEMENT_SELECTION_ADDITIONAL_TEXT : colouralpha</a><br />
<a class="element" href="#SC_ELEMENT_SELECTION_ADDITIONAL_BACK">SC_ELEMENT_SELECTION_ADDITIONAL_BACK : colouralpha</a><br />
<a class="discouraged message" href="#SCI_SETADDITIONALSELALPHA">SCI_SETADDITIONALSELALPHA(alpha alpha)</a><br />
@@ -1405,6 +1409,12 @@ struct Sci_TextRangeFull {
After setting the rectangular selection, this is broken down into multiple selections, one for each line.</p>
<p>
+ <b id="SCI_SETSELECTIONSERIALIZED">SCI_SETSELECTIONSERIALIZED(&lt;unused&gt;, const char *selectionString)</b><br />
+ <b id="SCI_GETSELECTIONSERIALIZED">SCI_GETSELECTIONSERIALIZED(&lt;unused&gt;, char *selectionString) &rarr; position</b><br />
+ Set or query the selection type and positions as a serialized string.
+ The format of this string may change in future versions so should not be persisted beyond the current session.</p>
+
+ <p>
<b id="SC_ELEMENT_SELECTION_ADDITIONAL_TEXT">SC_ELEMENT_SELECTION_ADDITIONAL_TEXT : colouralpha</b><br />
<b id="SC_ELEMENT_SELECTION_ADDITIONAL_BACK">SC_ELEMENT_SELECTION_ADDITIONAL_BACK : colouralpha</b><br />
<b id="SCI_SETADDITIONALSELALPHA">SCI_SETADDITIONALSELALPHA(<a class="jump" href="#alpha">alpha</a> alpha)</b><br />
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 7cb5ebcee..782801b7a 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -601,6 +601,9 @@
<a href="https://sourceforge.net/p/scintilla/bugs/1224/">Bug #1224</a>.
</li>
<li>
+ Serialize selection type and ranges with SCI_GETSELECTIONSERIALIZED and SCI_SETSELECTIONSERIALIZED.
+ </li>
+ <li>
Fix bug on Qt where double-click stopped working when Scintilla instance had been running for weeks.
</li>
</ul>
diff --git a/include/Scintilla.h b/include/Scintilla.h
index 736a7e2d5..4de92e1b8 100644
--- a/include/Scintilla.h
+++ b/include/Scintilla.h
@@ -536,6 +536,8 @@ typedef sptr_t (*SciFnDirectStatus)(sptr_t ptr, unsigned int iMessage, uptr_t wP
#define SC_UNDO_SELECTION_HISTORY_ENABLED 1
#define SCI_SETUNDOSELECTIONHISTORY 2782
#define SCI_GETUNDOSELECTIONHISTORY 2783
+#define SCI_SETSELECTIONSERIALIZED 2784
+#define SCI_GETSELECTIONSERIALIZED 2785
#define SCI_GETFIRSTVISIBLELINE 2152
#define SCI_GETLINE 2153
#define SCI_GETLINECOUNT 2154
diff --git a/include/Scintilla.iface b/include/Scintilla.iface
index 65d3d157b..4ce9d5703 100644
--- a/include/Scintilla.iface
+++ b/include/Scintilla.iface
@@ -1344,6 +1344,12 @@ set void SetUndoSelectionHistory=2782(UndoSelectionHistoryOption undoSelectionHi
# Report undo selection history status.
get UndoSelectionHistoryOption GetUndoSelectionHistory=2783(,)
+# Set selection from serialized form.
+set void SetSelectionSerialized=2784(, string selectionString)
+
+# Retrieve serialized form of selection.
+get position GetSelectionSerialized=2785(, stringresult selectionString)
+
# Retrieve the display line at the top of the display.
get line GetFirstVisibleLine=2152(,)
diff --git a/include/ScintillaCall.h b/include/ScintillaCall.h
index bcd462be9..345d15612 100644
--- a/include/ScintillaCall.h
+++ b/include/ScintillaCall.h
@@ -362,6 +362,9 @@ public:
Scintilla::ChangeHistoryOption ChangeHistory();
void SetUndoSelectionHistory(Scintilla::UndoSelectionHistoryOption undoSelectionHistory);
Scintilla::UndoSelectionHistoryOption UndoSelectionHistory();
+ void SetSelectionSerialized(const char *selectionString);
+ Position SelectionSerialized(char *selectionString);
+ std::string SelectionSerialized();
Line FirstVisibleLine();
Position GetLine(Line line, char *text);
std::string GetLine(Line line);
diff --git a/include/ScintillaMessages.h b/include/ScintillaMessages.h
index f60be4d52..d7ec27c39 100644
--- a/include/ScintillaMessages.h
+++ b/include/ScintillaMessages.h
@@ -287,6 +287,8 @@ enum class Message {
GetChangeHistory = 2781,
SetUndoSelectionHistory = 2782,
GetUndoSelectionHistory = 2783,
+ SetSelectionSerialized = 2784,
+ GetSelectionSerialized = 2785,
GetFirstVisibleLine = 2152,
GetLine = 2153,
GetLineCount = 2154,
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 10c694990..d85a4c294 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -711,6 +711,15 @@ void Editor::SetEmptySelection(Sci::Position currentPos_) {
SetEmptySelection(SelectionPosition(currentPos_));
}
+void Editor::SetSelectionFromSerialized(const char *serialized) {
+ if (serialized) {
+ sel = Selection(serialized);
+ sel.Truncate(pdoc->Length());
+ SetRectangularRange();
+ InvalidateStyleRedraw();
+ }
+}
+
void Editor::MultipleSelectAdd(AddNumber addNumber) {
if (SelectionEmpty() || !multipleSelection) {
// Select word at caret
@@ -8695,6 +8704,15 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) {
case Message::GetUndoSelectionHistory:
return static_cast<sptr_t>(undoSelectionHistoryOption);
+ case Message::SetSelectionSerialized:
+ SetSelectionFromSerialized(ConstCharPtrFromSPtr(lParam));
+ break;
+
+ case Message::GetSelectionSerialized: {
+ const std::string serialized = sel.ToString();
+ return BytesResult(lParam, serialized);
+ }
+
case Message::SetExtraAscent:
vs.extraAscent = static_cast<int>(wParam);
InvalidateStyleRedraw();
diff --git a/src/Editor.h b/src/Editor.h
index a6a484ede..ff940bc49 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -352,6 +352,7 @@ protected: // ScintillaBase subclass needs access to much of Editor
void SetSelection(SelectionPosition currentPos_);
void SetEmptySelection(SelectionPosition currentPos_);
void SetEmptySelection(Sci::Position currentPos_);
+ void SetSelectionFromSerialized(const char *serialized);
enum class AddNumber { one, each };
void MultipleSelectAdd(AddNumber addNumber);
bool RangeContainsProtected(Sci::Position start, Sci::Position end) const noexcept;
diff --git a/src/Selection.cxx b/src/Selection.cxx
index 5650d5c7e..7b517cc4a 100644
--- a/src/Selection.cxx
+++ b/src/Selection.cxx
@@ -225,6 +225,13 @@ bool SelectionRange::Trim(SelectionRange range) noexcept {
}
}
+void SelectionRange::Truncate(Sci::Position length) noexcept {
+ if (anchor.Position() > length)
+ anchor.SetPosition(length);
+ if (caret.Position() > length)
+ caret.SetPosition(length);
+}
+
// If range is all virtual collapse to start of virtual space
void SelectionRange::MinimizeVirtualSpace() noexcept {
if (caret.Position() == anchor.Position()) {
@@ -568,6 +575,16 @@ void Selection::SetRanges(const Ranges &rangesToSet) {
ranges = rangesToSet;
}
+void Selection::Truncate(Sci::Position length) noexcept {
+ // This may be needed when applying a persisted selection onto a document that has been shortened.
+ for (SelectionRange &range : ranges) {
+ range.Truncate(length);
+ }
+ // Above may have made some non-unique empty ranges.
+ RemoveDuplicates();
+ rangeRectangular.Truncate(length);
+}
+
std::string Selection::ToString() const {
std::string result;
switch (selType) {
diff --git a/src/Selection.h b/src/Selection.h
index 68e7a4e54..57de92a57 100644
--- a/src/Selection.h
+++ b/src/Selection.h
@@ -148,6 +148,7 @@ struct SelectionRange {
}
void Swap() noexcept;
bool Trim(SelectionRange range) noexcept;
+ void Truncate(Sci::Position length) noexcept;
// If range is all virtual collapse to start of virtual space
void MinimizeVirtualSpace() noexcept;
std::string ToString() const;
@@ -216,6 +217,7 @@ public:
return ranges;
}
void SetRanges(const Ranges &rangesToSet);
+ void Truncate(Sci::Position length) noexcept;
std::string ToString() const;
};
diff --git a/test/simpleTests.py b/test/simpleTests.py
index ce67edfde..867c0ebbc 100644
--- a/test/simpleTests.py
+++ b/test/simpleTests.py
@@ -2242,6 +2242,39 @@ class TestMultiSelection(unittest.TestCase):
self.assertEqual(self.ed.Contents(), b'a 1')
self.assertEqual(self.textOfSelection(0), b' ')
+ def testSelectionSerialization(self):
+ self.ed.SetContents(b"a")
+ self.ed.SetSelection(0, 1)
+ self.assertEqual(self.ed.GetSelectionSerialized(), b'1-0')
+ self.ed.SetSelection(1, 1)
+ self.assertEqual(self.ed.GetSelectionSerialized(), b'1')
+ self.ed.SetSelectionNAnchorVirtualSpace(0, 2)
+ self.ed.SetSelectionNCaretVirtualSpace(0, 3)
+ self.assertEqual(selectionRepresentation(self.ed, 0), "1+2v-1+3v")
+ self.assertEqual(self.textOfSelection(0), b'')
+ self.assertEqual(self.ed.GetSelectionSerialized(), b'1v2-1v3')
+ self.ed.SetSelectionSerialized(0, b'1-0')
+ self.assertEqual(self.ed.MainSelection, 0)
+ self.assertEqual(self.ed.Anchor, 1)
+ self.assertEqual(self.ed.CurrentPos, 0)
+ self.assertEqual(self.ed.GetSelectionNAnchor(0), 1)
+ self.assertEqual(self.ed.GetSelectionNCaret(0), 0)
+
+ def testSelectionSerializationOutOfBounds(self):
+ # Try setting selections that extend past document end through serialized form
+ # and check that the selection is limited to the document.
+ self.ed.SetContents(b"a")
+ self.ed.SetSelectionSerialized(0, b'200-0')
+ self.assertEqual(self.ed.GetSelectionSerialized(), b'1-0')
+
+ # Retain virtual space
+ self.ed.SetSelectionSerialized(0, b'0v1-200')
+ self.assertEqual(self.ed.GetSelectionSerialized(), b'0v1-1')
+
+ # Drop identical ranges, but touching empty range survives
+ self.ed.SetSelectionSerialized(0, b'0-200,300-400,500-600')
+ self.assertEqual(self.ed.GetSelectionSerialized(), b'0-1,1')
+
class TestModalSelection(unittest.TestCase):