diff options
-rw-r--r-- | cocoa/ScintillaCocoa.mm | 6 | ||||
-rw-r--r-- | doc/ScintillaDoc.html | 18 | ||||
-rw-r--r-- | doc/ScintillaHistory.html | 1 | ||||
-rwxr-xr-x | gtk/ScintillaGTK.cxx | 8 | ||||
-rw-r--r-- | include/Scintilla.h | 4 | ||||
-rw-r--r-- | include/Scintilla.iface | 12 | ||||
-rw-r--r-- | src/Editor.cxx | 92 | ||||
-rw-r--r-- | src/Editor.h | 3 | ||||
-rw-r--r-- | src/Selection.h | 3 | ||||
-rw-r--r-- | test/simpleTests.py | 20 | ||||
-rw-r--r-- | win32/ScintillaWin.cxx | 6 |
11 files changed, 121 insertions, 52 deletions
diff --git a/cocoa/ScintillaCocoa.mm b/cocoa/ScintillaCocoa.mm index bc6bb3698..e9284888f 100644 --- a/cocoa/ScintillaCocoa.mm +++ b/cocoa/ScintillaCocoa.mm @@ -1598,15 +1598,15 @@ bool ScintillaCocoa::GetPasteboardData(NSPasteboard *board, SelectionText *selec // Returns the target converted to UTF8. // Return the length in bytes. Sci::Position ScintillaCocoa::TargetAsUTF8(char *text) const { - const Sci::Position targetLength = targetEnd - targetStart; + const Sci::Position targetLength = targetRange.Length(); if (IsUnicodeMode()) { if (text) - pdoc->GetCharRange(text, targetStart, targetLength); + pdoc->GetCharRange(text, targetRange.start.Position(), targetLength); } else { // Need to convert const CFStringEncoding encoding = EncodingFromCharacterSet(IsUnicodeMode(), vs.styles[STYLE_DEFAULT].characterSet); - const std::string s = RangeText(targetStart, targetEnd); + const std::string s = RangeText(targetRange.start.Position(), targetRange.end.Position()); CFStringRef cfsVal = CFStringFromString(s.c_str(), s.length(), encoding); if (!cfsVal) { return 0; diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html index 9fa7f94c1..d77536e5b 100644 --- a/doc/ScintillaDoc.html +++ b/doc/ScintillaDoc.html @@ -711,10 +711,15 @@ struct Sci_TextRange { <code>SCI_SEARCHINTARGET</code> such as <code>SCFIND_MATCHCASE</code>, <code>SCFIND_WHOLEWORD</code>, <code>SCFIND_WORDSTART</code>, and <code>SCFIND_REGEXP</code> can be set with <code>SCI_SETSEARCHFLAGS</code>.</p> - <code><a class="message" href="#SCI_SETTARGETSTART">SCI_SETTARGETSTART(position start)</a><br /> + <code> + <a class="message" href="#SCI_SETTARGETSTART">SCI_SETTARGETSTART(position start)</a><br /> <a class="message" href="#SCI_GETTARGETSTART">SCI_GETTARGETSTART → position</a><br /> + <a class="message" href="#SCI_SETTARGETSTARTVIRTUALSPACE">SCI_SETTARGETSTARTVIRTUALSPACE(position space)</a><br /> + <a class="message" href="#SCI_GETTARGETSTARTVIRTUALSPACE">SCI_GETTARGETSTARTVIRTUALSPACE → position</a><br /> <a class="message" href="#SCI_SETTARGETEND">SCI_SETTARGETEND(position end)</a><br /> <a class="message" href="#SCI_GETTARGETEND">SCI_GETTARGETEND → position</a><br /> + <a class="message" href="#SCI_SETTARGETENDVIRTUALSPACE">SCI_SETTARGETENDVIRTUALSPACE(position space)</a><br /> + <a class="message" href="#SCI_GETTARGETENDVIRTUALSPACE">SCI_GETTARGETENDVIRTUALSPACE → position</a><br /> <a class="message" href="#SCI_SETTARGETRANGE">SCI_SETTARGETRANGE(position start, position end)</a><br /> <a class="message" href="#SCI_TARGETFROMSELECTION">SCI_TARGETFROMSELECTION</a><br /> <a class="message" href="#SCI_TARGETWHOLEDOCUMENT">SCI_TARGETWHOLEDOCUMENT</a><br /> @@ -729,13 +734,22 @@ struct Sci_TextRange { <p><b id="SCI_SETTARGETSTART">SCI_SETTARGETSTART(position start)</b><br /> <b id="SCI_GETTARGETSTART">SCI_GETTARGETSTART → position</b><br /> + <b id="SCI_SETTARGETSTARTVIRTUALSPACE">SCI_SETTARGETSTARTVIRTUALSPACE(position space)</b><br /> + <b id="SCI_GETTARGETSTARTVIRTUALSPACE">SCI_GETTARGETSTARTVIRTUALSPACE → position</b><br /> <b id="SCI_SETTARGETEND">SCI_SETTARGETEND(position end)</b><br /> <b id="SCI_GETTARGETEND">SCI_GETTARGETEND → position</b><br /> + <b id="SCI_SETTARGETENDVIRTUALSPACE">SCI_SETTARGETENDVIRTUALSPACE(position space)</b><br /> + <b id="SCI_GETTARGETENDVIRTUALSPACE">SCI_GETTARGETENDVIRTUALSPACE → position</b><br /> <b id="SCI_SETTARGETRANGE">SCI_SETTARGETRANGE(position start, position end)</b><br /> These functions set and return the start and end of the target. When searching you can set start greater than end to find the last matching text in the - target rather than the first matching text. The target is also set by a successful + target rather than the first matching text. + Setting a target position with <code>SCI_SETTARGETSTART</code>, <code>SCI_SETTARGETEND</code>, or <code>SCI_SETTARGETRANGE</code> + sets the virtual space to 0. + The target is also set by a successful <code>SCI_SEARCHINTARGET</code>.</p> + <p>The virtual space of the target range can be set and retrieved with the corresponding <code>...VIRTUALSPACE</code> + methods. This allows text to be inserted in virtual space more easily.</p> <p><b id="SCI_TARGETFROMSELECTION">SCI_TARGETFROMSELECTION</b><br /> Set the target start and end to the start and end positions of the selection.</p> diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 42bbd68f3..a5c815628 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -567,6 +567,7 @@ Released 24 October 2019. </li> <li> + Allow target to have virtual space. Add methods for finding the virtual space at start and end of multiple selections. <a href="https://sourceforge.net/p/scintilla/feature-requests/1316/">Feature #1316</a>. </li> diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx index 9162010c4..03213c500 100755 --- a/gtk/ScintillaGTK.cxx +++ b/gtk/ScintillaGTK.cxx @@ -757,16 +757,16 @@ std::string ConvertText(const char *s, size_t len, const char *charSetDest, // Returns the target converted to UTF8. // Return the length in bytes. Sci::Position ScintillaGTK::TargetAsUTF8(char *text) const { - const Sci::Position targetLength = targetEnd - targetStart; + const Sci::Position targetLength = targetRange.Length(); if (IsUnicodeMode()) { if (text) { - pdoc->GetCharRange(text, targetStart, targetLength); + pdoc->GetCharRange(text, targetRange.start.Position(), targetLength); } } else { // Need to convert const char *charSetBuffer = CharacterSetID(); if (*charSetBuffer) { - std::string s = RangeText(targetStart, targetEnd); + std::string s = RangeText(targetRange.start.Position(), targetRange.end.Position()); std::string tmputf = ConvertText(&s[0], targetLength, "UTF-8", charSetBuffer, false); if (text) { memcpy(text, tmputf.c_str(), tmputf.length()); @@ -774,7 +774,7 @@ Sci::Position ScintillaGTK::TargetAsUTF8(char *text) const { return tmputf.length(); } else { if (text) { - pdoc->GetCharRange(text, targetStart, targetLength); + pdoc->GetCharRange(text, targetRange.start.Position(), targetLength); } } } diff --git a/include/Scintilla.h b/include/Scintilla.h index 59ab2ff7a..b5fc17eb6 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -451,8 +451,12 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam, #define SCI_GETCARETWIDTH 2189 #define SCI_SETTARGETSTART 2190 #define SCI_GETTARGETSTART 2191 +#define SCI_SETTARGETSTARTVIRTUALSPACE 2728 +#define SCI_GETTARGETSTARTVIRTUALSPACE 2729 #define SCI_SETTARGETEND 2192 #define SCI_GETTARGETEND 2193 +#define SCI_SETTARGETENDVIRTUALSPACE 2730 +#define SCI_GETTARGETENDVIRTUALSPACE 2731 #define SCI_SETTARGETRANGE 2686 #define SCI_GETTARGETTEXT 2687 #define SCI_TARGETFROMSELECTION 2287 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index 9fa952f95..dde113847 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -1208,6 +1208,12 @@ set void SetTargetStart=2190(position start,) # Get the position that starts the target. get position GetTargetStart=2191(,) +# Sets the virtual space of the target start +set void SetTargetStartVirtualSpace=2728(position space,) + +# Get the virtual space of the target start +get position GetTargetStartVirtualSpace=2729(,) + # Sets the position that ends the target which is used for updating the # document without affecting the scroll position. set void SetTargetEnd=2192(position end,) @@ -1215,6 +1221,12 @@ set void SetTargetEnd=2192(position end,) # Get the position that ends the target. get position GetTargetEnd=2193(,) +# Sets the virtual space of the target end +set void SetTargetEndVirtualSpace=2730(position space,) + +# Get the virtual space of the target end +get position GetTargetEndVirtualSpace=2731(,) + # Sets both the start and end of the target in one call. fun void SetTargetRange=2686(position start, position end) diff --git a/src/Editor.cxx b/src/Editor.cxx index 826824cbd..016ef3383 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -167,8 +167,7 @@ Editor::Editor() : durationWrapOneLine(0.00001, 0.000001, 0.0001) { multiPasteMode = SC_MULTIPASTE_ONCE; virtualSpaceOptions = SCVS_NONE; - targetStart = 0; - targetEnd = 0; + targetRange = SelectionSegment(); searchFlags = 0; topLine = 0; @@ -755,7 +754,7 @@ void Editor::MultipleSelectAdd(AddNumber addNumber) { const Range rangeMainSelection(sel.RangeMain().Start().Position(), sel.RangeMain().End().Position()); const std::string selectedText = RangeText(rangeMainSelection.start, rangeMainSelection.end); - const Range rangeTarget(targetStart, targetEnd); + const Range rangeTarget(targetRange.start.Position(), targetRange.end.Position()); std::vector<Range> searchRanges; // Search should be over the target range excluding the current selection so // may need to search 2 ranges, after the selection then before the selection. @@ -1601,17 +1600,17 @@ bool Editor::WrapLines(WrapScope ws) { } void Editor::LinesJoin() { - if (!RangeContainsProtected(targetStart, targetEnd)) { + if (!RangeContainsProtected(targetRange.start.Position(), targetRange.end.Position())) { UndoGroup ug(pdoc); bool prevNonWS = true; - for (Sci::Position pos = targetStart; pos < targetEnd; pos++) { + for (Sci::Position pos = targetRange.start.Position(); pos < targetRange.end.Position(); pos++) { if (pdoc->IsPositionInLineEnd(pos)) { - targetEnd -= pdoc->LenChar(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); - targetEnd += lengthInserted; + targetRange.end.Add(lengthInserted); } } else { prevNonWS = pdoc->CharAt(pos) != ' '; @@ -1631,13 +1630,13 @@ const char *Editor::StringFromEOLMode(int eolMode) noexcept { } void Editor::LinesSplit(int pixelWidth) { - if (!RangeContainsProtected(targetStart, targetEnd)) { + if (!RangeContainsProtected(targetRange.start.Position(), targetRange.end.Position())) { if (pixelWidth == 0) { const PRectangle rcText = GetTextRectangle(); pixelWidth = static_cast<int>(rcText.Width()); } - const Sci::Line lineStart = pdoc->SciLineFromPosition(targetStart); - Sci::Line lineEnd = pdoc->SciLineFromPosition(targetEnd); + const Sci::Line lineStart = pdoc->SciLineFromPosition(targetRange.start.Position()); + Sci::Line lineEnd = pdoc->SciLineFromPosition(targetRange.end.Position()); const char *eol = StringFromEOLMode(pdoc->eolMode); UndoGroup ug(pdoc); for (Sci::Line line = lineStart; line <= lineEnd; line++) { @@ -1651,11 +1650,11 @@ void Editor::LinesSplit(int pixelWidth) { const Sci::Position lengthInserted = pdoc->InsertString( posLineStart + lengthInsertedTotal + ll->LineStart(subLine), eol, strlen(eol)); - targetEnd += lengthInserted; + targetRange.end.Add(lengthInserted); lengthInsertedTotal += lengthInserted; } } - lineEnd = pdoc->SciLineFromPosition(targetEnd); + lineEnd = pdoc->SciLineFromPosition(targetRange.end.Position()); } } } @@ -4156,12 +4155,12 @@ Sci::Position Editor::SearchInTarget(const char *text, Sci::Position length) { if (!pdoc->HasCaseFolder()) pdoc->SetCaseFolder(CaseFolderForEncoding()); try { - const Sci::Position pos = pdoc->FindText(targetStart, targetEnd, text, + const Sci::Position pos = pdoc->FindText(targetRange.start.Position(), targetRange.end.Position(), text, searchFlags, &lengthFound); if (pos != -1) { - targetStart = pos; - targetEnd = pos + lengthFound; + targetRange.start.SetPosition(pos); + targetRange.end.SetPosition(pos + lengthFound); } return pos; } catch (RegexError &) { @@ -5249,8 +5248,7 @@ void Editor::SetDocPointer(Document *document) { // Ensure all positions within document sel.Clear(); - targetStart = 0; - targetEnd = 0; + targetRange = SelectionSegment(); braces[0] = Sci::invalidPosition; braces[1] = Sci::invalidPosition; @@ -5585,11 +5583,20 @@ Sci::Position Editor::ReplaceTarget(bool replacePatterns, const char *text, Sci: return 0; } } - if (targetStart != targetEnd) - pdoc->DeleteChars(targetStart, targetEnd - targetStart); - targetEnd = targetStart; - const Sci::Position lengthInserted = pdoc->InsertString(targetStart, text, length); - targetEnd = targetStart + lengthInserted; + + // Remove the text inside the range + if (targetRange.Length() > 0) + pdoc->DeleteChars(targetRange.start.Position(), targetRange.Length()); + targetRange.end = targetRange.start; + + // Realize virtual space of target start + Sci::Position startAfterSpaceInsertion = RealizeVirtualSpace(targetRange.start.Position(), targetRange.start.VirtualSpace()); + targetRange.start.SetPosition(startAfterSpaceInsertion); + targetRange.end = targetRange.start; + + // Insert the new text + const Sci::Position lengthInserted = pdoc->InsertString(targetRange.start.Position(), text, length); + targetRange.end.SetPosition(targetRange.start.Position() + lengthInserted); return length; } @@ -5982,41 +5989,50 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { break; case SCI_SETTARGETSTART: - targetStart = static_cast<Sci::Position>(wParam); + targetRange.start.SetPosition(static_cast<Sci::Position>(wParam)); break; case SCI_GETTARGETSTART: - return targetStart; + return targetRange.start.Position(); + + case SCI_SETTARGETSTARTVIRTUALSPACE: + targetRange.start.SetVirtualSpace(static_cast<Sci::Position>(wParam)); + break; + + case SCI_GETTARGETSTARTVIRTUALSPACE: + return targetRange.start.VirtualSpace(); case SCI_SETTARGETEND: - targetEnd = static_cast<Sci::Position>(wParam); + targetRange.end.SetPosition(static_cast<Sci::Position>(wParam)); break; case SCI_GETTARGETEND: - return targetEnd; + return targetRange.end.Position(); + + case SCI_SETTARGETENDVIRTUALSPACE: + targetRange.end.SetVirtualSpace(static_cast<Sci::Position>(wParam)); + break; + + case SCI_GETTARGETENDVIRTUALSPACE: + return targetRange.end.VirtualSpace(); case SCI_SETTARGETRANGE: - targetStart = static_cast<Sci::Position>(wParam); - targetEnd = lParam; + targetRange.start.SetPosition(static_cast<Sci::Position>(wParam)); + targetRange.end.SetPosition(lParam); break; case SCI_TARGETWHOLEDOCUMENT: - targetStart = 0; - targetEnd = pdoc->Length(); + targetRange.start.SetPosition(0); + targetRange.end.SetPosition(pdoc->Length()); break; case SCI_TARGETFROMSELECTION: - if (sel.MainCaret() < sel.MainAnchor()) { - targetStart = sel.MainCaret(); - targetEnd = sel.MainAnchor(); - } else { - targetStart = sel.MainAnchor(); - targetEnd = sel.MainCaret(); - } + targetRange.start = sel.RangeMain().Start(); + targetRange.end = sel.RangeMain().End(); break; case SCI_GETTARGETTEXT: { - std::string text = RangeText(targetStart, targetEnd); + std::string text = RangeText(targetRange.start.Position(), targetRange.end.Position()); return BytesResult(lParam, reinterpret_cast<const unsigned char *>(text.c_str()), text.length()); } diff --git a/src/Editor.h b/src/Editor.h index 13e201169..69f8ef4ca 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -210,8 +210,7 @@ protected: // ScintillaBase subclass needs access to much of Editor Sci::Position wordSelectAnchorStartPos; Sci::Position wordSelectAnchorEndPos; Sci::Position wordSelectInitialCaretPos; - Sci::Position targetStart; - Sci::Position targetEnd; + SelectionSegment targetRange; int searchFlags; Sci::Line topLine; Sci::Position posTopLine; diff --git a/src/Selection.h b/src/Selection.h index d078c043e..11a6f097a 100644 --- a/src/Selection.h +++ b/src/Selection.h @@ -72,6 +72,9 @@ struct SelectionSegment { bool Empty() const noexcept { return start == end; } + Sci::Position Length() const noexcept { + return end.Position() - start.Position(); + } void Extend(SelectionPosition p) noexcept { if (start > p) start = p; diff --git a/test/simpleTests.py b/test/simpleTests.py index a4730980f..a68668f74 100644 --- a/test/simpleTests.py +++ b/test/simpleTests.py @@ -609,6 +609,26 @@ class TestSimple(unittest.TestCase): self.ed.ReplaceTargetRE(len(rep), rep) self.assertEquals(self.ed.Contents(), b"a\\nd") + def testTargetVirtualSpace(self): + self.ed.SetContents(b"a\nbcd") + self.assertEquals(self.ed.TargetStart, 0) + self.assertEquals(self.ed.TargetStartVirtualSpace, 0) + self.assertEquals(self.ed.TargetEnd, 5) + self.assertEquals(self.ed.TargetEndVirtualSpace, 0) + self.ed.TargetStart = 1 + self.ed.TargetStartVirtualSpace = 2 + self.ed.TargetEnd = 3 + self.ed.TargetEndVirtualSpace = 4 + # Adds 2 spaces to first line due to virtual space, and replace 2 characters with 3 + rep = b"12\n" + self.ed.ReplaceTarget(len(rep), rep) + self.assertEquals(self.ed.Contents(), b"a 12\ncd") + # 1+2v realized to 3 + self.assertEquals(self.ed.TargetStart, 3) + self.assertEquals(self.ed.TargetStartVirtualSpace, 0) + self.assertEquals(self.ed.TargetEnd, 6) + self.assertEquals(self.ed.TargetEndVirtualSpace, 0) + def testPointsAndPositions(self): self.ed.AddText(1, b"x") # Start of text diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index ff20740f8..b5ff31bae 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -791,14 +791,14 @@ std::wstring StringMapCase(std::wstring_view wsv, DWORD mapFlags) { // Returns the target converted to UTF8. // Return the length in bytes. Sci::Position ScintillaWin::TargetAsUTF8(char *text) const { - const Sci::Position targetLength = targetEnd - targetStart; + const Sci::Position targetLength = targetRange.Length(); if (IsUnicodeMode()) { if (text) { - pdoc->GetCharRange(text, targetStart, targetLength); + pdoc->GetCharRange(text, targetRange.start.Position(), targetLength); } } else { // Need to convert - const std::string s = RangeText(targetStart, targetEnd); + const std::string s = RangeText(targetRange.start.Position(), targetRange.end.Position()); const std::wstring characters = StringDecode(s, CodePageOfDocument()); const int utf8Len = MultiByteLenFromWideChar(CP_UTF8, characters); if (text) { |