diff options
author | Mitchell Foral <unknown> | 2018-02-24 15:43:07 +1100 |
---|---|---|
committer | Mitchell Foral <unknown> | 2018-02-24 15:43:07 +1100 |
commit | c81bc073334745825241e9817bc30aee2418ff9c (patch) | |
tree | 356229686d75160d70c7b53b95e998b39bad00ff | |
parent | 23d60e1d686ae4a94c94db4989f1f1071b3d920a (diff) | |
download | scintilla-mirror-c81bc073334745825241e9817bc30aee2418ff9c.tar.gz |
Backport: Fix move-extends-selection mode for rectangular and line selections.
Backport of changeset 6458:0a8a766722c0.
-rw-r--r-- | doc/ScintillaHistory.html | 3 | ||||
-rw-r--r-- | src/Editor.cxx | 69 | ||||
-rw-r--r-- | src/Editor.h | 1 | ||||
-rw-r--r-- | test/simpleTests.py | 82 |
4 files changed, 138 insertions, 17 deletions
diff --git a/doc/ScintillaHistory.html b/doc/ScintillaHistory.html index 9f4d4a7be..c52d96878 100644 --- a/doc/ScintillaHistory.html +++ b/doc/ScintillaHistory.html @@ -589,6 +589,9 @@ <a href="http://sourceforge.net/p/scintilla/bugs/1993/">Bug #1993</a>. </li> <li> + Fix move-extends-selection mode for rectangular and line selections. + </li> + <li> Fix HTML lexer handling of Django so that nesting a {{ }} or {% %} Django tag inside of a {# #} Django comment does not break highlighting of rest of file </li> diff --git a/src/Editor.cxx b/src/Editor.cxx index e810a8742..f33e5b588 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -626,26 +626,31 @@ void Editor::InvalidateWholeSelection() { InvalidateSelection(sel.RangeMain(), true); } +/* For Line selection - the anchor and caret are always + at the beginning and end of the region lines. */ +SelectionRange Editor::LineSelectionRange(SelectionPosition currentPos_, SelectionPosition anchor_) const { + if (currentPos_ > anchor_) { + anchor_ = SelectionPosition(static_cast<Sci::Position>( + pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position())))); + currentPos_ = SelectionPosition(static_cast<Sci::Position>( + pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position())))); + } else { + currentPos_ = SelectionPosition(static_cast<Sci::Position>( + pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position())))); + anchor_ = SelectionPosition(static_cast<Sci::Position>( + pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position())))); + } + return SelectionRange(currentPos_, anchor_); +} + void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) { currentPos_ = ClampPositionIntoDocument(currentPos_); anchor_ = ClampPositionIntoDocument(anchor_); Sci::Line currentLine = static_cast<Sci::Line>(pdoc->LineFromPosition(currentPos_.Position())); - /* For Line selection - ensure the anchor and caret are always - at the beginning and end of the region lines. */ + SelectionRange rangeNew(currentPos_, anchor_); if (sel.selType == Selection::selLines) { - if (currentPos_ > anchor_) { - anchor_ = SelectionPosition(static_cast<Sci::Position>( - pdoc->LineStart(pdoc->LineFromPosition(anchor_.Position())))); - currentPos_ = SelectionPosition(static_cast<Sci::Position>( - pdoc->LineEnd(pdoc->LineFromPosition(currentPos_.Position())))); - } else { - currentPos_ = SelectionPosition(static_cast<Sci::Position>( - pdoc->LineStart(pdoc->LineFromPosition(currentPos_.Position())))); - anchor_ = SelectionPosition(static_cast<Sci::Position>( - pdoc->LineEnd(pdoc->LineFromPosition(anchor_.Position())))); - } + rangeNew = LineSelectionRange(currentPos_, anchor_); } - SelectionRange rangeNew(currentPos_, anchor_); if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { InvalidateSelection(rangeNew); } @@ -675,6 +680,8 @@ void Editor::SetSelection(SelectionPosition currentPos_) { sel.Rectangular() = SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor); SetRectangularRange(); + } else if (sel.selType == Selection::selLines) { + sel.RangeMain() = LineSelectionRange(currentPos_, sel.RangeMain().anchor); } else { sel.RangeMain() = SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor); @@ -3120,7 +3127,7 @@ SelectionPosition Editor::PositionUpOrDown(SelectionPosition spStart, int direct void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { if ((selt == Selection::noSel) && sel.MoveExtends()) { - selt = Selection::selStream; + selt = !sel.IsRectangular() ? Selection::selStream : Selection::selRectangle; } SelectionPosition caretToUse = sel.Range(sel.Main()).caret; if (sel.IsRectangular()) { @@ -3142,6 +3149,11 @@ void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { sel.Rectangular() = SelectionRange(posNew, rangeBase.anchor); SetRectangularRange(); MovedCaret(posNew, caretToUse, true); + } else if (sel.selType == Selection::selLines && sel.MoveExtends()) { + // Calculate new caret position and call SetSelection(), which will ensure whole lines are selected. + const SelectionPosition posNew = MovePositionSoVisible( + PositionUpOrDown(caretToUse, direction, -1), direction); + SetSelection(posNew, sel.Range(sel.Main()).anchor); } else { InvalidateWholeSelection(); if (!additionalSelectionTyping || (sel.IsRectangular())) { @@ -3263,7 +3275,7 @@ int NaturalDirection(unsigned int iMessage) { } } -bool IsRectExtend(unsigned int iMessage) { +bool IsRectExtend(unsigned int iMessage, bool isRectMoveExtends) { switch (iMessage) { case SCI_CHARLEFTRECTEXTEND: case SCI_CHARRIGHTRECTEXTEND: @@ -3272,6 +3284,19 @@ bool IsRectExtend(unsigned int iMessage) { case SCI_LINEENDRECTEXTEND: return true; default: + if (isRectMoveExtends) { + // Handle SCI_SETSELECTIONMODE(SC_SEL_RECTANGLE) and subsequent movements. + switch (iMessage) { + case SCI_CHARLEFTEXTEND: + case SCI_CHARRIGHTEXTEND: + case SCI_HOMEEXTEND: + case SCI_VCHOMEEXTEND: + case SCI_LINEENDEXTEND: + return true; + default: + return false; + } + } return false; } } @@ -3307,6 +3332,9 @@ Sci::Position Editor::LineEndWrapPosition(Sci::Position position) { } int Editor::HorizontalMove(unsigned int iMessage) { + if (sel.selType == Selection::selLines) { + return 0; // horizontal moves with line selection have no effect + } if (sel.MoveExtends()) { iMessage = WithExtends(iMessage); } @@ -3319,7 +3347,7 @@ int Editor::HorizontalMove(unsigned int iMessage) { // Invalidate each of the current selections InvalidateWholeSelection(); - if (IsRectExtend(iMessage)) { + if (IsRectExtend(iMessage, sel.IsRectangular() && sel.MoveExtends())) { const SelectionRange rangeBase = sel.IsRectangular() ? sel.Rectangular() : sel.RangeMain(); if (!sel.IsRectangular()) { sel.DropAdditionalRanges(); @@ -3328,6 +3356,7 @@ int Editor::HorizontalMove(unsigned int iMessage) { SelectionPosition spCaret = rangeBase.caret; switch (iMessage) { case SCI_CHARLEFTRECTEXTEND: + case SCI_CHARLEFTEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() if (pdoc->IsLineEndPosition(spCaret.Position()) && spCaret.VirtualSpace()) { spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); } else if ((virtualSpaceOptions & SCVS_NOWRAPLINESTART) == 0 || pdoc->GetColumn(spCaret.Position()) > 0) { @@ -3335,6 +3364,7 @@ int Editor::HorizontalMove(unsigned int iMessage) { } break; case SCI_CHARRIGHTRECTEXTEND: + case SCI_CHARRIGHTEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) { spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); } else { @@ -3342,13 +3372,16 @@ int Editor::HorizontalMove(unsigned int iMessage) { } break; case SCI_HOMERECTEXTEND: + case SCI_HOMEEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() spCaret = SelectionPosition( static_cast<Sci::Position>(pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position())))); break; case SCI_VCHOMERECTEXTEND: + case SCI_VCHOMEEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() spCaret = SelectionPosition(pdoc->VCHomePosition(spCaret.Position())); break; case SCI_LINEENDRECTEXTEND: + case SCI_LINEENDEXTEND: // only when sel.IsRectangular() && sel.MoveExtends() spCaret = SelectionPosition(pdoc->LineEndPosition(spCaret.Position())); break; } @@ -7606,10 +7639,12 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SC_SEL_RECTANGLE: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle)); sel.selType = Selection::selRectangle; + sel.Rectangular() = sel.RangeMain(); // adjust current selection break; case SC_SEL_LINES: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines)); sel.selType = Selection::selLines; + SetSelection(sel.RangeMain().caret, sel.RangeMain().anchor); // adjust current selection break; case SC_SEL_THIN: sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin)); diff --git a/src/Editor.h b/src/Editor.h index 709adca39..af7586934 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -312,6 +312,7 @@ protected: // ScintillaBase subclass needs access to much of Editor void ThinRectangularRange(); void InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection=false); void InvalidateWholeSelection(); + SelectionRange LineSelectionRange(SelectionPosition currentPos_, SelectionPosition anchor_) const; void SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_); void SetSelection(Sci::Position currentPos_, Sci::Position anchor_); void SetSelection(SelectionPosition currentPos_); diff --git a/test/simpleTests.py b/test/simpleTests.py index 62243dd49..3ff283dad 100644 --- a/test/simpleTests.py +++ b/test/simpleTests.py @@ -1466,6 +1466,88 @@ class TestMultiSelection(unittest.TestCase): self.ed.DropSelectionN(0) self.assertEquals(self.ed.MainSelection, 2) +class TestModalSelection(unittest.TestCase): + + def setUp(self): + self.xite = Xite.xiteFrame + self.ed = self.xite.ed + self.ed.ClearAll() + self.ed.EmptyUndoBuffer() + # 3 lines of 3 characters + t = b"xxx\nxxx\nxxx" + self.ed.AddText(len(t), t) + + def testCharacterSelection(self): + self.ed.SetSelection(1, 1) + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 1) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.ed.SelectionMode = self.ed.SC_SEL_STREAM + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 1) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.ed.CharRight() + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 2) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.ed.LineDown() + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 6) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.ed.ClearSelections() + + def testRectangleSelection(self): + self.ed.SetSelection(1, 1) + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 1) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.ed.SelectionMode = self.ed.SC_SEL_RECTANGLE + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 1) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.ed.CharRight() + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 2) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.ed.LineDown() + self.assertEquals(self.ed.Selections, 2) + self.assertEquals(self.ed.MainSelection, 1) + self.assertEquals(self.ed.GetSelectionNCaret(0), 2) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.assertEquals(self.ed.GetSelectionNCaret(1), 6) + self.assertEquals(self.ed.GetSelectionNAnchor(1), 5) + self.ed.ClearSelections() + + def testLinesSelection(self): + self.ed.SetSelection(1, 1) + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 1) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 1) + self.ed.SelectionMode = self.ed.SC_SEL_LINES + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 0) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 3) + self.ed.CharRight() + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 0) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 3) + self.ed.LineDown() + self.assertEquals(self.ed.Selections, 1) + self.assertEquals(self.ed.MainSelection, 0) + self.assertEquals(self.ed.GetSelectionNCaret(0), 7) + self.assertEquals(self.ed.GetSelectionNAnchor(0), 0) + self.ed.ClearSelections() + class TestStyleAttributes(unittest.TestCase): """ These tests are just to ensure that the calls set and retrieve values. They do not check the visual appearance of the style attributes. |