aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2015-06-11 21:58:21 +1000
committerNeil <nyamatongwe@gmail.com>2015-06-11 21:58:21 +1000
commitc232fb50fc2cb0f30e3440bc61dbe7c5efacef35 (patch)
tree4f43a38a60b712a7eeefe4b025efd1f57173bca6
parent30d76df9409b32a53fedbea53eda2d4849e4f91c (diff)
downloadscintilla-mirror-c232fb50fc2cb0f30e3440bc61dbe7c5efacef35.tar.gz
Added MultipleSelectAddNext, MultipleSelectAddEach, IsRangeWord, and
TargetWholeDocument.
-rw-r--r--doc/ScintillaDoc.html19
-rw-r--r--doc/ScintillaHistory.html12
-rw-r--r--include/Scintilla.h6
-rw-r--r--include/Scintilla.iface20
-rw-r--r--src/Document.cxx2
-rw-r--r--src/Document.h8
-rw-r--r--src/Editor.cxx75
-rw-r--r--src/Editor.h2
-rw-r--r--test/simpleTests.py54
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 {
<a class="message" href="#SCI_GETTARGETEND">SCI_GETTARGETEND</a><br />
<a class="message" href="#SCI_SETTARGETRANGE">SCI_SETTARGETRANGE(int start, int end)</a><br />
<a class="message" href="#SCI_TARGETFROMSELECTION">SCI_TARGETFROMSELECTION</a><br />
+ <a class="message" href="#SCI_TARGETWHOLEDOCUMENT">SCI_TARGETWHOLEDOCUMENT</a><br />
<a class="message" href="#SCI_SETSEARCHFLAGS">SCI_SETSEARCHFLAGS(int searchFlags)</a><br />
<a class="message" href="#SCI_GETSEARCHFLAGS">SCI_GETSEARCHFLAGS</a><br />
<a class="message" href="#SCI_SEARCHINTARGET">SCI_SEARCHINTARGET(int length, const char
@@ -667,6 +668,9 @@ struct Sci_TextRange {
<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>
+ <p><b id="SCI_TARGETWHOLEDOCUMENT">SCI_TARGETWHOLEDOCUMENT</b><br />
+ Set the target start to the start of the document and target end to the end of the document.</p>
+
<p><b id="SCI_SETSEARCHFLAGS">SCI_SETSEARCHFLAGS(int searchFlags)</b><br />
<b id="SCI_GETSEARCHFLAGS">SCI_GETSEARCHFLAGS</b><br />
These get and set the <a class="jump" href="#searchFlags"><code>searchFlags</code></a> used by
@@ -1175,6 +1179,7 @@ struct Sci_TextToFind {
onlyWordCharacters)</a><br />
<a class="message" href="#SCI_WORDSTARTPOSITION">SCI_WORDSTARTPOSITION(int position, bool
onlyWordCharacters)</a><br />
+ <a class="message" href="#SCI_ISRANGEWORD">SCI_ISRANGEWORD(int start, int end)</a><br />
<a class="message" href="#SCI_POSITIONBEFORE">SCI_POSITIONBEFORE(int position)</a><br />
<a class="message" href="#SCI_POSITIONAFTER">SCI_POSITIONAFTER(int position)</a><br />
<a class="message" href="#SCI_POSITIONRELATIVE">SCI_POSITIONRELATIVE(int position, int relative)</a><br />
@@ -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.</p>
+ <p><b id="SCI_ISRANGEWORD">SCI_ISRANGEWORD(int start, int end)</b><br />
+ 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.</p>
+
+ <a class="message" href="#SCI_ISRANGEWORD">SCI_ISRANGEWORD(int start, int end)</a><br />
+
<p>Set <code>onlyWordCharacters</code> to <code>true</code> (1) to stop searching at the first
non-word character in the search direction. If <code>onlyWordCharacters</code> is
<code>false</code> (0), the first character in the search direction sets the type of the search
@@ -1624,6 +1635,7 @@ struct Sci_TextToFind {
<a class="message" href="#SCI_SWAPMAINANCHORCARET">SCI_SWAPMAINANCHORCARET</a><br />
<a class="message" href="#SCI_ROTATESELECTION">SCI_ROTATESELECTION</a><br />
+ <a class="message" href="#SCI_MULTIPLESELECTADDNEXT">SCI_MULTIPLESELECTADDNEXT</a><br />
</code>
<p>
@@ -1789,9 +1801,14 @@ struct Sci_TextToFind {
<p>
<b id="SCI_SWAPMAINANCHORCARET">SCI_SWAPMAINANCHORCARET</b><br />
<b id="SCI_ROTATESELECTION">SCI_ROTATESELECTION</b><br />
+ <b id="SCI_MULTIPLESELECTADDNEXT">SCI_MULTIPLESELECTADDNEXT</b><br />
These commands may be assigned to keys to make it possible to manipulate multiple selections.
<code>SCI_SWAPMAINANCHORCARET</code> moves the caret to the opposite end of the main selection.
- <code>SCI_ROTATESELECTION</code> makes the next selection be the main selection.
+ <code>SCI_ROTATESELECTION</code> makes the next selection be the main selection.<br />
+ <code>SCI_MULTIPLESELECTADDNEXT</code> 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 <a class="jump" href="#searchFlags"><code>searchFlags</code></a>
+ are used so the application may choose case sensitivity and word search options.
</p>
<h2 id="ScrollingAndAutomaticScrolling">Scrolling and automatic scrolling</h2>
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.
</li>
<li>
+ 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.
+ </li>
+ <li>
+ Added SCI_ISRANGEWORD to determine if the parameters are at the start and end of a word.
+ </li>
+ <li>
+ Added SCI_TARGETWHOLEDOCUMENT to set the target to the whole document.
+ </li>
+ <li>
Verilog lexer recognises protected regions and the folder folds protected regions.
</li>
<li>
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<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.
+ 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<Range>::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<int>(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<int>(wParam), 1, lParam != 0);
+ case SCI_ISRANGEWORD:
+ return pdoc->IsWordAt(static_cast<int>(wParam), lParam);
+
case SCI_SETWRAPMODE:
if (vs.SetWrapState(static_cast<int>(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<int>(wParam), static_cast<int>(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):