diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Editor.cxx | 873 | ||||
-rw-r--r-- | src/Editor.h | 7 | ||||
-rw-r--r-- | src/Selection.cxx | 8 | ||||
-rw-r--r-- | src/Selection.h | 1 |
4 files changed, 552 insertions, 337 deletions
diff --git a/src/Editor.cxx b/src/Editor.cxx index 9e57cb0bc..a3f9e1845 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -803,9 +803,37 @@ SelectionPosition Editor::MovePositionOutsideChar(SelectionPosition pos, int mov return pos; } +void Editor::MovedCaret(SelectionPosition newPos, SelectionPosition previousPos, bool ensureVisible) { + const int currentLine = pdoc->LineFromPosition(newPos.Position()); + if (ensureVisible) { + // In case in need of wrapping to ensure DisplayFromDoc works. + if (currentLine >= wrapPending.start) + WrapLines(wsAll); + XYScrollPosition newXY = XYScrollToMakeVisible( + SelectionRange(posDrag.IsValid() ? posDrag : newPos), xysDefault); + if (previousPos.IsValid() && (newXY.xOffset == xOffset)) { + // simple vertical scroll then invalidate + ScrollTo(newXY.topLine); + InvalidateSelection(SelectionRange(previousPos), true); + } else { + SetXYScroll(newXY); + } + } + + ShowCaretAtCurrentPosition(); + + ClaimSelection(); + SetHoverIndicatorPosition(sel.MainCaret()); + QueueIdleWork(WorkNeeded::workUpdateUI); + + if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { + RedrawSelMargin(); + } +} + void Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) { - const bool simpleCaret = (sel.Count() == 1) && sel.Empty(); - const SelectionPosition spCaret = sel.Last(); + const SelectionPosition spCaret = ((sel.Count() == 1) && sel.Empty()) ? + sel.Last() : SelectionPosition(INVALID_POSITION); int delta = newPos.Position() - sel.MainCaret(); newPos = ClampPositionIntoDocument(newPos); @@ -830,27 +858,8 @@ void Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, } else { SetEmptySelection(newPos); } - ShowCaretAtCurrentPosition(); - const int currentLine = pdoc->LineFromPosition(newPos.Position()); - if (ensureVisible) { - // In case in need of wrapping to ensure DisplayFromDoc works. - if (currentLine >= wrapPending.start) - WrapLines(wsAll); - XYScrollPosition newXY = XYScrollToMakeVisible( - SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret), xysDefault); - if (simpleCaret && (newXY.xOffset == xOffset)) { - // simple vertical scroll then invalidate - ScrollTo(newXY.topLine); - InvalidateSelection(SelectionRange(spCaret), true); - } else { - SetXYScroll(newXY); - } - } - - if (marginView.highlightDelimiter.NeedsDrawing(currentLine)) { - RedrawSelMargin(); - } + MovedCaret(newPos, spCaret, ensureVisible); } void Editor::MovePositionTo(int newPos, Selection::selTypes selt, bool ensureVisible) { @@ -2952,30 +2961,36 @@ void Editor::CancelModes() { } void Editor::NewLine() { - // Remove non-main ranges InvalidateWholeSelection(); - sel.DropAdditionalRanges(); - sel.RangeMain().ClearVirtualSpace(); + if (sel.IsRectangular() || !additionalSelectionTyping) { + // Remove non-main ranges + sel.DropAdditionalRanges(); + } - // Clear main range and insert line end - bool needGroupUndo = !sel.Empty(); - if (needGroupUndo) - pdoc->BeginUndoAction(); + UndoGroup ug(pdoc, !sel.Empty() || (sel.Count() > 1)); - if (!sel.Empty()) + // Clear each range + if (!sel.Empty()) { ClearSelection(); - const char *eol = "\n"; - if (pdoc->eolMode == SC_EOL_CRLF) { - eol = "\r\n"; - } else if (pdoc->eolMode == SC_EOL_CR) { - eol = "\r"; - } // else SC_EOL_LF -> "\n" already set - const int insertLength = pdoc->InsertString(sel.MainCaret(), eol, istrlen(eol)); - // Want to end undo group before NotifyChar as applications often modify text here - if (needGroupUndo) - pdoc->EndUndoAction(); - if (insertLength > 0) { - SetEmptySelection(sel.MainCaret() + insertLength); + } + + // Insert each line end + size_t countInsertions = 0; + for (size_t r = 0; r < sel.Count(); r++) { + sel.Range(r).ClearVirtualSpace(); + const char *eol = StringFromEOLMode(pdoc->eolMode); + const int positionInsert = sel.Range(r).caret.Position(); + const int insertLength = pdoc->InsertString(positionInsert, eol, istrlen(eol)); + if (insertLength > 0) { + sel.Range(r) = SelectionRange(positionInsert + insertLength); + countInsertions++; + } + } + + // Perform notifications after all the changes as the application may change the + // selections in response to the characters. + for (size_t i = 0; i < countInsertions; i++) { + const char *eol = StringFromEOLMode(pdoc->eolMode); while (*eol) { NotifyChar(*eol); if (recordingMacro) { @@ -2987,6 +3002,7 @@ void Editor::NewLine() { eol++; } } + SetLastXChosen(); SetScrollBars(); EnsureCaretVisible(); @@ -2994,26 +3010,17 @@ void Editor::NewLine() { ShowCaretAtCurrentPosition(); } -void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { - SelectionPosition caretToUse = sel.Range(sel.Main()).caret; - if (sel.IsRectangular()) { - if (selt == Selection::noSel) { - caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start; - } else { - caretToUse = sel.Rectangular().caret; - } - } - - Point pt = LocationFromPosition(caretToUse); +SelectionPosition Editor::PositionUpOrDown(SelectionPosition spStart, int direction, int lastX) { + const Point pt = LocationFromPosition(spStart); int skipLines = 0; if (vs.annotationVisible) { - int lineDoc = pdoc->LineFromPosition(caretToUse.Position()); - Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc)); - int subLine = static_cast<int>(pt.y - ptStartLine.y) / vs.lineHeight; + const int lineDoc = pdoc->LineFromPosition(spStart.Position()); + const Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc)); + const int subLine = static_cast<int>(pt.y - ptStartLine.y) / vs.lineHeight; if (direction < 0 && subLine == 0) { - int lineDisplay = cs.DisplayFromDoc(lineDoc); + const int lineDisplay = cs.DisplayFromDoc(lineDoc); if (lineDisplay > 0) { skipLines = pdoc->AnnotationLines(cs.DocFromDisplay(lineDisplay - 1)); } @@ -3022,9 +3029,12 @@ void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { } } - int newY = static_cast<int>(pt.y) + (1 + skipLines) * direction * vs.lineHeight; + const int newY = static_cast<int>(pt.y) + (1 + skipLines) * direction * vs.lineHeight; + if (lastX < 0) { + lastX = static_cast<int>(pt.x) + xOffset; + } SelectionPosition posNew = SPositionFromLocation( - Point::FromInts(lastXChosen - xOffset, newY), false, false, UserVirtualSpace()); + Point::FromInts(lastX - xOffset, newY), false, false, UserVirtualSpace()); if (direction < 0) { // Line wrapping may lead to a location on the same line, so @@ -3039,14 +3049,53 @@ void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { // There is an equivalent case when moving down which skips // over a line. Point ptNew = LocationFromPosition(posNew.Position()); - while ((posNew.Position() > caretToUse.Position()) && (ptNew.y > newY)) { + while ((posNew.Position() > spStart.Position()) && (ptNew.y > newY)) { posNew.Add(-1); posNew.SetVirtualSpace(0); ptNew = LocationFromPosition(posNew.Position()); } } + return posNew; +} - MovePositionTo(MovePositionSoVisible(posNew, direction), selt); +void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { + SelectionPosition caretToUse = sel.Range(sel.Main()).caret; + if (sel.IsRectangular()) { + if (selt == Selection::noSel) { + caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start; + } else { + caretToUse = sel.Rectangular().caret; + } + } + if (selt == Selection::selRectangle) { + const SelectionRange rangeBase = sel.IsRectangular() ? sel.Rectangular() : sel.RangeMain(); + if (!sel.IsRectangular()) { + InvalidateWholeSelection(); + sel.DropAdditionalRanges(); + } + const SelectionPosition posNew = MovePositionSoVisible( + PositionUpOrDown(caretToUse, direction, lastXChosen), direction); + sel.selType = Selection::selRectangle; + sel.Rectangular() = SelectionRange(posNew, rangeBase.anchor); + SetRectangularRange(); + MovedCaret(posNew, caretToUse, true); + } else { + if (!additionalSelectionTyping || (sel.IsRectangular())) { + InvalidateWholeSelection(); + sel.DropAdditionalRanges(); + } + sel.selType = Selection::selStream; + for (size_t r = 0; r < sel.Count(); r++) { + const int lastX = (r == sel.Main()) ? lastXChosen : -1; + const SelectionPosition spCaretNow = sel.Range(r).caret; + const SelectionPosition posNew = MovePositionSoVisible( + PositionUpOrDown(spCaretNow, direction, lastX), direction); + sel.Range(r) = selt == Selection::selStream ? + SelectionRange(posNew, sel.Range(r).anchor) : SelectionRange(posNew); + } + sel.RemoveDuplicates(); + MovedCaret(sel.RangeMain().caret, caretToUse, true); + } } void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) { @@ -3076,6 +3125,402 @@ int Editor::StartEndDisplayLine(int pos, bool start) { } } +namespace { + +unsigned int WithExtends(unsigned int iMessage) { + switch (iMessage) { + case SCI_CHARLEFT: return SCI_CHARLEFTEXTEND; + case SCI_CHARRIGHT: return SCI_CHARRIGHTEXTEND; + + case SCI_WORDLEFT: return SCI_WORDLEFTEXTEND; + case SCI_WORDRIGHT: return SCI_WORDRIGHTEXTEND; + case SCI_WORDLEFTEND: return SCI_WORDLEFTENDEXTEND; + case SCI_WORDRIGHTEND: return SCI_WORDRIGHTENDEXTEND; + case SCI_WORDPARTLEFT: return SCI_WORDPARTLEFTEXTEND; + case SCI_WORDPARTRIGHT: return SCI_WORDPARTRIGHTEXTEND; + + case SCI_HOME: return SCI_HOMEEXTEND; + case SCI_HOMEDISPLAY: return SCI_HOMEDISPLAYEXTEND; + case SCI_HOMEWRAP: return SCI_HOMEWRAPEXTEND; + case SCI_VCHOME: return SCI_VCHOMEEXTEND; + case SCI_VCHOMEDISPLAY: return SCI_VCHOMEDISPLAYEXTEND; + case SCI_VCHOMEWRAP: return SCI_VCHOMEWRAPEXTEND; + + case SCI_LINEEND: return SCI_LINEENDEXTEND; + case SCI_LINEENDDISPLAY: return SCI_LINEENDDISPLAYEXTEND; + case SCI_LINEENDWRAP: return SCI_LINEENDWRAPEXTEND; + + default: return iMessage; + } +} + +int NaturalDirection(unsigned int iMessage) { + switch (iMessage) { + case SCI_CHARLEFT: + case SCI_CHARLEFTEXTEND: + case SCI_CHARLEFTRECTEXTEND: + case SCI_WORDLEFT: + case SCI_WORDLEFTEXTEND: + case SCI_WORDLEFTEND: + case SCI_WORDLEFTENDEXTEND: + case SCI_WORDPARTLEFT: + case SCI_WORDPARTLEFTEXTEND: + case SCI_HOME: + case SCI_HOMEEXTEND: + case SCI_HOMEDISPLAY: + case SCI_HOMEDISPLAYEXTEND: + case SCI_HOMEWRAP: + case SCI_HOMEWRAPEXTEND: + // VC_HOME* mostly goes back + case SCI_VCHOME: + case SCI_VCHOMEEXTEND: + case SCI_VCHOMEDISPLAY: + case SCI_VCHOMEDISPLAYEXTEND: + case SCI_VCHOMEWRAP: + case SCI_VCHOMEWRAPEXTEND: + return -1; + + default: + return 1; + } +} + +bool IsRectExtend(unsigned int iMessage) { + switch (iMessage) { + case SCI_CHARLEFTRECTEXTEND: + case SCI_CHARRIGHTRECTEXTEND: + case SCI_HOMERECTEXTEND: + case SCI_VCHOMERECTEXTEND: + case SCI_LINEENDRECTEXTEND: + return true; + default: + return false; + } +} + +} + +int Editor::VCHomeDisplayPosition(int position) { + const int homePos = pdoc->VCHomePosition(position); + const int viewLineStart = StartEndDisplayLine(position, true); + if (viewLineStart > homePos) + return viewLineStart; + else + return homePos; +} + +int Editor::VCHomeWrapPosition(int position) { + const int homePos = pdoc->VCHomePosition(position); + const int viewLineStart = StartEndDisplayLine(position, true); + if ((viewLineStart < position) && (viewLineStart > homePos)) + return viewLineStart; + else + return homePos; +} + +int Editor::LineEndWrapPosition(int position) { + const int endPos = StartEndDisplayLine(position, false); + const int realEndPos = pdoc->LineEndPosition(position); + if (endPos > realEndPos // if moved past visible EOLs + || position >= endPos) // if at end of display line already + return realEndPos; + else + return endPos; +} + +int Editor::HorizontalMove(unsigned int iMessage) { + if (sel.MoveExtends()) { + iMessage = WithExtends(iMessage); + } + + if (!multipleSelection && !sel.IsRectangular()) { + // Simplify selection down to 1 + sel.SetSelection(sel.RangeMain()); + } + + // Invalidate each of the current selections + InvalidateWholeSelection(); + + if (IsRectExtend(iMessage)) { + const SelectionRange rangeBase = sel.IsRectangular() ? sel.Rectangular() : sel.RangeMain(); + if (!sel.IsRectangular()) { + sel.DropAdditionalRanges(); + } + // Will change to rectangular if not currently rectangular + SelectionPosition spCaret = rangeBase.caret; + switch (iMessage) { + case SCI_CHARLEFTRECTEXTEND: + if (pdoc->IsLineEndPosition(spCaret.Position()) && spCaret.VirtualSpace()) { + spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); + } else { + spCaret = SelectionPosition(spCaret.Position() - 1); + } + break; + case SCI_CHARRIGHTRECTEXTEND: + if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) { + spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); + } else { + spCaret = SelectionPosition(spCaret.Position() + 1); + } + break; + case SCI_HOMERECTEXTEND: + spCaret = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); + break; + case SCI_VCHOMERECTEXTEND: + spCaret = SelectionPosition(pdoc->VCHomePosition(spCaret.Position())); + break; + case SCI_LINEENDRECTEXTEND: + spCaret = SelectionPosition(pdoc->LineEndPosition(spCaret.Position())); + break; + } + const int directionMove = (spCaret < rangeBase.caret) ? -1 : 1; + spCaret = MovePositionSoVisible(spCaret, directionMove); + sel.selType = Selection::selRectangle; + sel.Rectangular() = SelectionRange(spCaret, rangeBase.anchor); + SetRectangularRange(); + } else { + if (sel.IsRectangular()) { + // Not a rectangular extension so switch to stream. + SelectionPosition selAtLimit = (NaturalDirection(iMessage) > 0) ? sel.Limits().end : sel.Limits().start; + sel.selType = Selection::selStream; + sel.SetSelection(SelectionRange(selAtLimit)); + } + if (!additionalSelectionTyping) { + InvalidateWholeSelection(); + sel.DropAdditionalRanges(); + } + for (size_t r = 0; r < sel.Count(); r++) { + const SelectionPosition spCaretNow = sel.Range(r).caret; + SelectionPosition spCaret = spCaretNow; + switch (iMessage) { + case SCI_CHARLEFT: + case SCI_CHARLEFTEXTEND: + if (spCaret.VirtualSpace()) { + spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); + } else { + spCaret = SelectionPosition(spCaret.Position() - 1); + } + break; + case SCI_CHARRIGHT: + case SCI_CHARRIGHTEXTEND: + if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(spCaret.Position())) { + spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); + } else { + spCaret = SelectionPosition(spCaret.Position() + 1); + } + break; + case SCI_WORDLEFT: + case SCI_WORDLEFTEXTEND: + spCaret = SelectionPosition(pdoc->NextWordStart(spCaret.Position(), -1)); + break; + case SCI_WORDRIGHT: + case SCI_WORDRIGHTEXTEND: + spCaret = SelectionPosition(pdoc->NextWordStart(spCaret.Position(), 1)); + break; + case SCI_WORDLEFTEND: + case SCI_WORDLEFTENDEXTEND: + spCaret = SelectionPosition(pdoc->NextWordEnd(spCaret.Position(), -1)); + break; + case SCI_WORDRIGHTEND: + case SCI_WORDRIGHTENDEXTEND: + spCaret = SelectionPosition(pdoc->NextWordEnd(spCaret.Position(), 1)); + break; + case SCI_WORDPARTLEFT: + case SCI_WORDPARTLEFTEXTEND: + spCaret = SelectionPosition(pdoc->WordPartLeft(spCaret.Position())); + break; + case SCI_WORDPARTRIGHT: + case SCI_WORDPARTRIGHTEXTEND: + spCaret = SelectionPosition(pdoc->WordPartRight(spCaret.Position())); + break; + case SCI_HOME: + case SCI_HOMEEXTEND: + spCaret = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); + break; + case SCI_HOMEDISPLAY: + case SCI_HOMEDISPLAYEXTEND: + spCaret = SelectionPosition(StartEndDisplayLine(spCaret.Position(), true)); + break; + case SCI_HOMEWRAP: + case SCI_HOMEWRAPEXTEND: + spCaret = MovePositionSoVisible(StartEndDisplayLine(spCaret.Position(), true), -1); + if (spCaretNow <= spCaret) + spCaret = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(spCaret.Position()))); + break; + case SCI_VCHOME: + case SCI_VCHOMEEXTEND: + // VCHome alternates between beginning of line and beginning of text so may move back or forwards + spCaret = SelectionPosition(pdoc->VCHomePosition(spCaret.Position())); + break; + case SCI_VCHOMEDISPLAY: + case SCI_VCHOMEDISPLAYEXTEND: + spCaret = SelectionPosition(VCHomeDisplayPosition(spCaret.Position())); + break; + case SCI_VCHOMEWRAP: + case SCI_VCHOMEWRAPEXTEND: + spCaret = SelectionPosition(VCHomeWrapPosition(spCaret.Position())); + break; + case SCI_LINEEND: + case SCI_LINEENDEXTEND: + spCaret = SelectionPosition(pdoc->LineEndPosition(spCaret.Position())); + break; + case SCI_LINEENDDISPLAY: + case SCI_LINEENDDISPLAYEXTEND: + spCaret = SelectionPosition(StartEndDisplayLine(spCaret.Position(), false)); + break; + case SCI_LINEENDWRAP: + case SCI_LINEENDWRAPEXTEND: + spCaret = SelectionPosition(LineEndWrapPosition(spCaret.Position())); + break; + + default: + PLATFORM_ASSERT(false); + } + + const int directionMove = (spCaret < spCaretNow) ? -1 : 1; + spCaret = MovePositionSoVisible(spCaret, directionMove); + + // Handle move versus extend, and special behaviour for non-emoty left/right + switch (iMessage) { + case SCI_CHARLEFT: + case SCI_CHARRIGHT: + if (sel.Range(r).Empty()) { + sel.Range(r) = SelectionRange(spCaret); + } else { + sel.Range(r) = SelectionRange( + (iMessage == SCI_CHARLEFT) ? sel.Range(r).Start() : sel.Range(r).End()); + } + break; + + case SCI_WORDLEFT: + case SCI_WORDRIGHT: + case SCI_WORDLEFTEND: + case SCI_WORDRIGHTEND: + case SCI_WORDPARTLEFT: + case SCI_WORDPARTRIGHT: + case SCI_HOME: + case SCI_HOMEDISPLAY: + case SCI_HOMEWRAP: + case SCI_VCHOME: + case SCI_VCHOMEDISPLAY: + case SCI_VCHOMEWRAP: + case SCI_LINEEND: + case SCI_LINEENDDISPLAY: + case SCI_LINEENDWRAP: + sel.Range(r) = SelectionRange(spCaret); + break; + + case SCI_CHARLEFTEXTEND: + case SCI_CHARRIGHTEXTEND: + case SCI_WORDLEFTEXTEND: + case SCI_WORDRIGHTEXTEND: + case SCI_WORDLEFTENDEXTEND: + case SCI_WORDRIGHTENDEXTEND: + case SCI_WORDPARTLEFTEXTEND: + case SCI_WORDPARTRIGHTEXTEND: + case SCI_HOMEEXTEND: + case SCI_HOMEDISPLAYEXTEND: + case SCI_HOMEWRAPEXTEND: + case SCI_VCHOMEEXTEND: + case SCI_VCHOMEDISPLAYEXTEND: + case SCI_VCHOMEWRAPEXTEND: + case SCI_LINEENDEXTEND: + case SCI_LINEENDDISPLAYEXTEND: + case SCI_LINEENDWRAPEXTEND: { + SelectionRange rangeNew = SelectionRange(spCaret, sel.Range(r).anchor); + sel.TrimOtherSelections(r, SelectionRange(rangeNew)); + sel.Range(r) = rangeNew; + } + break; + + default: + PLATFORM_ASSERT(false); + } + } + } + + sel.RemoveDuplicates(); + + MovedCaret(sel.RangeMain().caret, SelectionPosition(INVALID_POSITION), true); + + // Invalidate the new state of the selection + InvalidateWholeSelection(); + + SetLastXChosen(); + // Need the line moving and so forth from MovePositionTo + return 0; +} + +int Editor::DelWordOrLine(unsigned int iMessage) { + // Virtual space may be realised for SCI_DELWORDRIGHT or SCI_DELWORDRIGHTEND + // which means 2 actions so wrap in an undo group. + + // Rightwards and leftwards deletions differ in treatment of virtual space. + // Clear virtual space for leftwards, realise for rightwards. + const bool leftwards = (iMessage == SCI_DELWORDLEFT) || (iMessage == SCI_DELLINELEFT); + + if (!additionalSelectionTyping) { + InvalidateWholeSelection(); + sel.DropAdditionalRanges(); + } + + UndoGroup ug0(pdoc, (sel.Count() > 1) || !leftwards); + + for (size_t r = 0; r < sel.Count(); r++) { + if (leftwards) { + // Delete to the left so first clear the virtual space. + sel.Range(r).ClearVirtualSpace(); + } else { + // Delete to the right so first realise the virtual space. + sel.Range(r) = SelectionRange( + InsertSpace(sel.Range(r).caret.Position(), sel.Range(r).caret.VirtualSpace())); + } + + Range rangeDelete; + switch (iMessage) { + case SCI_DELWORDLEFT: + rangeDelete = Range( + pdoc->NextWordStart(sel.Range(r).caret.Position(), -1), + sel.Range(r).caret.Position()); + break; + case SCI_DELWORDRIGHT: + rangeDelete = Range( + sel.Range(r).caret.Position(), + pdoc->NextWordStart(sel.Range(r).caret.Position(), 1)); + break; + case SCI_DELWORDRIGHTEND: + rangeDelete = Range( + sel.Range(r).caret.Position(), + pdoc->NextWordEnd(sel.Range(r).caret.Position(), 1)); + break; + case SCI_DELLINELEFT: + rangeDelete = Range( + pdoc->LineStart(pdoc->LineFromPosition(sel.Range(r).caret.Position())), + sel.Range(r).caret.Position()); + break; + case SCI_DELLINERIGHT: + rangeDelete = Range( + sel.Range(r).caret.Position(), + pdoc->LineEnd(pdoc->LineFromPosition(sel.Range(r).caret.Position()))); + break; + } + if (!RangeContainsProtected(rangeDelete.start, rangeDelete.end)) { + pdoc->DeleteChars(rangeDelete.start, rangeDelete.end - rangeDelete.start); + } + } + + // May need something stronger here: can selections overlap at this point? + sel.RemoveDuplicates(); + + MovedCaret(sel.RangeMain().caret, SelectionPosition(INVALID_POSITION), true); + + // Invalidate the new state of the selection + InvalidateWholeSelection(); + + SetLastXChosen(); + return 0; +} + int Editor::KeyCommand(unsigned int iMessage) { switch (iMessage) { case SCI_LINEDOWN: @@ -3116,174 +3561,48 @@ int Editor::KeyCommand(unsigned int iMessage) { ScrollTo(topLine - 1); MoveCaretInsideView(false); break; + case SCI_CHARLEFT: - if (SelectionEmpty() || sel.MoveExtends()) { - if ((sel.Count() == 1) && pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { - SelectionPosition spCaret = sel.RangeMain().caret; - spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); - MovePositionTo(spCaret); - } else if (sel.MoveExtends() && sel.selType == Selection::selStream) { - MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1)); - } else { - MovePositionTo(MovePositionSoVisible( - SelectionPosition((sel.LimitsForRectangularElseMain().start).Position() - 1), -1)); - } - } else { - MovePositionTo(sel.LimitsForRectangularElseMain().start); - } - SetLastXChosen(); - break; case SCI_CHARLEFTEXTEND: - if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { - SelectionPosition spCaret = sel.RangeMain().caret; - spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); - MovePositionTo(spCaret, Selection::selStream); - } else { - MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream); - } - SetLastXChosen(); - break; case SCI_CHARLEFTRECTEXTEND: - if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { - SelectionPosition spCaret = sel.RangeMain().caret; - spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); - MovePositionTo(spCaret, Selection::selRectangle); - } else { - MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle); - } - SetLastXChosen(); - break; case SCI_CHARRIGHT: - if (SelectionEmpty() || sel.MoveExtends()) { - if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) { - SelectionPosition spCaret = sel.RangeMain().caret; - spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); - MovePositionTo(spCaret); - } else if (sel.MoveExtends() && sel.selType == Selection::selStream) { - MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1)); - } else { - MovePositionTo(MovePositionSoVisible( - SelectionPosition((sel.LimitsForRectangularElseMain().end).Position() + 1), 1)); - } - } else { - MovePositionTo(sel.LimitsForRectangularElseMain().end); - } - SetLastXChosen(); - break; case SCI_CHARRIGHTEXTEND: - if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) { - SelectionPosition spCaret = sel.RangeMain().caret; - spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); - MovePositionTo(spCaret, Selection::selStream); - } else { - MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream); - } - SetLastXChosen(); - break; case SCI_CHARRIGHTRECTEXTEND: - if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) { - SelectionPosition spCaret = sel.RangeMain().caret; - spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); - MovePositionTo(spCaret, Selection::selRectangle); - } else { - MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle); - } - SetLastXChosen(); - break; case SCI_WORDLEFT: - MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1)); - SetLastXChosen(); - break; case SCI_WORDLEFTEXTEND: - MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream); - SetLastXChosen(); - break; case SCI_WORDRIGHT: - MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1)); - SetLastXChosen(); - break; case SCI_WORDRIGHTEXTEND: - MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream); - SetLastXChosen(); - break; - case SCI_WORDLEFTEND: - MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1)); - SetLastXChosen(); - break; case SCI_WORDLEFTENDEXTEND: - MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream); - SetLastXChosen(); - break; case SCI_WORDRIGHTEND: - MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1)); - SetLastXChosen(); - break; case SCI_WORDRIGHTENDEXTEND: - MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream); - SetLastXChosen(); - break; - + case SCI_WORDPARTLEFT: + case SCI_WORDPARTLEFTEXTEND: + case SCI_WORDPARTRIGHT: + case SCI_WORDPARTRIGHTEXTEND: case SCI_HOME: - MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); - SetLastXChosen(); - break; case SCI_HOMEEXTEND: - MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream); - SetLastXChosen(); - break; case SCI_HOMERECTEXTEND: - MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle); - SetLastXChosen(); - break; + case SCI_HOMEDISPLAY: + case SCI_HOMEDISPLAYEXTEND: + case SCI_HOMEWRAP: + case SCI_HOMEWRAPEXTEND: + case SCI_VCHOME: + case SCI_VCHOMEEXTEND: + case SCI_VCHOMERECTEXTEND: + case SCI_VCHOMEDISPLAY: + case SCI_VCHOMEDISPLAYEXTEND: + case SCI_VCHOMEWRAP: + case SCI_VCHOMEWRAPEXTEND: case SCI_LINEEND: - MovePositionTo(pdoc->LineEndPosition(sel.MainCaret())); - SetLastXChosen(); - break; case SCI_LINEENDEXTEND: - MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream); - SetLastXChosen(); - break; case SCI_LINEENDRECTEXTEND: - MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle); - SetLastXChosen(); - break; - case SCI_HOMEWRAP: { - SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); - if (sel.RangeMain().caret <= homePos) - homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); - MovePositionTo(homePos); - SetLastXChosen(); - } - break; - case SCI_HOMEWRAPEXTEND: { - SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); - if (sel.RangeMain().caret <= homePos) - homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); - MovePositionTo(homePos, Selection::selStream); - SetLastXChosen(); - } - break; - case SCI_LINEENDWRAP: { - SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1); - SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret())); - if (endPos > realEndPos // if moved past visible EOLs - || sel.RangeMain().caret >= endPos) // if at end of display line already - endPos = realEndPos; - MovePositionTo(endPos); - SetLastXChosen(); - } - break; - case SCI_LINEENDWRAPEXTEND: { - SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1); - SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret())); - if (endPos > realEndPos // if moved past visible EOLs - || sel.RangeMain().caret >= endPos) // if at end of display line already - endPos = realEndPos; - MovePositionTo(endPos, Selection::selStream); - SetLastXChosen(); - } - break; + case SCI_LINEENDDISPLAY: + case SCI_LINEENDDISPLAYEXTEND: + case SCI_LINEENDWRAP: + case SCI_LINEENDWRAPEXTEND: + return HorizontalMove(iMessage); + case SCI_DOCUMENTSTART: MovePositionTo(0); SetLastXChosen(); @@ -3381,38 +3700,6 @@ int Editor::KeyCommand(unsigned int iMessage) { case SCI_FORMFEED: AddChar('\f'); break; - case SCI_VCHOME: - MovePositionTo(pdoc->VCHomePosition(sel.MainCaret())); - SetLastXChosen(); - break; - case SCI_VCHOMEEXTEND: - MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream); - SetLastXChosen(); - break; - case SCI_VCHOMERECTEXTEND: - MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle); - SetLastXChosen(); - break; - case SCI_VCHOMEWRAP: { - SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); - SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); - if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos)) - homePos = viewLineStart; - - MovePositionTo(homePos); - SetLastXChosen(); - } - break; - case SCI_VCHOMEWRAPEXTEND: { - SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); - SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); - if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos)) - homePos = viewLineStart; - - MovePositionTo(homePos, Selection::selStream); - SetLastXChosen(); - } - break; case SCI_ZOOMIN: if (vs.zoomLevel < 20) { vs.zoomLevel++; @@ -3427,46 +3714,14 @@ int Editor::KeyCommand(unsigned int iMessage) { NotifyZoom(); } break; - case SCI_DELWORDLEFT: { - int startWord = pdoc->NextWordStart(sel.MainCaret(), -1); - pdoc->DeleteChars(startWord, sel.MainCaret() - startWord); - sel.RangeMain().ClearVirtualSpace(); - SetLastXChosen(); - } - break; - case SCI_DELWORDRIGHT: { - UndoGroup ug(pdoc); - InvalidateWholeSelection(); - sel.RangeMain().caret = SelectionPosition( - InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); - sel.RangeMain().anchor = sel.RangeMain().caret; - int endWord = pdoc->NextWordStart(sel.MainCaret(), 1); - pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret()); - } - break; - case SCI_DELWORDRIGHTEND: { - UndoGroup ug(pdoc); - InvalidateWholeSelection(); - sel.RangeMain().caret = SelectionPosition( - InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); - int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1); - pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret()); - } - break; - case SCI_DELLINELEFT: { - int line = pdoc->LineFromPosition(sel.MainCaret()); - int start = pdoc->LineStart(line); - pdoc->DeleteChars(start, sel.MainCaret() - start); - sel.RangeMain().ClearVirtualSpace(); - SetLastXChosen(); - } - break; - case SCI_DELLINERIGHT: { - int line = pdoc->LineFromPosition(sel.MainCaret()); - int end = pdoc->LineEnd(line); - pdoc->DeleteChars(sel.MainCaret(), end - sel.MainCaret()); - } - break; + + case SCI_DELWORDLEFT: + case SCI_DELWORDRIGHT: + case SCI_DELWORDRIGHTEND: + case SCI_DELLINELEFT: + case SCI_DELLINERIGHT: + return DelWordOrLine(iMessage); + case SCI_LINECOPY: { int lineStart = pdoc->LineFromPosition(SelectionStart().Position()); int lineEnd = pdoc->LineFromPosition(SelectionEnd().Position()); @@ -3506,62 +3761,6 @@ int Editor::KeyCommand(unsigned int iMessage) { case SCI_UPPERCASE: ChangeCaseOfSelection(cmUpper); break; - case SCI_WORDPARTLEFT: - MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1)); - SetLastXChosen(); - break; - case SCI_WORDPARTLEFTEXTEND: - MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream); - SetLastXChosen(); - break; - case SCI_WORDPARTRIGHT: - MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1)); - SetLastXChosen(); - break; - case SCI_WORDPARTRIGHTEXTEND: - MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream); - SetLastXChosen(); - break; - case SCI_HOMEDISPLAY: - MovePositionTo(MovePositionSoVisible( - StartEndDisplayLine(sel.MainCaret(), true), -1)); - SetLastXChosen(); - break; - case SCI_VCHOMEDISPLAY: { - SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); - SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); - if (viewLineStart > homePos) - homePos = viewLineStart; - - MovePositionTo(homePos); - SetLastXChosen(); - } - break; - case SCI_HOMEDISPLAYEXTEND: - MovePositionTo(MovePositionSoVisible( - StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream); - SetLastXChosen(); - break; - case SCI_VCHOMEDISPLAYEXTEND: { - SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); - SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); - if (viewLineStart > homePos) - homePos = viewLineStart; - - MovePositionTo(homePos, Selection::selStream); - SetLastXChosen(); - } - break; - case SCI_LINEENDDISPLAY: - MovePositionTo(MovePositionSoVisible( - StartEndDisplayLine(sel.MainCaret(), false), 1)); - SetLastXChosen(); - break; - case SCI_LINEENDDISPLAYEXTEND: - MovePositionTo(MovePositionSoVisible( - StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream); - SetLastXChosen(); - break; case SCI_SCROLLTOSTART: ScrollTo(0); break; diff --git a/src/Editor.h b/src/Editor.h index 3301c4b05..fdc86f9f6 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -326,6 +326,7 @@ protected: // ScintillaBase subclass needs access to much of Editor bool SelectionContainsProtected(); int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const; SelectionPosition MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd=true) const; + void MovedCaret(SelectionPosition newPos, SelectionPosition previousPos, bool ensureVisible); void MovePositionTo(SelectionPosition newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true); void MovePositionTo(int newPos, Selection::selTypes selt=Selection::noSel, bool ensureVisible=true); SelectionPosition MovePositionSoVisible(SelectionPosition pos, int moveDir); @@ -458,9 +459,15 @@ protected: // ScintillaBase subclass needs access to much of Editor void Duplicate(bool forLine); virtual void CancelModes(); void NewLine(); + SelectionPosition PositionUpOrDown(SelectionPosition spStart, int direction, int lastX); void CursorUpOrDown(int direction, Selection::selTypes selt); void ParaUpOrDown(int direction, Selection::selTypes selt); int StartEndDisplayLine(int pos, bool start); + int VCHomeDisplayPosition(int position); + int VCHomeWrapPosition(int position); + int LineEndWrapPosition(int position); + int HorizontalMove(unsigned int iMessage); + int DelWordOrLine(unsigned int iMessage); virtual int KeyCommand(unsigned int iMessage); virtual int KeyDefault(int /* key */, int /*modifiers*/); int KeyDownWithModifiers(int key, int modifiers, bool *consumed); diff --git a/src/Selection.cxx b/src/Selection.cxx index f4308b130..0a7c15c1a 100644 --- a/src/Selection.cxx +++ b/src/Selection.cxx @@ -311,6 +311,14 @@ void Selection::TrimSelection(SelectionRange range) { } } +void Selection::TrimOtherSelections(size_t r, SelectionRange range) { + for (size_t i = 0; i<ranges.size(); ++i) { + if (i != r) { + ranges[i].Trim(range); + } + } +} + void Selection::SetSelection(SelectionRange range) { ranges.clear(); ranges.push_back(range); diff --git a/src/Selection.h b/src/Selection.h index 166e3fa71..22c01beff 100644 --- a/src/Selection.h +++ b/src/Selection.h @@ -168,6 +168,7 @@ public: int Length() const; void MovePositions(bool insertion, int startChange, int length); void TrimSelection(SelectionRange range); + void TrimOtherSelections(size_t r, SelectionRange range); void SetSelection(SelectionRange range); void AddSelection(SelectionRange range); void AddSelectionWithoutTrim(SelectionRange range); |