From c232fb50fc2cb0f30e3440bc61dbe7c5efacef35 Mon Sep 17 00:00:00 2001
From: Neil
Date: Thu, 11 Jun 2015 21:58:21 +1000
Subject: Added MultipleSelectAddNext, MultipleSelectAddEach, IsRangeWord, and
TargetWholeDocument.
---
doc/ScintillaDoc.html | 19 +++++++++++-
doc/ScintillaHistory.html | 12 ++++++++
include/Scintilla.h | 6 +++-
include/Scintilla.iface | 20 +++++++++++--
src/Document.cxx | 2 +-
src/Document.h | 8 ++---
src/Editor.cxx | 75 +++++++++++++++++++++++++++++++++++++++++++++++
src/Editor.h | 2 ++
test/simpleTests.py | 54 ++++++++++++++++++++++++++++++++++
9 files changed, 188 insertions(+), 10 deletions(-)
diff --git a/doc/ScintillaDoc.html b/doc/ScintillaDoc.html
index 6e4210bc9..3e40adab2 100644
--- a/doc/ScintillaDoc.html
+++ b/doc/ScintillaDoc.html
@@ -641,6 +641,7 @@ struct Sci_TextRange {
SCI_GETTARGETEND
SCI_SETTARGETRANGE(int start, int end)
SCI_TARGETFROMSELECTION
+ SCI_TARGETWHOLEDOCUMENT
SCI_SETSEARCHFLAGS(int searchFlags)
SCI_GETSEARCHFLAGS
SCI_SEARCHINTARGET(int length, const char
@@ -667,6 +668,9 @@ struct Sci_TextRange {
SCI_TARGETFROMSELECTION
Set the target start and end to the start and end positions of the selection.
+ SCI_TARGETWHOLEDOCUMENT
+ Set the target start to the start of the document and target end to the end of the document.
+
SCI_SETSEARCHFLAGS(int searchFlags)
SCI_GETSEARCHFLAGS
These get and set the searchFlags used by
@@ -1175,6 +1179,7 @@ struct Sci_TextToFind {
onlyWordCharacters)
SCI_WORDSTARTPOSITION(int position, bool
onlyWordCharacters)
+ SCI_ISRANGEWORD(int start, int end)
SCI_POSITIONBEFORE(int position)
SCI_POSITIONAFTER(int position)
SCI_POSITIONRELATIVE(int position, int relative)
@@ -1399,6 +1404,12 @@ struct Sci_TextToFind {
sets the start or the search, which is forwards when searching for the end and backwards when
searching for the start.
+ SCI_ISRANGEWORD(int start, int end)
+ Is the range start..end a word or set of words? This message checks that start is at a word start transition and that
+ end is at a word end transition. It does not check whether there are any spaces inside the range.
+
+ SCI_ISRANGEWORD(int start, int end)
+
Set onlyWordCharacters to true (1) to stop searching at the first
non-word character in the search direction. If onlyWordCharacters is
false (0), the first character in the search direction sets the type of the search
@@ -1624,6 +1635,7 @@ struct Sci_TextToFind {
SCI_SWAPMAINANCHORCARET
SCI_ROTATESELECTION
+ SCI_MULTIPLESELECTADDNEXT
@@ -1789,9 +1801,14 @@ struct Sci_TextToFind {
SCI_SWAPMAINANCHORCARET
SCI_ROTATESELECTION
+ SCI_MULTIPLESELECTADDNEXT
These commands may be assigned to keys to make it possible to manipulate multiple selections.
SCI_SWAPMAINANCHORCARET moves the caret to the opposite end of the main selection.
- SCI_ROTATESELECTION makes the next selection be the main selection.
+ SCI_ROTATESELECTION makes the next selection be the main selection.
+ SCI_MULTIPLESELECTADDNEXT adds the next occurrence of the main selection to
+ the set of selections as main. If the current selection is empty then select word around caret.
+ The current searchFlags
+ are used so the application may choose case sensitivity and word search options.
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html
index 67a5927da..9ffcaaacc 100644
--- a/doc/ScintillaHistory.html
+++ b/doc/ScintillaHistory.html
@@ -491,6 +491,18 @@
Released 26 May 2015.
+ Added SCI_MULTIPLESELECTADDNEXT to add the next occurrence of the main selection within the
+ target to the set of selections as main. If the current selection is empty then select word around caret.
+ SCI_MULTIPLESELECTADDNEXT adds each occurrence of the main selection within the
+ target to the set of selections.
+
+
+ Added SCI_ISRANGEWORD to determine if the parameters are at the start and end of a word.
+
+
+ Added SCI_TARGETWHOLEDOCUMENT to set the target to the whole document.
+
+
Verilog lexer recognises protected regions and the folder folds protected regions.
diff --git a/include/Scintilla.h b/include/Scintilla.h
index 22d36d34d..50deb755e 100644
--- a/include/Scintilla.h
+++ b/include/Scintilla.h
@@ -434,6 +434,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_GETTARGETEND 2193
#define SCI_SETTARGETRANGE 2686
#define SCI_GETTARGETTEXT 2687
+#define SCI_TARGETFROMSELECTION 2287
+#define SCI_TARGETWHOLEDOCUMENT 2690
#define SCI_REPLACETARGET 2194
#define SCI_REPLACETARGETRE 2195
#define SCI_SEARCHINTARGET 2197
@@ -498,6 +500,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_GETMOUSEDWELLTIME 2265
#define SCI_WORDSTARTPOSITION 2266
#define SCI_WORDENDPOSITION 2267
+#define SCI_ISRANGEWORD 2691
#define SC_WRAP_NONE 0
#define SC_WRAP_WORD 1
#define SC_WRAP_CHAR 2
@@ -559,7 +562,6 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_SETMULTIPASTE 2614
#define SCI_GETMULTIPASTE 2615
#define SCI_GETTAG 2616
-#define SCI_TARGETFROMSELECTION 2287
#define SCI_LINESJOIN 2288
#define SCI_LINESSPLIT 2289
#define SCI_SETFOLDMARGINCOLOUR 2290
@@ -894,6 +896,8 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,
#define SCI_GETADDITIONALCARETFORE 2605
#define SCI_ROTATESELECTION 2606
#define SCI_SWAPMAINANCHORCARET 2607
+#define SCI_MULTIPLESELECTADDNEXT 2688
+#define SCI_MULTIPLESELECTADDEACH 2689
#define SCI_CHANGELEXERSTATE 2617
#define SCI_CONTRACTEDFOLDNEXT 2618
#define SCI_VERTICALCENTRECARET 2619
diff --git a/include/Scintilla.iface b/include/Scintilla.iface
index 8cd651540..9a084785a 100644
--- a/include/Scintilla.iface
+++ b/include/Scintilla.iface
@@ -1069,6 +1069,12 @@ fun void SetTargetRange=2686(position start, position end)
# Retrieve the text in the target.
get int GetTargetText=2687(, stringresult characters)
+# Make the target range start and end be the same as the selection range start and end.
+fun void TargetFromSelection=2287(,)
+
+# Sets the target to the whole document.
+fun void TargetWholeDocument=2690(,)
+
# Replace the target text with the argument text.
# Text is counted so it can contain NULs.
# Returns the length of the replacement text.
@@ -1248,6 +1254,9 @@ fun int WordStartPosition=2266(position pos, bool onlyWordCharacters)
# Get position of end of word.
fun int WordEndPosition=2267(position pos, bool onlyWordCharacters)
+# Is the range start..end considered a word?
+fun bool IsRangeWord=2691(position start, position end)
+
enu Wrap=SC_WRAP_
val SC_WRAP_NONE=0
val SC_WRAP_WORD=1
@@ -1403,9 +1412,6 @@ get int GetMultiPaste=2615(,)
# Result is NUL-terminated.
get int GetTag=2616(int tagNumber, stringresult tagValue)
-# Make the target range start and end be the same as the selection range start and end.
-fun void TargetFromSelection=2287(,)
-
# Join the lines in the target.
fun void LinesJoin=2288(,)
@@ -2350,6 +2356,14 @@ fun void RotateSelection=2606(,)
# Swap that caret and anchor of the main selection.
fun void SwapMainAnchorCaret=2607(,)
+# Add the next occurrence of the main selection to the set of selections as main.
+# If the current selection is empty then select word around caret.
+fun void MultipleSelectAddNext=2688(,)
+
+# Add each occurrence of the main selection in the target to the set of selections.
+# If the current selection is empty then select word around caret.
+fun void MultipleSelectAddEach=2689(,)
+
# Indicate that the internal state of a lexer has changed over a range and therefore
# there may be a need to redraw.
fun int ChangeLexerState=2617(position start, position end)
diff --git a/src/Document.cxx b/src/Document.cxx
index 3065b1828..2eb412f73 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -1603,7 +1603,7 @@ bool Document::IsWordEndAt(int pos) const {
* ends and where the characters on the inside are word or punctuation characters.
*/
bool Document::IsWordAt(int start, int end) const {
- return IsWordStartAt(start) && IsWordEndAt(end);
+ return (start < end) && IsWordStartAt(start) && IsWordEndAt(end);
}
bool Document::MatchesWordOptions(bool word, bool wordStart, int pos, int length) const {
diff --git a/src/Document.h b/src/Document.h
index 923462e7a..308a67062 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -381,6 +381,10 @@ public:
};
CharacterExtracted ExtractCharacter(int position) const;
+ bool IsWordStartAt(int pos) const;
+ bool IsWordEndAt(int pos) const;
+ bool IsWordAt(int start, int end) const;
+
bool MatchesWordOptions(bool word, bool wordStart, int pos, int length) const;
bool HasCaseFolder(void) const;
void SetCaseFolder(CaseFolder *pcf_);
@@ -437,10 +441,6 @@ public:
int BraceMatch(int position, int maxReStyle);
private:
- bool IsWordStartAt(int pos) const;
- bool IsWordEndAt(int pos) const;
- bool IsWordAt(int start, int end) const;
-
void NotifyModifyAttempt();
void NotifySavePoint(bool atSavePoint);
void NotifyModified(DocModification mh);
diff --git a/src/Editor.cxx b/src/Editor.cxx
index ce465808c..beb270219 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -692,6 +692,59 @@ void Editor::SetEmptySelection(int currentPos_) {
SetEmptySelection(SelectionPosition(currentPos_));
}
+void Editor::MultipleSelectAdd(AddNumber addNumber) {
+ if (SelectionEmpty() || !multipleSelection) {
+ // Select word at caret
+ const int startWord = pdoc->ExtendWordSelect(sel.MainCaret(), -1, true);
+ const int endWord = pdoc->ExtendWordSelect(startWord, 1, true);
+ TrimAndSetSelection(endWord, startWord);
+
+ } else {
+
+ if (!pdoc->HasCaseFolder())
+ pdoc->SetCaseFolder(CaseFolderForEncoding());
+
+ 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);
+ std::vector 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.
+ if (rangeTarget.Overlaps(rangeMainSelection)) {
+ // Common case is that the selection is completely within the target but
+ // may also have overlap at start or end.
+ if (rangeMainSelection.end < rangeTarget.end)
+ searchRanges.push_back(Range(rangeMainSelection.end, rangeTarget.end));
+ if (rangeTarget.start < rangeMainSelection.start)
+ searchRanges.push_back(Range(rangeTarget.start, rangeMainSelection.start));
+ } else {
+ // No overlap
+ searchRanges.push_back(rangeTarget);
+ }
+
+ for (std::vector::const_iterator it = searchRanges.begin(); it != searchRanges.end(); ++it) {
+ int searchStart = it->start;
+ const int searchEnd = it->end;
+ for (;;) {
+ int lengthFound = selectedText.length();
+ int pos = pdoc->FindText(searchStart, searchEnd, selectedText.c_str(),
+ searchFlags, &lengthFound);
+ if (pos >= 0) {
+ sel.AddSelection(SelectionRange(pos + lengthFound, pos));
+ ScrollRange(sel.RangeMain());
+ Redraw();
+ if (addNumber == addOne)
+ return;
+ searchStart = pos + lengthFound;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+}
+
bool Editor::RangeContainsProtected(int start, int end) const {
if (vs.ProtectionActive()) {
if (start > end) {
@@ -2895,6 +2948,12 @@ void Editor::Duplicate(bool forLine) {
void Editor::CancelModes() {
sel.SetMoveExtends(false);
+ if (sel.Count() > 1) {
+ // Drop additional selections
+ const SelectionRange rangeOnly = sel.RangeMain();
+ InvalidateSelection(rangeOnly, true);
+ sel.SetSelection(rangeOnly);
+ }
}
void Editor::NewLine() {
@@ -5532,6 +5591,11 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
targetEnd = static_cast(lParam);
break;
+ case SCI_TARGETWHOLEDOCUMENT:
+ targetStart = 0;
+ targetEnd = pdoc->Length();
+ break;
+
case SCI_TARGETFROMSELECTION:
if (sel.MainCaret() < sel.MainAnchor()) {
targetStart = sel.MainCaret();
@@ -6113,6 +6177,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_WORDENDPOSITION:
return pdoc->ExtendWordSelect(static_cast(wParam), 1, lParam != 0);
+ case SCI_ISRANGEWORD:
+ return pdoc->IsWordAt(static_cast(wParam), lParam);
+
case SCI_SETWRAPMODE:
if (vs.SetWrapState(static_cast(wParam))) {
xOffset = 0;
@@ -7636,6 +7703,14 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
sel.RangeMain() = SelectionRange(sel.RangeMain().anchor, sel.RangeMain().caret);
break;
+ case SCI_MULTIPLESELECTADDNEXT:
+ MultipleSelectAdd(addOne);
+ break;
+
+ case SCI_MULTIPLESELECTADDEACH:
+ MultipleSelectAdd(addEach);
+ break;
+
case SCI_CHANGELEXERSTATE:
pdoc->ChangeLexerState(static_cast(wParam), static_cast(lParam));
break;
diff --git a/src/Editor.h b/src/Editor.h
index 2bf8336fa..b08fc7159 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -319,6 +319,8 @@ protected: // ScintillaBase subclass needs access to much of Editor
void SetSelection(int currentPos_);
void SetEmptySelection(SelectionPosition currentPos_);
void SetEmptySelection(int currentPos_);
+ enum AddNumber { addOne, addEach };
+ void MultipleSelectAdd(AddNumber addNumber);
bool RangeContainsProtected(int start, int end) const;
bool SelectionContainsProtected();
int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const;
diff --git a/test/simpleTests.py b/test/simpleTests.py
index 4e8462c71..9b7525066 100644
--- a/test/simpleTests.py
+++ b/test/simpleTests.py
@@ -576,6 +576,14 @@ class TestSimple(unittest.TestCase):
self.assertEquals(self.ed.TargetStart, 4)
self.assertEquals(self.ed.TargetEnd, 5)
+ def testTargetWhole(self):
+ self.ed.SetContents(b"abcd")
+ self.ed.TargetStart = 1
+ self.ed.TargetEnd = 3
+ self.ed.TargetWholeDocument()
+ self.assertEquals(self.ed.TargetStart, 0)
+ self.assertEquals(self.ed.TargetEnd, 4)
+
def testTargetEscape(self):
# Checks that a literal \ can be in the replacement. Bug #2959876
self.ed.SetContents(b"abcd")
@@ -619,6 +627,18 @@ class TestSimple(unittest.TestCase):
self.assertEquals(self.ed.WordEndPosition(5, 0), 6)
self.assertEquals(self.ed.WordEndPosition(6, 0), 8)
+ def testWordRange(self):
+ text = b"ab cd\t++"
+ self.ed.AddText(len(text), text)
+ self.assertEquals(self.ed.IsRangeWord(0, 0), 0)
+ self.assertEquals(self.ed.IsRangeWord(0, 1), 0)
+ self.assertEquals(self.ed.IsRangeWord(0, 2), 1)
+ self.assertEquals(self.ed.IsRangeWord(0, 3), 0)
+ self.assertEquals(self.ed.IsRangeWord(0, 4), 0)
+ self.assertEquals(self.ed.IsRangeWord(0, 5), 1)
+ self.assertEquals(self.ed.IsRangeWord(6, 7), 0)
+ self.assertEquals(self.ed.IsRangeWord(6, 8), 1)
+
MODI = 1
UNDO = 2
REDO = 4
@@ -1107,6 +1127,40 @@ class TestSearch(unittest.TestCase):
self.assertEquals(-1, self.ed.FindBytes(0, self.ed.Length, b"\\xAB", flags))
self.assertEquals(0, self.ed.FindBytes(0, self.ed.Length, b"\\xAD", flags))
+ def testMultipleAddSelection(self):
+ # Find both 'a'
+ self.assertEquals(self.ed.MultipleSelection, 0)
+ self.ed.MultipleSelection = 1
+ self.assertEquals(self.ed.MultipleSelection, 1)
+ self.ed.TargetWholeDocument()
+ self.ed.SearchFlags = 0
+ self.ed.SetSelection(1, 0)
+ self.assertEquals(self.ed.Selections, 1)
+ self.ed.MultipleSelectAddNext()
+ self.assertEquals(self.ed.Selections, 2)
+ self.assertEquals(self.ed.GetSelectionNAnchor(0), 0)
+ self.assertEquals(self.ed.GetSelectionNCaret(0), 1)
+ self.assertEquals(self.ed.GetSelectionNAnchor(1), 8)
+ self.assertEquals(self.ed.GetSelectionNCaret(1), 9)
+ self.ed.MultipleSelection = 0
+
+ def testMultipleAddEachSelection(self):
+ # Find each 'b'
+ self.assertEquals(self.ed.MultipleSelection, 0)
+ self.ed.MultipleSelection = 1
+ self.assertEquals(self.ed.MultipleSelection, 1)
+ self.ed.TargetWholeDocument()
+ self.ed.SearchFlags = 0
+ self.ed.SetSelection(3, 2)
+ self.assertEquals(self.ed.Selections, 1)
+ self.ed.MultipleSelectAddEach()
+ self.assertEquals(self.ed.Selections, 2)
+ self.assertEquals(self.ed.GetSelectionNAnchor(0), 2)
+ self.assertEquals(self.ed.GetSelectionNCaret(0), 3)
+ self.assertEquals(self.ed.GetSelectionNAnchor(1), 6)
+ self.assertEquals(self.ed.GetSelectionNCaret(1), 7)
+ self.ed.MultipleSelection = 0
+
class TestRepresentations(unittest.TestCase):
def setUp(self):
--
cgit v1.2.3