diff options
author | Zufu Liu <unknown> | 2025-07-03 08:23:26 +1000 |
---|---|---|
committer | Zufu Liu <unknown> | 2025-07-03 08:23:26 +1000 |
commit | cde12528a7e587833926354b88ad1974aedaf103 (patch) | |
tree | a6b75dc168997106346dafdd8a424d44949c29f1 | |
parent | 181b13c2eed7499d192d0b85c7269dc7ab71336b (diff) | |
download | scintilla-mirror-master.tar.gz |
Feature [feature-requests:#1563]. Move main range in selection serialized form.master
Avoid processing characters multiple times by relying on from_chars munching
digit characters instead of searching for delimiters.
-rw-r--r-- | doc/ScintillaDoc.html | 3 | ||||
-rw-r--r-- | doc/ScintillaHistory.html | 4 | ||||
-rw-r--r-- | src/Selection.cxx | 56 | ||||
-rw-r--r-- | src/Selection.h | 4 | ||||
-rw-r--r-- | test/unit/testSelection.cxx | 28 |
5 files changed, 54 insertions, 41 deletions
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 2d0cd4679..5c92043cc 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -1444,6 +1444,9 @@ struct Sci_TextRangeFull { <b id="SCI_GETSELECTIONSERIALIZED">SCI_GETSELECTIONSERIALIZED(<unused>, char *selectionString) → 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>The format is currently<br/><code>[selType:R|L|T] [# mainRange ,] [anchor [v virtualSpace] [- caret [v virtualSpace]]] [, ...]</code> + <br/>Example of a multiple selection with virtual space: <code>#1,5v3-2,1</code> + </p> <p> <b id="SC_ELEMENT_SELECTION_ADDITIONAL_TEXT">SC_ELEMENT_SELECTION_ADDITIONAL_TEXT : colouralpha</b><br /> diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 0e04865d8..e8b55793b 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -602,6 +602,10 @@ Released 8 June 2025. </li> <li> + Change format for SCI_GETSELECTIONSERIALIZED. + <a href="https://sourceforge.net/p/scintilla/feature-requests/1563/">Feature #1563</a>. + </li> + <li> On Win32, force autocompletion list colours to be opaque. Enlarge bitmap to avoid visible blank background between items. <a href="https://sourceforge.net/p/scintilla/bugs/2482/">Bug #2482</a>. diff --git a/src/Selection.cxx b/src/Selection.cxx index 795570ee2..967033bff 100644 --- a/src/Selection.cxx +++ b/src/Selection.cxx @@ -29,23 +29,24 @@ namespace { // Generically convert a string to a integer value throwing if the conversion failed. // Failures include values that are out of range for the destination variable. template <typename T> -void ValueFromString(std::string_view sv, T &value) { +void ValueFromString(std::string_view &sv, T &value) { const std::from_chars_result res = std::from_chars(sv.data(), sv.data() + sv.size(), value); if (res.ec != std::errc{}) { if (res.ec == std::errc::result_out_of_range) throw std::runtime_error("from_chars out of range."); throw std::runtime_error("from_chars failed."); } + sv.remove_prefix(res.ptr - sv.data()); } } -SelectionPosition::SelectionPosition(std::string_view sv) : position(0) { - if (const size_t v = sv.find('v'); v != std::string_view::npos) { - ValueFromString(sv.substr(v + 1), virtualSpace); - sv = sv.substr(0, v); - } +SelectionPosition::SelectionPosition(std::string_view &sv) : position(0) { ValueFromString(sv, position); + if (!sv.empty() && sv.front() == 'v') { + sv.remove_prefix(1); + ValueFromString(sv, virtualSpace); + } } void SelectionPosition::MoveForInsertDelete(bool insertion, Sci::Position startChange, Sci::Position length, bool moveForEqual) noexcept { @@ -109,14 +110,13 @@ std::string SelectionPosition::ToString() const { return result; } -SelectionRange::SelectionRange(std::string_view sv) { - const size_t dash = sv.find('-'); - if (dash == std::string_view::npos) { - anchor = SelectionPosition(sv); +SelectionRange::SelectionRange(std::string_view &sv) { + anchor = SelectionPosition(sv); + if (sv.empty() || sv.front() != '-') { caret = anchor; } else { - anchor = SelectionPosition(sv.substr(0, dash)); - caret = SelectionPosition(sv.substr(dash + 1)); + sv.remove_prefix(1); + caret = SelectionPosition(sv); } } @@ -274,10 +274,13 @@ Selection::Selection(std::string_view sv) : mainRange(0), moveExtends(false), te sv.remove_prefix(1); } - // Non-zero main index at end after '#' - if (const size_t hash = sv.find('#'); hash != std::string_view::npos) { - ValueFromString(sv.substr(hash + 1), mainRange); - sv = sv.substr(0, hash); + // Non-zero main index at start after '#' + if (!sv.empty() && sv.front() == '#') { + sv.remove_prefix(1); + ValueFromString(sv, mainRange); + if (!sv.empty() && sv.front() == ',') { + sv.remove_prefix(1); + } } // Remainder is list of ranges @@ -288,13 +291,12 @@ Selection::Selection(std::string_view sv) : mainRange(0), moveExtends(false), te ranges.emplace_back(SelectionPosition(0)); } } else { - size_t comma = sv.find(','); - while (comma != std::string_view::npos) { - ranges.emplace_back(sv.substr(0, comma)); - sv.remove_prefix(comma + 1); - comma = sv.find(','); + while (!sv.empty()) { + if (sv.front() == ',') { + sv.remove_prefix(1); + } + ranges.emplace_back(sv); } - ranges.emplace_back(sv); if (mainRange >= ranges.size()) { mainRange = ranges.size() - 1; } @@ -595,6 +597,11 @@ std::string Selection::ToString() const { // No prefix. break; } + if (mainRange > 0) { + result += '#'; + result += std::to_string(mainRange); + result += ','; + } if (selType == SelTypes::rectangle || selType == SelTypes::thin) { result += rangeRectangular.ToString(); } else { @@ -606,10 +613,5 @@ std::string Selection::ToString() const { } } - if (mainRange > 0) { - result += '#'; - result += std::to_string(mainRange); - } - return result; } diff --git a/src/Selection.h b/src/Selection.h index 6779ee7ce..1a57d2e78 100644 --- a/src/Selection.h +++ b/src/Selection.h @@ -20,7 +20,7 @@ public: if (virtualSpace < 0) virtualSpace = 0; } - explicit SelectionPosition(std::string_view sv); + explicit SelectionPosition(std::string_view &sv); void Reset() noexcept { position = 0; virtualSpace = 0; @@ -121,7 +121,7 @@ struct SelectionRange { } constexpr SelectionRange(Sci::Position caret_, Sci::Position anchor_) noexcept : caret(caret_), anchor(anchor_) { } - explicit SelectionRange(std::string_view sv); + explicit SelectionRange(std::string_view &sv); SelectionSegment AsSegment() const noexcept { return {caret, anchor}; } diff --git a/test/unit/testSelection.cxx b/test/unit/testSelection.cxx index 609feaf00..ab0065624 100644 --- a/test/unit/testSelection.cxx +++ b/test/unit/testSelection.cxx @@ -115,18 +115,21 @@ TEST_CASE("SelectionPosition") { const std::string invalidString(invalid.ToString()); REQUIRE(invalidString == "-1"); - const SelectionPosition invalidReturned(invalidString); + std::string_view sv = invalidString; + const SelectionPosition invalidReturned(sv); REQUIRE(invalidReturned == invalid); const std::string zeroString(zero.ToString()); REQUIRE(zeroString == "0"); - const SelectionPosition zeroReturned(zeroString); + sv = zeroString; + const SelectionPosition zeroReturned(sv); REQUIRE(zeroReturned == zero); const SelectionPosition virtue(2, 3); const std::string virtueString(virtue.ToString()); REQUIRE(virtueString == "2v3"); - const SelectionPosition virtueReturned(virtueString); + sv = virtueString; + const SelectionPosition virtueReturned(sv); REQUIRE(virtueReturned == virtue); } @@ -156,9 +159,10 @@ TEST_CASE("SelectionRange") { // Range from 1 to 2 with 3 virtual spaces const SelectionRange range123(SelectionPosition(2, 3), SelectionPosition(1)); const std::string range123String(range123.ToString()); - // Opposite order to constructor: from anchor to caret + // Opposite order to constructor: from anchor to caret REQUIRE(range123String == "1-2v3"); - const SelectionRange range123Returned(range123String); + std::string_view sv = range123String; + const SelectionRange range123Returned(sv); REQUIRE(range123Returned == range123); } @@ -200,7 +204,7 @@ TEST_CASE("Selection") { SECTION("Selection") { Selection sel; - + REQUIRE(sel.selType == Selection::SelTypes::stream); REQUIRE(!sel.IsRectangular()); REQUIRE(sel.Count() == 1); @@ -220,9 +224,9 @@ TEST_CASE("Selection") { Selection selection; selection.SetSelection(range532); const std::string selectionString(selection.ToString()); - // Opposite order to constructor: from anchor to caret + // Opposite order to constructor: from anchor to caret REQUIRE(selectionString == "5v3-2"); - const SelectionRange selectionReturned(selectionString); + selection = Selection(selectionString); REQUIRE(selection.selType == Selection::SelTypes::stream); REQUIRE(!selection.IsRectangular()); @@ -246,8 +250,8 @@ TEST_CASE("Selection") { selection.AddSelection(range1); selection.SetMain(1); const std::string selectionString(selection.ToString()); - REQUIRE(selectionString == "5v3-2,1#1"); - const SelectionRange selectionReturned(selectionString); + REQUIRE(selectionString == "#1,5v3-2,1"); + selection = Selection(selectionString); REQUIRE(selection.selType == Selection::SelTypes::stream); REQUIRE(!selection.IsRectangular()); @@ -266,7 +270,7 @@ TEST_CASE("Selection") { // Range from 5 with 3 virtual spaces to 2 const SelectionRange range532(SelectionPosition(2), SelectionPosition(5, 3)); - + // Create a single-line rectangular selection Selection selection; selection.selType = Selection::SelTypes::rectangle; @@ -276,7 +280,7 @@ TEST_CASE("Selection") { const std::string selectionString(selection.ToString()); REQUIRE(selectionString == "R5v3-2"); - const Selection selectionReturned(selectionString); + selection = Selection(selectionString); REQUIRE(selection.selType == Selection::SelTypes::rectangle); REQUIRE(selection.IsRectangular()); |