1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
20 #include <forward_list>
27 #include "Scintilla.h"
29 #include "StringCopy.h"
31 #include "UniqueString.h"
32 #include "SplitVector.h"
33 #include "Partitioning.h"
34 #include "RunStyles.h"
35 #include "ContractionState.h"
36 #include "CellBuffer.h"
39 #include "Indicator.h"
41 #include "LineMarker.h"
43 #include "ViewStyle.h"
44 #include "CharClassify.h"
45 #include "Decoration.h"
46 #include "CaseFolder.h"
48 #include "UniConversion.h"
49 #include "Selection.h"
50 #include "PositionCache.h"
51 #include "EditModel.h"
52 #include "MarginView.h"
57 using namespace Scintilla
;
61 return whether this modification represents an operation that
62 may reasonably be deferred (not done now OR [possibly] at all)
64 static bool CanDeferToLastStep(const DocModification
&mh
) {
65 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
66 return true; // CAN skip
67 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
68 return false; // MUST do
69 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
70 return true; // CAN skip
71 return false; // PRESUMABLY must do
74 static bool CanEliminate(const DocModification
&mh
) {
76 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
80 return whether this modification represents the FINAL step
81 in a [possibly lengthy] multi-step Undo/Redo sequence
83 static bool IsLastStep(const DocModification
&mh
) {
85 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
86 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
87 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
88 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
92 ticking(false), ticksToWait(0), tickerID(0) {}
95 state(false), idlerID(0) {}
97 static inline bool IsAllSpacesOrTabs(const char *s
, unsigned int len
) {
98 for (unsigned int i
= 0; i
< len
; i
++) {
99 // This is safe because IsSpaceOrTab() will return false for null terminators
100 if (!IsSpaceOrTab(s
[i
]))
111 technology
= SC_TECHNOLOGY_DEFAULT
;
112 scaleRGBAImage
= 100.0f
;
114 cursorMode
= SC_CURSORNORMAL
;
118 mouseDownCaptures
= true;
119 mouseWheelCaptures
= true;
122 doubleClickCloseThreshold
= Point(3, 3);
123 dwellDelay
= SC_TIME_FOREVER
;
124 ticksToDwell
= SC_TIME_FOREVER
;
129 dropWentOutside
= false;
130 posDrop
= SelectionPosition(Sci::invalidPosition
);
131 hotSpotClickPos
= INVALID_POSITION
;
132 selectionType
= selChar
;
136 originalAnchorPos
= 0;
137 wordSelectAnchorStartPos
= 0;
138 wordSelectAnchorEndPos
= 0;
139 wordSelectInitialCaretPos
= -1;
141 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
144 caretYPolicy
= CARET_EVEN
;
153 horizontalScrollBarVisible
= true;
155 verticalScrollBarVisible
= true;
156 endAtLastLine
= true;
157 caretSticky
= SC_CARETSTICKY_OFF
;
158 marginOptions
= SC_MARGINOPTION_NONE
;
159 mouseSelectionRectangularSwitch
= false;
160 multipleSelection
= false;
161 additionalSelectionTyping
= false;
162 multiPasteMode
= SC_MULTIPASTE_ONCE
;
163 virtualSpaceOptions
= SCVS_NONE
;
172 lengthForEncode
= -1;
175 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
177 paintState
= notPainting
;
178 paintAbandonedByStyling
= false;
179 paintingAllText
= false;
180 willRedrawAll
= false;
181 idleStyling
= SC_IDLESTYLING_NONE
;
182 needIdleStyling
= false;
184 modEventMask
= SC_MODEVENTMASKALL
;
186 pdoc
->AddWatcher(this, 0);
188 recordingMacro
= false;
191 convertPastes
= true;
193 SetRepresentations();
197 pdoc
->RemoveWatcher(this, 0);
201 void Editor::Finalise() {
206 void Editor::SetRepresentations() {
210 const char *reps
[] = {
211 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
212 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
213 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
214 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
216 for (size_t j
=0; j
< ELEMENTS(reps
); j
++) {
217 char c
[2] = { static_cast<char>(j
), 0 };
218 reprs
.SetRepresentation(c
, reps
[j
]);
222 // As well as Unicode mode, ISO-8859-1 should use these
223 if (IsUnicodeMode()) {
224 const char *repsC1
[] = {
225 "PAD", "HOP", "BPH", "NBH", "IND", "NEL", "SSA", "ESA",
226 "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
227 "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
228 "SOS", "SGCI", "SCI", "CSI", "ST", "OSC", "PM", "APC"
230 for (size_t j
=0; j
< ELEMENTS(repsC1
); j
++) {
231 char c1
[3] = { '\xc2', static_cast<char>(0x80+j
), 0 };
232 reprs
.SetRepresentation(c1
, repsC1
[j
]);
234 reprs
.SetRepresentation("\xe2\x80\xa8", "LS");
235 reprs
.SetRepresentation("\xe2\x80\xa9", "PS");
238 // UTF-8 invalid bytes
239 if (IsUnicodeMode()) {
240 for (int k
=0x80; k
< 0x100; k
++) {
241 char hiByte
[2] = { static_cast<char>(k
), 0 };
243 sprintf(hexits
, "x%2X", k
);
244 reprs
.SetRepresentation(hiByte
, hexits
);
249 void Editor::DropGraphics(bool freeObjects
) {
250 marginView
.DropGraphics(freeObjects
);
251 view
.DropGraphics(freeObjects
);
254 void Editor::AllocateGraphics() {
255 marginView
.AllocateGraphics(vs
);
256 view
.AllocateGraphics(vs
);
259 void Editor::InvalidateStyleData() {
261 vs
.technology
= technology
;
264 view
.llc
.Invalidate(LineLayout::llInvalid
);
265 view
.posCache
.Clear();
268 void Editor::InvalidateStyleRedraw() {
270 InvalidateStyleData();
274 void Editor::RefreshStyleData() {
277 AutoSurface
surface(this);
279 vs
.Refresh(*surface
, pdoc
->tabInChars
);
282 SetRectangularRange();
286 Point
Editor::GetVisibleOriginInMain() const {
290 PointDocument
Editor::DocumentPointFromView(Point ptView
) const {
291 PointDocument
ptDocument(ptView
);
292 if (wMargin
.GetID()) {
293 const Point ptOrigin
= GetVisibleOriginInMain();
294 ptDocument
.x
+= ptOrigin
.x
;
295 ptDocument
.y
+= ptOrigin
.y
;
297 ptDocument
.x
+= xOffset
;
298 ptDocument
.y
+= topLine
* vs
.lineHeight
;
303 Sci::Line
Editor::TopLineOfMain() const {
310 PRectangle
Editor::GetClientRectangle() const {
312 return win
.GetClientPosition();
315 PRectangle
Editor::GetClientDrawingRectangle() {
316 return GetClientRectangle();
319 PRectangle
Editor::GetTextRectangle() const {
320 PRectangle rc
= GetClientRectangle();
321 rc
.left
+= vs
.textStart
;
322 rc
.right
-= vs
.rightMarginWidth
;
326 Sci::Line
Editor::LinesOnScreen() const {
327 const PRectangle rcClient
= GetClientRectangle();
328 const int htClient
= static_cast<int>(rcClient
.bottom
- rcClient
.top
);
329 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
330 return htClient
/ vs
.lineHeight
;
333 Sci::Line
Editor::LinesToScroll() const {
334 Sci::Line retVal
= LinesOnScreen() - 1;
341 Sci::Line
Editor::MaxScrollPos() const {
342 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
343 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
344 Sci::Line retVal
= cs
.LinesDisplayed();
346 retVal
-= LinesOnScreen();
357 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
358 if (sp
.Position() < 0) {
359 return SelectionPosition(0);
360 } else if (sp
.Position() > pdoc
->Length()) {
361 return SelectionPosition(pdoc
->Length());
363 // If not at end of line then set offset to 0
364 if (!pdoc
->IsLineEndPosition(sp
.Position()))
365 sp
.SetVirtualSpace(0);
370 Point
Editor::LocationFromPosition(SelectionPosition pos
, PointEnd pe
) {
372 AutoSurface
surface(this);
373 return view
.LocationFromPosition(surface
, *this, pos
, topLine
, vs
, pe
);
376 Point
Editor::LocationFromPosition(Sci::Position pos
, PointEnd pe
) {
377 return LocationFromPosition(SelectionPosition(pos
), pe
);
380 int Editor::XFromPosition(Sci::Position pos
) {
381 Point pt
= LocationFromPosition(pos
);
382 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
385 int Editor::XFromPosition(SelectionPosition sp
) {
386 Point pt
= LocationFromPosition(sp
);
387 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
390 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
392 AutoSurface
surface(this);
394 if (canReturnInvalid
) {
395 PRectangle rcClient
= GetTextRectangle();
396 // May be in scroll view coordinates so translate back to main view
397 Point ptOrigin
= GetVisibleOriginInMain();
398 rcClient
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
399 if (!rcClient
.Contains(pt
))
400 return SelectionPosition(INVALID_POSITION
);
401 if (pt
.x
< vs
.textStart
)
402 return SelectionPosition(INVALID_POSITION
);
404 return SelectionPosition(INVALID_POSITION
);
406 PointDocument ptdoc
= DocumentPointFromView(pt
);
407 return view
.SPositionFromLocation(surface
, *this, ptdoc
, canReturnInvalid
, charPosition
, virtualSpace
, vs
);
410 Sci::Position
Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
411 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
415 * Find the document position corresponding to an x coordinate on a particular document line.
416 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
417 * This method is used for rectangular selections and does not work on wrapped lines.
419 SelectionPosition
Editor::SPositionFromLineX(Sci::Line lineDoc
, int x
) {
421 if (lineDoc
>= pdoc
->LinesTotal())
422 return SelectionPosition(pdoc
->Length());
423 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
424 AutoSurface
surface(this);
425 return view
.SPositionFromLineX(surface
, *this, lineDoc
, x
, vs
);
428 Sci::Position
Editor::PositionFromLineX(Sci::Line lineDoc
, int x
) {
429 return SPositionFromLineX(lineDoc
, x
).Position();
432 Sci::Line
Editor::LineFromLocation(Point pt
) const {
433 return cs
.DocFromDisplay(static_cast<int>(pt
.y
) / vs
.lineHeight
+ topLine
);
436 void Editor::SetTopLine(Sci::Line topLineNew
) {
437 if ((topLine
!= topLineNew
) && (topLineNew
>= 0)) {
438 topLine
= topLineNew
;
439 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
441 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
445 * If painting then abandon the painting because a wider redraw is needed.
446 * @return true if calling code should stop drawing.
448 bool Editor::AbandonPaint() {
449 if ((paintState
== painting
) && !paintingAllText
) {
450 paintState
= paintAbandoned
;
452 return paintState
== paintAbandoned
;
455 void Editor::RedrawRect(PRectangle rc
) {
456 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
458 // Clip the redraw rectangle into the client area
459 PRectangle rcClient
= GetClientRectangle();
460 if (rc
.top
< rcClient
.top
)
461 rc
.top
= rcClient
.top
;
462 if (rc
.bottom
> rcClient
.bottom
)
463 rc
.bottom
= rcClient
.bottom
;
464 if (rc
.left
< rcClient
.left
)
465 rc
.left
= rcClient
.left
;
466 if (rc
.right
> rcClient
.right
)
467 rc
.right
= rcClient
.right
;
469 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
470 wMain
.InvalidateRectangle(rc
);
474 void Editor::DiscardOverdraw() {
475 // Overridden on platforms that may draw outside visible area.
478 void Editor::Redraw() {
479 //Platform::DebugPrintf("Redraw all\n");
480 PRectangle rcClient
= GetClientRectangle();
481 wMain
.InvalidateRectangle(rcClient
);
483 wMargin
.InvalidateAll();
484 //wMain.InvalidateAll();
487 void Editor::RedrawSelMargin(Sci::Line line
, bool allAfter
) {
488 const bool markersInText
= vs
.maskInLine
|| vs
.maskDrawInText
;
489 if (!wMargin
.GetID() || markersInText
) { // May affect text area so may need to abandon and retry
490 if (AbandonPaint()) {
494 if (wMargin
.GetID() && markersInText
) {
498 PRectangle rcMarkers
= GetClientRectangle();
499 if (!markersInText
) {
500 // Normal case: just draw the margin
501 rcMarkers
.right
= rcMarkers
.left
+ vs
.fixedColumnWidth
;
504 PRectangle rcLine
= RectangleFromRange(Range(pdoc
->LineStart(line
)), 0);
506 // Inflate line rectangle if there are image markers with height larger than line height
507 if (vs
.largestMarkerHeight
> vs
.lineHeight
) {
508 int delta
= (vs
.largestMarkerHeight
- vs
.lineHeight
+ 1) / 2;
510 rcLine
.bottom
+= delta
;
511 if (rcLine
.top
< rcMarkers
.top
)
512 rcLine
.top
= rcMarkers
.top
;
513 if (rcLine
.bottom
> rcMarkers
.bottom
)
514 rcLine
.bottom
= rcMarkers
.bottom
;
517 rcMarkers
.top
= rcLine
.top
;
519 rcMarkers
.bottom
= rcLine
.bottom
;
520 if (rcMarkers
.Empty())
523 if (wMargin
.GetID()) {
524 Point ptOrigin
= GetVisibleOriginInMain();
525 rcMarkers
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
526 wMargin
.InvalidateRectangle(rcMarkers
);
528 wMain
.InvalidateRectangle(rcMarkers
);
532 PRectangle
Editor::RectangleFromRange(Range r
, int overlap
) {
533 const Sci::Line minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.First()));
534 const Sci::Line maxLine
= cs
.DisplayLastFromDoc(pdoc
->LineFromPosition(r
.Last()));
535 const PRectangle rcClientDrawing
= GetClientDrawingRectangle();
537 const int leftTextOverlap
= ((xOffset
== 0) && (vs
.leftMarginWidth
> 0)) ? 1 : 0;
538 rc
.left
= static_cast<XYPOSITION
>(vs
.textStart
- leftTextOverlap
);
539 rc
.top
= static_cast<XYPOSITION
>((minLine
- TopLineOfMain()) * vs
.lineHeight
- overlap
);
540 if (rc
.top
< rcClientDrawing
.top
)
541 rc
.top
= rcClientDrawing
.top
;
542 // Extend to right of prepared area if any to prevent artifacts from caret line highlight
543 rc
.right
= rcClientDrawing
.right
;
544 rc
.bottom
= static_cast<XYPOSITION
>((maxLine
- TopLineOfMain() + 1) * vs
.lineHeight
+ overlap
);
549 void Editor::InvalidateRange(Sci::Position start
, Sci::Position end
) {
550 RedrawRect(RectangleFromRange(Range(start
, end
), view
.LinesOverlap() ? vs
.lineOverlap
: 0));
553 Sci::Position
Editor::CurrentPosition() const {
554 return sel
.MainCaret();
557 bool Editor::SelectionEmpty() const {
561 SelectionPosition
Editor::SelectionStart() {
562 return sel
.RangeMain().Start();
565 SelectionPosition
Editor::SelectionEnd() {
566 return sel
.RangeMain().End();
569 void Editor::SetRectangularRange() {
570 if (sel
.IsRectangular()) {
571 const int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
572 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
573 if (sel
.selType
== Selection::selThin
) {
576 const Sci::Line lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
577 const Sci::Line lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
578 const int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
579 for (Sci::Line line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
580 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
581 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
582 range
.ClearVirtualSpace();
583 if (line
== lineAnchorRect
)
584 sel
.SetSelection(range
);
586 sel
.AddSelectionWithoutTrim(range
);
591 void Editor::ThinRectangularRange() {
592 if (sel
.IsRectangular()) {
593 sel
.selType
= Selection::selThin
;
594 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
595 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
597 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
599 SetRectangularRange();
603 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
604 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
605 invalidateWholeSelection
= true;
607 Sci::Position firstAffected
= std::min(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
608 // +1 for lastAffected ensures caret repainted
609 Sci::Position lastAffected
= std::max(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
610 lastAffected
= std::max(lastAffected
, sel
.RangeMain().End().Position());
611 if (invalidateWholeSelection
) {
612 for (size_t r
=0; r
<sel
.Count(); r
++) {
613 firstAffected
= std::min(firstAffected
, sel
.Range(r
).caret
.Position());
614 firstAffected
= std::min(firstAffected
, sel
.Range(r
).anchor
.Position());
615 lastAffected
= std::max(lastAffected
, sel
.Range(r
).caret
.Position()+1);
616 lastAffected
= std::max(lastAffected
, sel
.Range(r
).anchor
.Position());
619 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
620 InvalidateRange(firstAffected
, lastAffected
);
623 void Editor::InvalidateWholeSelection() {
624 InvalidateSelection(sel
.RangeMain(), true);
627 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
628 currentPos_
= ClampPositionIntoDocument(currentPos_
);
629 anchor_
= ClampPositionIntoDocument(anchor_
);
630 Sci::Line currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
631 /* For Line selection - ensure the anchor and caret are always
632 at the beginning and end of the region lines. */
633 if (sel
.selType
== Selection::selLines
) {
634 if (currentPos_
> anchor_
) {
635 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
636 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
638 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
639 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
642 SelectionRange
rangeNew(currentPos_
, anchor_
);
643 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
644 InvalidateSelection(rangeNew
);
646 sel
.RangeMain() = rangeNew
;
647 SetRectangularRange();
649 SetHoverIndicatorPosition(sel
.MainCaret());
651 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
654 QueueIdleWork(WorkNeeded::workUpdateUI
);
657 void Editor::SetSelection(Sci::Position currentPos_
, Sci::Position anchor_
) {
658 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
661 // Just move the caret on the main selection
662 void Editor::SetSelection(SelectionPosition currentPos_
) {
663 currentPos_
= ClampPositionIntoDocument(currentPos_
);
664 Sci::Line currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
665 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
666 InvalidateSelection(SelectionRange(currentPos_
));
668 if (sel
.IsRectangular()) {
670 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
671 SetRectangularRange();
674 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
677 SetHoverIndicatorPosition(sel
.MainCaret());
679 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
682 QueueIdleWork(WorkNeeded::workUpdateUI
);
685 void Editor::SetSelection(int currentPos_
) {
686 SetSelection(SelectionPosition(currentPos_
));
689 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
690 Sci::Line currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
691 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
692 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
693 InvalidateSelection(rangeNew
);
696 sel
.RangeMain() = rangeNew
;
697 SetRectangularRange();
699 SetHoverIndicatorPosition(sel
.MainCaret());
701 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
704 QueueIdleWork(WorkNeeded::workUpdateUI
);
707 void Editor::SetEmptySelection(Sci::Position currentPos_
) {
708 SetEmptySelection(SelectionPosition(currentPos_
));
711 void Editor::MultipleSelectAdd(AddNumber addNumber
) {
712 if (SelectionEmpty() || !multipleSelection
) {
713 // Select word at caret
714 const Sci::Position startWord
= pdoc
->ExtendWordSelect(sel
.MainCaret(), -1, true);
715 const Sci::Position endWord
= pdoc
->ExtendWordSelect(startWord
, 1, true);
716 TrimAndSetSelection(endWord
, startWord
);
720 if (!pdoc
->HasCaseFolder())
721 pdoc
->SetCaseFolder(CaseFolderForEncoding());
723 const Range
rangeMainSelection(sel
.RangeMain().Start().Position(), sel
.RangeMain().End().Position());
724 const std::string selectedText
= RangeText(rangeMainSelection
.start
, rangeMainSelection
.end
);
726 const Range
rangeTarget(targetStart
, targetEnd
);
727 std::vector
<Range
> searchRanges
;
728 // Search should be over the target range excluding the current selection so
729 // may need to search 2 ranges, after the selection then before the selection.
730 if (rangeTarget
.Overlaps(rangeMainSelection
)) {
731 // Common case is that the selection is completely within the target but
732 // may also have overlap at start or end.
733 if (rangeMainSelection
.end
< rangeTarget
.end
)
734 searchRanges
.push_back(Range(rangeMainSelection
.end
, rangeTarget
.end
));
735 if (rangeTarget
.start
< rangeMainSelection
.start
)
736 searchRanges
.push_back(Range(rangeTarget
.start
, rangeMainSelection
.start
));
739 searchRanges
.push_back(rangeTarget
);
742 for (std::vector
<Range
>::const_iterator it
= searchRanges
.begin(); it
!= searchRanges
.end(); ++it
) {
743 Sci::Position searchStart
= it
->start
;
744 const Sci::Position searchEnd
= it
->end
;
746 Sci::Position lengthFound
= static_cast<Sci::Position
>(selectedText
.length());
747 Sci::Position pos
= static_cast<Sci::Position
>(pdoc
->FindText(searchStart
, searchEnd
,
748 selectedText
.c_str(), searchFlags
, &lengthFound
));
750 sel
.AddSelection(SelectionRange(pos
+ lengthFound
, pos
));
751 ScrollRange(sel
.RangeMain());
753 if (addNumber
== addOne
)
755 searchStart
= pos
+ lengthFound
;
764 bool Editor::RangeContainsProtected(Sci::Position start
, Sci::Position end
) const {
765 if (vs
.ProtectionActive()) {
767 Sci::Position t
= start
;
771 for (Sci::Position pos
= start
; pos
< end
; pos
++) {
772 if (vs
.styles
[pdoc
->StyleIndexAt(pos
)].IsProtected())
779 bool Editor::SelectionContainsProtected() {
780 for (size_t r
=0; r
<sel
.Count(); r
++) {
781 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
782 sel
.Range(r
).End().Position())) {
790 * Asks document to find a good position and then moves out of any invisible positions.
792 Sci::Position
Editor::MovePositionOutsideChar(Sci::Position pos
, Sci::Position moveDir
, bool checkLineEnd
) const {
793 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
796 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, Sci::Position moveDir
, bool checkLineEnd
) const {
797 Sci::Position posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
798 if (posMoved
!= pos
.Position())
799 pos
.SetPosition(posMoved
);
800 if (vs
.ProtectionActive()) {
802 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleIndexAt(pos
.Position() - 1)].IsProtected()) {
803 while ((pos
.Position() < pdoc
->Length()) &&
804 (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position())].IsProtected()))
807 } else if (moveDir
< 0) {
808 if (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position())].IsProtected()) {
809 while ((pos
.Position() > 0) &&
810 (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position() - 1)].IsProtected()))
818 void Editor::MovedCaret(SelectionPosition newPos
, SelectionPosition previousPos
, bool ensureVisible
) {
819 const Sci::Line currentLine
= pdoc
->LineFromPosition(newPos
.Position());
821 // In case in need of wrapping to ensure DisplayFromDoc works.
822 if (currentLine
>= wrapPending
.start
)
823 WrapLines(WrapScope::wsAll
);
824 XYScrollPosition newXY
= XYScrollToMakeVisible(
825 SelectionRange(posDrag
.IsValid() ? posDrag
: newPos
), xysDefault
);
826 if (previousPos
.IsValid() && (newXY
.xOffset
== xOffset
)) {
827 // simple vertical scroll then invalidate
828 ScrollTo(newXY
.topLine
);
829 InvalidateSelection(SelectionRange(previousPos
), true);
835 ShowCaretAtCurrentPosition();
839 SetHoverIndicatorPosition(sel
.MainCaret());
840 QueueIdleWork(WorkNeeded::workUpdateUI
);
842 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
847 void Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
848 const SelectionPosition spCaret
= ((sel
.Count() == 1) && sel
.Empty()) ?
849 sel
.Last() : SelectionPosition(INVALID_POSITION
);
851 Sci::Position delta
= newPos
.Position() - sel
.MainCaret();
852 newPos
= ClampPositionIntoDocument(newPos
);
853 newPos
= MovePositionOutsideChar(newPos
, delta
);
854 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
855 // Can't turn into multiple selection so clear additional selections
856 InvalidateSelection(SelectionRange(newPos
), true);
857 sel
.DropAdditionalRanges();
859 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
860 // Switching to rectangular
861 InvalidateSelection(sel
.RangeMain(), false);
862 SelectionRange rangeMain
= sel
.RangeMain();
864 sel
.Rectangular() = rangeMain
;
866 if (selt
!= Selection::noSel
) {
869 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
870 SetSelection(newPos
);
872 SetEmptySelection(newPos
);
875 MovedCaret(newPos
, spCaret
, ensureVisible
);
878 void Editor::MovePositionTo(Sci::Position newPos
, Selection::selTypes selt
, bool ensureVisible
) {
879 MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
882 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
883 pos
= ClampPositionIntoDocument(pos
);
884 pos
= MovePositionOutsideChar(pos
, moveDir
);
885 Sci::Line lineDoc
= pdoc
->LineFromPosition(pos
.Position());
886 if (cs
.GetVisible(lineDoc
)) {
889 Sci::Line lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
891 // lineDisplay is already line before fold as lines in fold use display line of line after fold
892 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
893 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
895 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
896 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
901 SelectionPosition
Editor::MovePositionSoVisible(Sci::Position pos
, int moveDir
) {
902 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
905 Point
Editor::PointMainCaret() {
906 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
910 * Choose the x position that the caret will try to stick to
911 * as it moves up and down.
913 void Editor::SetLastXChosen() {
914 Point pt
= PointMainCaret();
915 lastXChosen
= static_cast<Sci::Position
>(pt
.x
) + xOffset
;
918 void Editor::ScrollTo(Sci::Line line
, bool moveThumb
) {
919 const Sci::Line topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
920 if (topLineNew
!= topLine
) {
921 // Try to optimise small scrolls
923 const Sci::Line linesToMove
= topLine
- topLineNew
;
924 const bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
925 willRedrawAll
= !performBlit
;
927 SetTopLine(topLineNew
);
928 // Optimize by styling the view as this will invalidate any needed area
929 // which could abort the initial paint if discovered later.
930 StyleAreaBounded(GetClientRectangle(), true);
932 // Perform redraw rather than scroll if many lines would be redrawn anyway.
934 ScrollText(linesToMove
);
938 willRedrawAll
= false;
943 SetVerticalScrollPos();
948 void Editor::ScrollText(Sci::Line
/* linesToMove */) {
949 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
953 void Editor::HorizontalScrollTo(int xPos
) {
954 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
957 if (!Wrapping() && (xOffset
!= xPos
)) {
959 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
960 SetHorizontalScrollPos();
961 RedrawRect(GetClientRectangle());
965 void Editor::VerticalCentreCaret() {
966 const Sci::Line lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
967 const Sci::Line lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
968 const Sci::Line newTop
= lineDisplay
- (LinesOnScreen() / 2);
969 if (topLine
!= newTop
) {
970 SetTopLine(newTop
> 0 ? newTop
: 0);
971 RedrawRect(GetClientRectangle());
975 // Avoid 64 bit compiler warnings.
976 // Scintilla does not support text buffers larger than 2**31
977 static int istrlen(const char *s
) {
978 return static_cast<int>(s
? strlen(s
) : 0);
981 void Editor::MoveSelectedLines(int lineDelta
) {
983 // if selection doesn't start at the beginning of the line, set the new start
984 Sci::Position selectionStart
= SelectionStart().Position();
985 const Sci::Line startLine
= pdoc
->LineFromPosition(selectionStart
);
986 const Sci::Position beginningOfStartLine
= pdoc
->LineStart(startLine
);
987 selectionStart
= beginningOfStartLine
;
989 // if selection doesn't end at the beginning of a line greater than that of the start,
990 // then set it at the beginning of the next one
991 Sci::Position selectionEnd
= SelectionEnd().Position();
992 const Sci::Line endLine
= pdoc
->LineFromPosition(selectionEnd
);
993 const Sci::Position beginningOfEndLine
= pdoc
->LineStart(endLine
);
994 bool appendEol
= false;
995 if (selectionEnd
> beginningOfEndLine
996 || selectionStart
== selectionEnd
) {
997 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
998 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
1001 // if there's nowhere for the selection to move
1002 // (i.e. at the beginning going up or at the end going down),
1003 // stop it right there!
1004 if ((selectionStart
== 0 && lineDelta
< 0)
1005 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
1006 || selectionStart
== selectionEnd
) {
1012 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
1013 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
1015 selectionEnd
= CurrentPosition();
1017 SetSelection(selectionStart
, selectionEnd
);
1019 SelectionText selectedText
;
1020 CopySelectionRange(&selectedText
);
1022 Sci::Position selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
1023 Point currentLocation
= LocationFromPosition(CurrentPosition());
1024 Sci::Line currentLine
= LineFromLocation(currentLocation
);
1027 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
1030 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1031 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
1032 pdoc
->InsertString(pdoc
->Length(), eol
, istrlen(eol
));
1033 GoToLine(currentLine
+ lineDelta
);
1035 selectionLength
= pdoc
->InsertString(CurrentPosition(), selectedText
.Data(), selectionLength
);
1037 const Sci::Position lengthInserted
= pdoc
->InsertString(CurrentPosition() + selectionLength
, eol
, istrlen(eol
));
1038 selectionLength
+= lengthInserted
;
1040 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
1043 void Editor::MoveSelectedLinesUp() {
1044 MoveSelectedLines(-1);
1047 void Editor::MoveSelectedLinesDown() {
1048 MoveSelectedLines(1);
1051 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1052 PRectangle rcClient
= GetTextRectangle();
1053 Point pt
= PointMainCaret();
1054 if (pt
.y
< rcClient
.top
) {
1055 MovePositionTo(SPositionFromLocation(
1056 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
)),
1057 false, false, UserVirtualSpace()),
1058 Selection::noSel
, ensureVisible
);
1059 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1060 Sci::Position yOfLastLineFullyDisplayed
= static_cast<Sci::Position
>(rcClient
.top
) + (LinesOnScreen() - 1) * vs
.lineHeight
;
1061 MovePositionTo(SPositionFromLocation(
1062 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
) + yOfLastLineFullyDisplayed
),
1063 false, false, UserVirtualSpace()),
1064 Selection::noSel
, ensureVisible
);
1068 Sci::Line
Editor::DisplayFromPosition(Sci::Position pos
) {
1069 AutoSurface
surface(this);
1070 return view
.DisplayFromPosition(surface
, *this, pos
, vs
);
1074 * Ensure the caret is reasonably visible in context.
1076 Caret policy in SciTE
1078 If slop is set, we can define a slop value.
1079 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1080 This zone is defined as a number of pixels near the vertical margins,
1081 and as a number of lines near the horizontal margins.
1082 By keeping the caret away from the edges, it is seen within its context,
1083 so it is likely that the identifier that the caret is on can be completely seen,
1084 and that the current line is seen with some of the lines following it which are
1085 often dependent on that line.
1087 If strict is set, the policy is enforced... strictly.
1088 The caret is centred on the display if slop is not set,
1089 and cannot go in the UZ if slop is set.
1091 If jumps is set, the display is moved more energetically
1092 so the caret can move in the same direction longer before the policy is applied again.
1093 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1095 If even is not set, instead of having symmetrical UZs,
1096 the left and bottom UZs are extended up to right and top UZs respectively.
1097 This way, we favour the displaying of useful information: the beginning of lines,
1098 where most code reside, and the lines after the caret, eg. the body of a function.
1101 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1102 | | | | | visibility or going into the UZ) display is...
1103 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1104 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1105 0 | 0 | 0 | 1 | Yes | moved by one position
1106 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1107 0 | 0 | 1 | 1 | Yes | centred on the caret
1108 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1109 0 | 1 | - | 1 | No, caret is always centred | -
1110 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1111 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1112 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1113 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1114 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1115 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1116 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1119 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const SelectionRange
&range
, const XYScrollOptions options
) {
1120 const PRectangle rcClient
= GetTextRectangle();
1121 Point pt
= LocationFromPosition(range
.caret
);
1122 Point ptAnchor
= LocationFromPosition(range
.anchor
);
1123 const Point ptOrigin
= GetVisibleOriginInMain();
1126 ptAnchor
.x
+= ptOrigin
.x
;
1127 ptAnchor
.y
+= ptOrigin
.y
;
1128 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1130 XYScrollPosition
newXY(xOffset
, topLine
);
1131 if (rcClient
.Empty()) {
1135 // Vertical positioning
1136 if ((options
& xysVertical
) && (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1137 const Sci::Line lineCaret
= DisplayFromPosition(range
.caret
.Position());
1138 const Sci::Line linesOnScreen
= LinesOnScreen();
1139 const Sci::Line halfScreen
= std::max(linesOnScreen
- 1, 2) / 2;
1140 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1141 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1142 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1143 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1145 // It should be possible to scroll the window to show the caret,
1146 // but this fails to remove the caret on GTK+
1147 if (bSlop
) { // A margin is defined
1148 Sci::Line yMoveT
, yMoveB
;
1150 Sci::Line yMarginT
, yMarginB
;
1151 if (!(options
& xysUseMargin
)) {
1152 // In drag mode, avoid moves
1153 // otherwise, a double click will select several lines.
1154 yMarginT
= yMarginB
= 0;
1156 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1157 // a maximum of slightly less than half the heigth of the text area.
1158 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1160 yMarginB
= yMarginT
;
1162 yMarginB
= linesOnScreen
- yMarginT
- 1;
1168 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1172 yMoveB
= linesOnScreen
- yMoveT
- 1;
1174 if (lineCaret
< topLine
+ yMarginT
) {
1175 // Caret goes too high
1176 newXY
.topLine
= lineCaret
- yMoveT
;
1177 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1178 // Caret goes too low
1179 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1181 } else { // Not strict
1182 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1183 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1187 yMoveB
= linesOnScreen
- yMoveT
- 1;
1189 if (lineCaret
< topLine
) {
1190 // Caret goes too high
1191 newXY
.topLine
= lineCaret
- yMoveT
;
1192 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1193 // Caret goes too low
1194 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1198 if (!bStrict
&& !bJump
) {
1200 if (lineCaret
< topLine
) {
1201 // Caret goes too high
1202 newXY
.topLine
= lineCaret
;
1203 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1204 // Caret goes too low
1206 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1208 newXY
.topLine
= lineCaret
;
1211 } else { // Strict or going out of display
1213 // Always center caret
1214 newXY
.topLine
= lineCaret
- halfScreen
;
1216 // Always put caret on top of display
1217 newXY
.topLine
= lineCaret
;
1221 if (!(range
.caret
== range
.anchor
)) {
1222 const Sci::Line lineAnchor
= DisplayFromPosition(range
.anchor
.Position());
1223 if (lineAnchor
< lineCaret
) {
1224 // Shift up to show anchor or as much of range as possible
1225 newXY
.topLine
= std::min(newXY
.topLine
, lineAnchor
);
1226 newXY
.topLine
= std::max(newXY
.topLine
, lineCaret
- LinesOnScreen());
1228 // Shift down to show anchor or as much of range as possible
1229 newXY
.topLine
= std::max(newXY
.topLine
, lineAnchor
- LinesOnScreen());
1230 newXY
.topLine
= std::min(newXY
.topLine
, lineCaret
);
1233 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1236 // Horizontal positioning
1237 if ((options
& xysHorizontal
) && !Wrapping()) {
1238 const int halfScreen
= std::max(static_cast<int>(rcClient
.Width()) - 4, 4) / 2;
1239 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1240 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1241 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1242 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1244 if (bSlop
) { // A margin is defined
1247 int xMarginL
, xMarginR
;
1248 if (!(options
& xysUseMargin
)) {
1249 // In drag mode, avoid moves unless very near of the margin
1250 // otherwise, a simple click will select text.
1251 xMarginL
= xMarginR
= 2;
1253 // xMargin must equal to caretXSlop, with a minimum of 2 and
1254 // a maximum of slightly less than half the width of the text area.
1255 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1257 xMarginL
= xMarginR
;
1259 xMarginL
= static_cast<int>(rcClient
.Width()) - xMarginR
- 4;
1262 if (bJump
&& bEven
) {
1263 // Jump is used only in even mode
1264 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1266 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1268 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1269 // Caret is on the left of the display
1270 if (bJump
&& bEven
) {
1271 newXY
.xOffset
-= xMoveL
;
1273 // Move just enough to allow to display the caret
1274 newXY
.xOffset
-= static_cast<int>((rcClient
.left
+ xMarginL
) - pt
.x
);
1276 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1277 // Caret is on the right of the display
1278 if (bJump
&& bEven
) {
1279 newXY
.xOffset
+= xMoveR
;
1281 // Move just enough to allow to display the caret
1282 newXY
.xOffset
+= static_cast<int>(pt
.x
- (rcClient
.right
- xMarginR
) + 1);
1285 } else { // Not strict
1286 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1287 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1291 xMoveL
= static_cast<int>(rcClient
.Width()) - xMoveR
- 4;
1293 if (pt
.x
< rcClient
.left
) {
1294 // Caret is on the left of the display
1295 newXY
.xOffset
-= xMoveL
;
1296 } else if (pt
.x
>= rcClient
.right
) {
1297 // Caret is on the right of the display
1298 newXY
.xOffset
+= xMoveR
;
1303 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1304 // Strict or going out of display
1307 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.left
- halfScreen
);
1309 // Put caret on right
1310 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
+ 1);
1313 // Move just enough to allow to display the caret
1314 if (pt
.x
< rcClient
.left
) {
1315 // Caret is on the left of the display
1317 newXY
.xOffset
-= static_cast<int>(rcClient
.left
- pt
.x
);
1319 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1321 } else if (pt
.x
>= rcClient
.right
) {
1322 // Caret is on the right of the display
1323 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1327 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1328 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1329 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 2;
1330 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1331 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 2;
1332 if ((vs
.caretStyle
== CARETSTYLE_BLOCK
) || view
.imeCaretBlockOverride
) {
1333 // Ensure we can see a good portion of the block caret
1334 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1337 if (!(range
.caret
== range
.anchor
)) {
1338 if (ptAnchor
.x
< pt
.x
) {
1339 // Shift to left to show anchor or as much of range as possible
1340 const int maxOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.left
) - 1;
1341 const int minOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 1;
1342 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1343 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1345 // Shift to right to show anchor or as much of range as possible
1346 const int minOffset
= static_cast<Sci::Position
>(ptAnchor
.x
+ xOffset
- rcClient
.right
) + 1;
1347 const int maxOffset
= static_cast<Sci::Position
>(pt
.x
+ xOffset
- rcClient
.left
) - 1;
1348 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1349 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1352 if (newXY
.xOffset
< 0) {
1360 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1361 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1362 if (newXY
.topLine
!= topLine
) {
1363 SetTopLine(newXY
.topLine
);
1364 SetVerticalScrollPos();
1366 if (newXY
.xOffset
!= xOffset
) {
1367 xOffset
= newXY
.xOffset
;
1368 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1369 if (newXY
.xOffset
> 0) {
1370 const PRectangle rcText
= GetTextRectangle();
1371 if (horizontalScrollBarVisible
&&
1372 rcText
.Width() + xOffset
> scrollWidth
) {
1373 scrollWidth
= xOffset
+ static_cast<Sci::Position
>(rcText
.Width());
1377 SetHorizontalScrollPos();
1380 UpdateSystemCaret();
1384 void Editor::ScrollRange(SelectionRange range
) {
1385 SetXYScroll(XYScrollToMakeVisible(range
, xysDefault
));
1388 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1389 SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
),
1390 static_cast<XYScrollOptions
>((useMargin
?xysUseMargin
:0)|(vert
?xysVertical
:0)|(horiz
?xysHorizontal
:0))));
1393 void Editor::ShowCaretAtCurrentPosition() {
1395 caret
.active
= true;
1397 if (FineTickerAvailable()) {
1398 FineTickerCancel(tickCaret
);
1399 if (caret
.period
> 0)
1400 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1405 caret
.active
= false;
1407 if (FineTickerAvailable()) {
1408 FineTickerCancel(tickCaret
);
1414 void Editor::DropCaret() {
1415 caret
.active
= false;
1416 if (FineTickerAvailable()) {
1417 FineTickerCancel(tickCaret
);
1422 void Editor::CaretSetPeriod(int period
) {
1423 if (caret
.period
!= period
) {
1424 caret
.period
= period
;
1426 if (FineTickerAvailable()) {
1427 FineTickerCancel(tickCaret
);
1428 if ((caret
.active
) && (caret
.period
> 0))
1429 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1435 void Editor::InvalidateCaret() {
1436 if (posDrag
.IsValid()) {
1437 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1439 for (size_t r
=0; r
<sel
.Count(); r
++) {
1440 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1443 UpdateSystemCaret();
1446 void Editor::NotifyCaretMove() {
1449 void Editor::UpdateSystemCaret() {
1452 bool Editor::Wrapping() const {
1453 return vs
.wrapState
!= eWrapNone
;
1456 void Editor::NeedWrapping(Sci::Line docLineStart
, Sci::Line docLineEnd
) {
1457 //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd);
1458 if (wrapPending
.AddRange(docLineStart
, docLineEnd
)) {
1459 view
.llc
.Invalidate(LineLayout::llPositions
);
1461 // Wrap lines during idle.
1462 if (Wrapping() && wrapPending
.NeedsWrap()) {
1467 bool Editor::WrapOneLine(Surface
*surface
, Sci::Line lineToWrap
) {
1468 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(lineToWrap
, *this));
1469 int linesWrapped
= 1;
1471 view
.LayoutLine(*this, lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1472 linesWrapped
= ll
->lines
;
1474 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1475 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1478 // Perform wrapping for a subset of the lines needing wrapping.
1479 // wsAll: wrap all lines which need wrapping in this single call
1480 // wsVisible: wrap currently visible lines
1481 // wsIdle: wrap one page + 100 lines
1482 // Return true if wrapping occurred.
1483 bool Editor::WrapLines(WrapScope ws
) {
1484 Sci::Line goodTopLine
= topLine
;
1485 bool wrapOccurred
= false;
1487 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1488 wrapWidth
= LineLayout::wrapWidthInfinite
;
1489 for (Sci::Line lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1490 cs
.SetHeight(lineDoc
, 1 +
1491 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1493 wrapOccurred
= true;
1495 wrapPending
.Reset();
1497 } else if (wrapPending
.NeedsWrap()) {
1498 wrapPending
.start
= std::min(wrapPending
.start
, pdoc
->LinesTotal());
1499 if (!SetIdle(true)) {
1500 // Idle processing not supported so full wrap required.
1501 ws
= WrapScope::wsAll
;
1503 // Decide where to start wrapping
1504 Sci::Line lineToWrap
= wrapPending
.start
;
1505 Sci::Line lineToWrapEnd
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1506 const Sci::Line lineDocTop
= cs
.DocFromDisplay(topLine
);
1507 const int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1508 if (ws
== WrapScope::wsVisible
) {
1509 lineToWrap
= Platform::Clamp(lineDocTop
-5, wrapPending
.start
, pdoc
->LinesTotal());
1510 // Priority wrap to just after visible area.
1511 // Since wrapping could reduce display lines, treat each
1512 // as taking only one display line.
1513 lineToWrapEnd
= lineDocTop
;
1514 Sci::Line lines
= LinesOnScreen() + 1;
1515 while ((lineToWrapEnd
< cs
.LinesInDoc()) && (lines
>0)) {
1516 if (cs
.GetVisible(lineToWrapEnd
))
1520 // .. and if the paint window is outside pending wraps
1521 if ((lineToWrap
> wrapPending
.end
) || (lineToWrapEnd
< wrapPending
.start
)) {
1522 // Currently visible text does not need wrapping
1525 } else if (ws
== WrapScope::wsIdle
) {
1526 lineToWrapEnd
= lineToWrap
+ LinesOnScreen() + 100;
1528 const Sci::Line lineEndNeedWrap
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1529 lineToWrapEnd
= std::min(lineToWrapEnd
, lineEndNeedWrap
);
1531 // Ensure all lines being wrapped are styled.
1532 pdoc
->EnsureStyledTo(pdoc
->LineStart(lineToWrapEnd
));
1534 if (lineToWrap
< lineToWrapEnd
) {
1536 PRectangle rcTextArea
= GetClientRectangle();
1537 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1538 rcTextArea
.right
-= vs
.rightMarginWidth
;
1539 wrapWidth
= static_cast<int>(rcTextArea
.Width());
1541 AutoSurface
surface(this);
1543 //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd);
1545 while (lineToWrap
< lineToWrapEnd
) {
1546 if (WrapOneLine(surface
, lineToWrap
)) {
1547 wrapOccurred
= true;
1549 wrapPending
.Wrapped(lineToWrap
);
1553 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
) + std::min(subLineTop
, cs
.GetHeight(lineDocTop
)-1);
1557 // If wrapping is done, bring it to resting position
1558 if (wrapPending
.start
>= lineEndNeedWrap
) {
1559 wrapPending
.Reset();
1565 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1566 SetVerticalScrollPos();
1569 return wrapOccurred
;
1572 void Editor::LinesJoin() {
1573 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1575 bool prevNonWS
= true;
1576 for (Sci::Position pos
= targetStart
; pos
< targetEnd
; pos
++) {
1577 if (pdoc
->IsPositionInLineEnd(pos
)) {
1578 targetEnd
-= pdoc
->LenChar(pos
);
1581 // Ensure at least one space separating previous lines
1582 const Sci::Position lengthInserted
= pdoc
->InsertString(pos
, " ", 1);
1583 targetEnd
+= lengthInserted
;
1586 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1592 const char *Editor::StringFromEOLMode(int eolMode
) {
1593 if (eolMode
== SC_EOL_CRLF
) {
1595 } else if (eolMode
== SC_EOL_CR
) {
1602 void Editor::LinesSplit(int pixelWidth
) {
1603 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1604 if (pixelWidth
== 0) {
1605 const PRectangle rcText
= GetTextRectangle();
1606 pixelWidth
= static_cast<int>(rcText
.Width());
1608 Sci::Line lineStart
= pdoc
->LineFromPosition(targetStart
);
1609 Sci::Line lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1610 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1612 for (Sci::Line line
= lineStart
; line
<= lineEnd
; line
++) {
1613 AutoSurface
surface(this);
1614 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
1615 if (surface
&& ll
) {
1616 Sci::Position posLineStart
= pdoc
->LineStart(line
);
1617 view
.LayoutLine(*this, line
, surface
, vs
, ll
, pixelWidth
);
1618 Sci::Position lengthInsertedTotal
= 0;
1619 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1620 const Sci::Position lengthInserted
= pdoc
->InsertString(
1621 static_cast<int>(posLineStart
+ lengthInsertedTotal
+
1622 ll
->LineStart(subLine
)),
1624 targetEnd
+= lengthInserted
;
1625 lengthInsertedTotal
+= lengthInserted
;
1628 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1633 void Editor::PaintSelMargin(Surface
*surfaceWindow
, PRectangle
&rc
) {
1634 if (vs
.fixedColumnWidth
== 0)
1639 RefreshPixMaps(surfaceWindow
);
1641 // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished
1642 // at this point. The Initialised call checks for this case and sets the status
1643 // to be bad which avoids crashes in following calls.
1644 if (!surfaceWindow
->Initialised()) {
1648 PRectangle rcMargin
= GetClientRectangle();
1649 Point ptOrigin
= GetVisibleOriginInMain();
1650 rcMargin
.Move(0, -ptOrigin
.y
);
1652 rcMargin
.right
= static_cast<XYPOSITION
>(vs
.fixedColumnWidth
);
1654 if (!rc
.Intersects(rcMargin
))
1658 if (view
.bufferedDraw
) {
1659 surface
= marginView
.pixmapSelMargin
.get();
1661 surface
= surfaceWindow
;
1664 // Clip vertically to paint area to avoid drawing line numbers
1665 if (rcMargin
.bottom
> rc
.bottom
)
1666 rcMargin
.bottom
= rc
.bottom
;
1667 if (rcMargin
.top
< rc
.top
)
1668 rcMargin
.top
= rc
.top
;
1670 marginView
.PaintMargin(surface
, topLine
, rc
, rcMargin
, *this, vs
);
1672 if (view
.bufferedDraw
) {
1673 surfaceWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *marginView
.pixmapSelMargin
);
1677 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
1678 view
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1679 marginView
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1680 if (view
.bufferedDraw
) {
1681 const PRectangle rcClient
= GetClientRectangle();
1682 if (!view
.pixmapLine
->Initialised()) {
1684 view
.pixmapLine
->InitPixMap(static_cast<int>(rcClient
.Width()), vs
.lineHeight
,
1685 surfaceWindow
, wMain
.GetID());
1687 if (!marginView
.pixmapSelMargin
->Initialised()) {
1688 marginView
.pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1689 static_cast<int>(rcClient
.Height()), surfaceWindow
, wMain
.GetID());
1694 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1695 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1696 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1700 if (paintState
== paintAbandoned
)
1701 return; // Scroll bars may have changed so need redraw
1702 RefreshPixMaps(surfaceWindow
);
1704 paintAbandonedByStyling
= false;
1706 StyleAreaBounded(rcArea
, false);
1708 PRectangle rcClient
= GetClientRectangle();
1709 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1710 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1712 if (NotifyUpdateUI()) {
1714 RefreshPixMaps(surfaceWindow
);
1717 // Wrap the visible lines if needed.
1718 if (WrapLines(WrapScope::wsVisible
)) {
1719 // The wrapping process has changed the height of some lines so
1720 // abandon this paint for a complete repaint.
1721 if (AbandonPaint()) {
1724 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
1726 PLATFORM_ASSERT(marginView
.pixmapSelPattern
->Initialised());
1728 if (!view
.bufferedDraw
)
1729 surfaceWindow
->SetClip(rcArea
);
1731 if (paintState
!= paintAbandoned
) {
1732 if (vs
.marginInside
) {
1733 PaintSelMargin(surfaceWindow
, rcArea
);
1734 PRectangle rcRightMargin
= rcClient
;
1735 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1736 if (rcArea
.Intersects(rcRightMargin
)) {
1737 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1739 } else { // Else separate view so separate paint event but leftMargin included to allow overlap
1740 PRectangle rcLeftMargin
= rcArea
;
1741 rcLeftMargin
.left
= 0;
1742 rcLeftMargin
.right
= rcLeftMargin
.left
+ vs
.leftMarginWidth
;
1743 if (rcArea
.Intersects(rcLeftMargin
)) {
1744 surfaceWindow
->FillRectangle(rcLeftMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1749 if (paintState
== paintAbandoned
) {
1750 // Either styling or NotifyUpdateUI noticed that painting is needed
1751 // outside the current painting rectangle
1752 //Platform::DebugPrintf("Abandoning paint\n");
1754 if (paintAbandonedByStyling
) {
1755 // Styling has spilled over a line end, such as occurs by starting a multiline
1756 // comment. The width of subsequent text may have changed, so rewrap.
1757 NeedWrapping(cs
.DocFromDisplay(topLine
));
1763 view
.PaintText(surfaceWindow
, *this, rcArea
, rcClient
, vs
);
1765 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
1766 if (FineTickerAvailable()) {
1767 scrollWidth
= view
.lineWidthMaxSeen
;
1768 if (!FineTickerRunning(tickWiden
)) {
1769 FineTickerStart(tickWiden
, 50, 5);
1777 // This is mostly copied from the Paint method but with some things omitted
1778 // such as the margin markers, line numbers, selection and caret
1779 // Should be merged back into a combined Draw method.
1780 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
1784 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
1787 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
1788 if (!surfaceMeasure
) {
1791 return view
.FormatRange(draw
, pfr
, surface
, surfaceMeasure
, *this, vs
);
1794 int Editor::TextWidth(int style
, const char *text
) {
1796 AutoSurface
surface(this);
1798 return static_cast<int>(surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
)));
1804 // Empty method is overridden on GTK+ to show / hide scrollbars
1805 void Editor::ReconfigureScrollBars() {}
1807 void Editor::SetScrollBars() {
1810 const Sci::Line nMax
= MaxScrollPos();
1811 const Sci::Line nPage
= LinesOnScreen();
1812 const bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
1817 // TODO: ensure always showing as many lines as possible
1818 // May not be, if, for example, window made larger
1819 if (topLine
> MaxScrollPos()) {
1820 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1821 SetVerticalScrollPos();
1825 if (!AbandonPaint())
1828 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1831 void Editor::ChangeSize() {
1832 DropGraphics(false);
1835 PRectangle rcTextArea
= GetClientRectangle();
1836 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1837 rcTextArea
.right
-= vs
.rightMarginWidth
;
1838 if (wrapWidth
!= rcTextArea
.Width()) {
1845 Sci::Position
Editor::RealizeVirtualSpace(Sci::Position position
, Sci::Position virtualSpace
) {
1846 if (virtualSpace
> 0) {
1847 const Sci::Line line
= pdoc
->LineFromPosition(position
);
1848 const Sci::Position indent
= pdoc
->GetLineIndentPosition(line
);
1849 if (indent
== position
) {
1850 return pdoc
->SetLineIndentation(line
, pdoc
->GetLineIndentation(line
) + virtualSpace
);
1852 std::string
spaceText(virtualSpace
, ' ');
1853 const Sci::Position lengthInserted
= pdoc
->InsertString(position
, spaceText
.c_str(), virtualSpace
);
1854 position
+= lengthInserted
;
1860 SelectionPosition
Editor::RealizeVirtualSpace(const SelectionPosition
&position
) {
1861 // Return the new position with no virtual space
1862 return SelectionPosition(RealizeVirtualSpace(position
.Position(), position
.VirtualSpace()));
1865 void Editor::AddChar(char ch
) {
1872 void Editor::FilterSelections() {
1873 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
1874 InvalidateWholeSelection();
1875 sel
.DropAdditionalRanges();
1879 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
1880 void Editor::AddCharUTF(const char *s
, unsigned int len
, bool treatAsDBCS
) {
1883 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1885 // Vector elements point into selection in order to change selection.
1886 std::vector
<SelectionRange
*> selPtrs
;
1887 for (size_t r
= 0; r
< sel
.Count(); r
++) {
1888 selPtrs
.push_back(&sel
.Range(r
));
1890 // Order selections by position in document.
1891 std::sort(selPtrs
.begin(), selPtrs
.end(),
1892 [](const SelectionRange
*a
, const SelectionRange
*b
) {return *a
< *b
;});
1894 // Loop in reverse to avoid disturbing positions of selections yet to be processed.
1895 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
1896 rit
!= selPtrs
.rend(); ++rit
) {
1897 SelectionRange
*currentSel
= *rit
;
1898 if (!RangeContainsProtected(currentSel
->Start().Position(),
1899 currentSel
->End().Position())) {
1900 Sci::Position positionInsert
= currentSel
->Start().Position();
1901 if (!currentSel
->Empty()) {
1902 if (currentSel
->Length()) {
1903 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
1904 currentSel
->ClearVirtualSpace();
1906 // Range is all virtual so collapse to start of virtual space
1907 currentSel
->MinimizeVirtualSpace();
1909 } else if (inOverstrike
) {
1910 if (positionInsert
< pdoc
->Length()) {
1911 if (!pdoc
->IsPositionInLineEnd(positionInsert
)) {
1912 pdoc
->DelChar(positionInsert
);
1913 currentSel
->ClearVirtualSpace();
1917 positionInsert
= RealizeVirtualSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
1918 const Sci::Position lengthInserted
= pdoc
->InsertString(positionInsert
, s
, len
);
1919 if (lengthInserted
> 0) {
1920 currentSel
->caret
.SetPosition(positionInsert
+ lengthInserted
);
1921 currentSel
->anchor
.SetPosition(positionInsert
+ lengthInserted
);
1923 currentSel
->ClearVirtualSpace();
1924 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1926 AutoSurface
surface(this);
1928 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
1930 SetVerticalScrollPos();
1941 ThinRectangularRange();
1942 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1943 EnsureCaretVisible();
1944 // Avoid blinking during rapid typing:
1945 ShowCaretAtCurrentPosition();
1946 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
1947 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
1952 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
1953 static_cast<unsigned char>(s
[1]));
1954 } else if (len
> 0) {
1955 int byte
= static_cast<unsigned char>(s
[0]);
1956 if ((byte
< 0xC0) || (1 == len
)) {
1957 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1958 // characters when not in UTF-8 mode.
1959 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1960 // characters representing themselves.
1962 unsigned int utf32
[1] = { 0 };
1963 UTF32FromUTF8(s
, len
, utf32
, ELEMENTS(utf32
));
1969 if (recordingMacro
) {
1970 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
1974 void Editor::ClearBeforeTentativeStart() {
1975 // Make positions for the first composition string.
1977 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1978 for (size_t r
= 0; r
<sel
.Count(); r
++) {
1979 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1980 sel
.Range(r
).End().Position())) {
1981 Sci::Position positionInsert
= sel
.Range(r
).Start().Position();
1982 if (!sel
.Range(r
).Empty()) {
1983 if (sel
.Range(r
).Length()) {
1984 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1985 sel
.Range(r
).ClearVirtualSpace();
1987 // Range is all virtual so collapse to start of virtual space
1988 sel
.Range(r
).MinimizeVirtualSpace();
1991 RealizeVirtualSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
1992 sel
.Range(r
).ClearVirtualSpace();
1997 void Editor::InsertPaste(const char *text
, int len
) {
1998 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
1999 SelectionPosition selStart
= sel
.Start();
2000 selStart
= RealizeVirtualSpace(selStart
);
2001 const Sci::Position lengthInserted
= pdoc
->InsertString(selStart
.Position(), text
, len
);
2002 if (lengthInserted
> 0) {
2003 SetEmptySelection(selStart
.Position() + lengthInserted
);
2006 // SC_MULTIPASTE_EACH
2007 for (size_t r
=0; r
<sel
.Count(); r
++) {
2008 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
2009 sel
.Range(r
).End().Position())) {
2010 Sci::Position positionInsert
= sel
.Range(r
).Start().Position();
2011 if (!sel
.Range(r
).Empty()) {
2012 if (sel
.Range(r
).Length()) {
2013 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
2014 sel
.Range(r
).ClearVirtualSpace();
2016 // Range is all virtual so collapse to start of virtual space
2017 sel
.Range(r
).MinimizeVirtualSpace();
2020 positionInsert
= RealizeVirtualSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
2021 const Sci::Position lengthInserted
= pdoc
->InsertString(positionInsert
, text
, len
);
2022 if (lengthInserted
> 0) {
2023 sel
.Range(r
).caret
.SetPosition(positionInsert
+ lengthInserted
);
2024 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ lengthInserted
);
2026 sel
.Range(r
).ClearVirtualSpace();
2032 void Editor::InsertPasteShape(const char *text
, int len
, PasteShape shape
) {
2033 std::string convertedText
;
2034 if (convertPastes
) {
2035 // Convert line endings of the paste into our local line-endings mode
2036 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
2037 len
= static_cast<int>(convertedText
.length());
2038 text
= convertedText
.c_str();
2040 if (shape
== pasteRectangular
) {
2041 PasteRectangular(sel
.Start(), text
, len
);
2043 if (shape
== pasteLine
) {
2044 Sci::Position insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
2045 Sci::Position lengthInserted
= pdoc
->InsertString(insertPos
, text
, len
);
2046 // add the newline if necessary
2047 if ((len
> 0) && (text
[len
- 1] != '\n' && text
[len
- 1] != '\r')) {
2048 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
2049 int length
= static_cast<int>(strlen(endline
));
2050 lengthInserted
+= pdoc
->InsertString(insertPos
+ lengthInserted
, endline
, length
);
2052 if (sel
.MainCaret() == insertPos
) {
2053 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
2056 InsertPaste(text
, len
);
2061 void Editor::ClearSelection(bool retainMultipleSelections
) {
2062 if (!sel
.IsRectangular() && !retainMultipleSelections
)
2065 for (size_t r
=0; r
<sel
.Count(); r
++) {
2066 if (!sel
.Range(r
).Empty()) {
2067 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
2068 sel
.Range(r
).End().Position())) {
2069 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
2070 sel
.Range(r
).Length());
2071 sel
.Range(r
) = SelectionRange(sel
.Range(r
).Start());
2075 ThinRectangularRange();
2076 sel
.RemoveDuplicates();
2078 SetHoverIndicatorPosition(sel
.MainCaret());
2081 void Editor::ClearAll() {
2084 if (0 != pdoc
->Length()) {
2085 pdoc
->DeleteChars(0, pdoc
->Length());
2087 if (!pdoc
->IsReadOnly()) {
2089 pdoc
->AnnotationClearAll();
2090 pdoc
->MarginClearAll();
2094 view
.ClearAllTabstops();
2098 SetVerticalScrollPos();
2099 InvalidateStyleRedraw();
2102 void Editor::ClearDocumentStyle() {
2103 pdoc
->decorations
.DeleteLexerDecorations();
2104 pdoc
->StartStyling(0, '\377');
2105 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2107 SetAnnotationHeights(0, pdoc
->LinesTotal());
2108 pdoc
->ClearLevels();
2111 void Editor::CopyAllowLine() {
2112 SelectionText selectedText
;
2113 CopySelectionRange(&selectedText
, true);
2114 CopyToClipboard(selectedText
);
2117 void Editor::Cut() {
2118 pdoc
->CheckReadOnly();
2119 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2125 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, Sci::Position len
) {
2126 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2130 sel
.RangeMain() = SelectionRange(pos
);
2131 Sci::Line line
= pdoc
->LineFromPosition(sel
.MainCaret());
2133 sel
.RangeMain().caret
= RealizeVirtualSpace(sel
.RangeMain().caret
);
2134 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
2135 bool prevCr
= false;
2136 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
2138 for (Sci::Position i
= 0; i
< len
; i
++) {
2139 if (IsEOLChar(ptr
[i
])) {
2140 if ((ptr
[i
] == '\r') || (!prevCr
))
2142 if (line
>= pdoc
->LinesTotal()) {
2143 if (pdoc
->eolMode
!= SC_EOL_LF
)
2144 pdoc
->InsertString(pdoc
->Length(), "\r", 1);
2145 if (pdoc
->eolMode
!= SC_EOL_CR
)
2146 pdoc
->InsertString(pdoc
->Length(), "\n", 1);
2148 // Pad the end of lines with spaces if required
2149 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
2150 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
2151 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
2153 const Sci::Position lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), " ", 1);
2154 sel
.RangeMain().caret
.Add(lengthInserted
);
2157 prevCr
= ptr
[i
] == '\r';
2159 const Sci::Position lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
2160 sel
.RangeMain().caret
.Add(lengthInserted
);
2164 SetEmptySelection(pos
);
2167 bool Editor::CanPaste() {
2168 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
2171 void Editor::Clear() {
2172 // If multiple selections, don't delete EOLS
2174 bool singleVirtual
= false;
2175 if ((sel
.Count() == 1) &&
2176 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
2177 sel
.RangeMain().Start().VirtualSpace()) {
2178 singleVirtual
= true;
2180 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
2181 for (size_t r
=0; r
<sel
.Count(); r
++) {
2182 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
2183 if (sel
.Range(r
).Start().VirtualSpace()) {
2184 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
2185 sel
.Range(r
) = SelectionRange(RealizeVirtualSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
2187 sel
.Range(r
) = SelectionRange(RealizeVirtualSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
2189 if ((sel
.Count() == 1) || !pdoc
->IsPositionInLineEnd(sel
.Range(r
).caret
.Position())) {
2190 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
2191 sel
.Range(r
).ClearVirtualSpace();
2192 } // else multiple selection so don't eat line ends
2194 sel
.Range(r
).ClearVirtualSpace();
2200 sel
.RemoveDuplicates();
2201 ShowCaretAtCurrentPosition(); // Avoid blinking
2204 void Editor::SelectAll() {
2206 SetSelection(0, pdoc
->Length());
2210 void Editor::Undo() {
2211 if (pdoc
->CanUndo()) {
2213 Sci::Position newPos
= pdoc
->Undo();
2215 SetEmptySelection(newPos
);
2216 EnsureCaretVisible();
2220 void Editor::Redo() {
2221 if (pdoc
->CanRedo()) {
2222 Sci::Position newPos
= pdoc
->Redo();
2224 SetEmptySelection(newPos
);
2225 EnsureCaretVisible();
2229 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2231 if (!sel
.IsRectangular())
2233 if (sel
.IsRectangular())
2234 allowLineStartDeletion
= false;
2235 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
2237 for (size_t r
=0; r
<sel
.Count(); r
++) {
2238 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
2239 if (sel
.Range(r
).caret
.VirtualSpace()) {
2240 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
2241 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
2243 Sci::Line lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2244 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
2245 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2246 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
2247 UndoGroup
ugInner(pdoc
, !ug
.Needed());
2248 const int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2249 const int indentationStep
= pdoc
->IndentSize();
2250 int indentationChange
= indentation
% indentationStep
;
2251 if (indentationChange
== 0)
2252 indentationChange
= indentationStep
;
2253 const Sci::Position posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationChange
);
2254 // SetEmptySelection
2255 sel
.Range(r
) = SelectionRange(posSelect
);
2257 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
2262 sel
.Range(r
).ClearVirtualSpace();
2265 ThinRectangularRange();
2269 sel
.RemoveDuplicates();
2270 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
2271 // Avoid blinking during rapid typing:
2272 ShowCaretAtCurrentPosition();
2275 int Editor::ModifierFlags(bool shift
, bool ctrl
, bool alt
, bool meta
, bool super
) {
2277 (shift
? SCI_SHIFT
: 0) |
2278 (ctrl
? SCI_CTRL
: 0) |
2279 (alt
? SCI_ALT
: 0) |
2280 (meta
? SCI_META
: 0) |
2281 (super
? SCI_SUPER
: 0);
2284 void Editor::NotifyFocus(bool focus
) {
2285 SCNotification scn
= {};
2286 scn
.nmhdr
.code
= focus
? SCN_FOCUSIN
: SCN_FOCUSOUT
;
2290 void Editor::SetCtrlID(int identifier
) {
2291 ctrlID
= identifier
;
2294 void Editor::NotifyStyleToNeeded(Sci::Position endStyleNeeded
) {
2295 SCNotification scn
= {};
2296 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2297 scn
.position
= endStyleNeeded
;
2301 void Editor::NotifyStyleNeeded(Document
*, void *, Sci::Position endStyleNeeded
) {
2302 NotifyStyleToNeeded(endStyleNeeded
);
2305 void Editor::NotifyLexerChanged(Document
*, void *) {
2308 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
2309 errorStatus
= status
;
2312 void Editor::NotifyChar(int ch
) {
2313 SCNotification scn
= {};
2314 scn
.nmhdr
.code
= SCN_CHARADDED
;
2319 void Editor::NotifySavePoint(bool isSavePoint
) {
2320 SCNotification scn
= {};
2322 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2324 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2329 void Editor::NotifyModifyAttempt() {
2330 SCNotification scn
= {};
2331 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2335 void Editor::NotifyDoubleClick(Point pt
, int modifiers
) {
2336 SCNotification scn
= {};
2337 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2338 scn
.line
= LineFromLocation(pt
);
2339 scn
.position
= PositionFromLocation(pt
, true);
2340 scn
.modifiers
= modifiers
;
2344 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2345 NotifyDoubleClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2348 void Editor::NotifyHotSpotDoubleClicked(Sci::Position position
, int modifiers
) {
2349 SCNotification scn
= {};
2350 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
2351 scn
.position
= position
;
2352 scn
.modifiers
= modifiers
;
2356 void Editor::NotifyHotSpotDoubleClicked(Sci::Position position
, bool shift
, bool ctrl
, bool alt
) {
2357 NotifyHotSpotDoubleClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2360 void Editor::NotifyHotSpotClicked(Sci::Position position
, int modifiers
) {
2361 SCNotification scn
= {};
2362 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
2363 scn
.position
= position
;
2364 scn
.modifiers
= modifiers
;
2368 void Editor::NotifyHotSpotClicked(Sci::Position position
, bool shift
, bool ctrl
, bool alt
) {
2369 NotifyHotSpotClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2372 void Editor::NotifyHotSpotReleaseClick(Sci::Position position
, int modifiers
) {
2373 SCNotification scn
= {};
2374 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
2375 scn
.position
= position
;
2376 scn
.modifiers
= modifiers
;
2380 void Editor::NotifyHotSpotReleaseClick(Sci::Position position
, bool shift
, bool ctrl
, bool alt
) {
2381 NotifyHotSpotReleaseClick(position
, ModifierFlags(shift
, ctrl
, alt
));
2384 bool Editor::NotifyUpdateUI() {
2386 SCNotification scn
= {};
2387 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2388 scn
.updated
= needUpdateUI
;
2396 void Editor::NotifyPainted() {
2397 SCNotification scn
= {};
2398 scn
.nmhdr
.code
= SCN_PAINTED
;
2402 void Editor::NotifyIndicatorClick(bool click
, Sci::Position position
, int modifiers
) {
2403 const int mask
= pdoc
->decorations
.AllOnFor(position
);
2404 if ((click
&& mask
) || pdoc
->decorations
.ClickNotified()) {
2405 SCNotification scn
= {};
2406 pdoc
->decorations
.SetClickNotified(click
);
2407 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
2408 scn
.modifiers
= modifiers
;
2409 scn
.position
= position
;
2414 void Editor::NotifyIndicatorClick(bool click
, Sci::Position position
, bool shift
, bool ctrl
, bool alt
) {
2415 NotifyIndicatorClick(click
, position
, ModifierFlags(shift
, ctrl
, alt
));
2418 bool Editor::NotifyMarginClick(Point pt
, int modifiers
) {
2419 const int marginClicked
= vs
.MarginFromLocation(pt
);
2420 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2421 Sci::Position position
= pdoc
->LineStart(LineFromLocation(pt
));
2422 if ((vs
.ms
[marginClicked
].mask
& SC_MASK_FOLDERS
) && (foldAutomatic
& SC_AUTOMATICFOLD_CLICK
)) {
2423 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
2424 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
2425 Sci::Line lineClick
= pdoc
->LineFromPosition(position
);
2426 if (shift
&& ctrl
) {
2427 FoldAll(SC_FOLDACTION_TOGGLE
);
2429 int levelClick
= pdoc
->GetLevel(lineClick
);
2430 if (levelClick
& SC_FOLDLEVELHEADERFLAG
) {
2432 // Ensure all children visible
2433 FoldExpand(lineClick
, SC_FOLDACTION_EXPAND
, levelClick
);
2435 FoldExpand(lineClick
, SC_FOLDACTION_TOGGLE
, levelClick
);
2438 FoldLine(lineClick
, SC_FOLDACTION_TOGGLE
);
2444 SCNotification scn
= {};
2445 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2446 scn
.modifiers
= modifiers
;
2447 scn
.position
= position
;
2448 scn
.margin
= marginClicked
;
2456 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2457 return NotifyMarginClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2460 bool Editor::NotifyMarginRightClick(Point pt
, int modifiers
) {
2461 int marginRightClicked
= vs
.MarginFromLocation(pt
);
2462 if ((marginRightClicked
>= 0) && vs
.ms
[marginRightClicked
].sensitive
) {
2463 Sci::Position position
= pdoc
->LineStart(LineFromLocation(pt
));
2464 SCNotification scn
= {};
2465 scn
.nmhdr
.code
= SCN_MARGINRIGHTCLICK
;
2466 scn
.modifiers
= modifiers
;
2467 scn
.position
= position
;
2468 scn
.margin
= marginRightClicked
;
2476 void Editor::NotifyNeedShown(Sci::Position pos
, Sci::Position len
) {
2477 SCNotification scn
= {};
2478 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2484 void Editor::NotifyDwelling(Point pt
, bool state
) {
2485 SCNotification scn
= {};
2486 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2487 scn
.position
= PositionFromLocation(pt
, true);
2488 scn
.x
= static_cast<int>(pt
.x
+ vs
.ExternalMarginWidth());
2489 scn
.y
= static_cast<int>(pt
.y
);
2493 void Editor::NotifyZoom() {
2494 SCNotification scn
= {};
2495 scn
.nmhdr
.code
= SCN_ZOOM
;
2499 // Notifications from document
2500 void Editor::NotifyModifyAttempt(Document
*, void *) {
2501 //Platform::DebugPrintf("** Modify Attempt\n");
2502 NotifyModifyAttempt();
2505 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2506 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2507 NotifySavePoint(atSavePoint
);
2510 void Editor::CheckModificationForWrap(DocModification mh
) {
2511 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
2512 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2513 Sci::Line lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2514 Sci::Line lines
= std::max(static_cast<Sci::Line
>(0), mh
.linesAdded
);
2516 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
2519 // Fix up annotation heights
2520 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
2524 // Move a position so it is still after the same character as before the insertion.
2525 static inline Sci::Position
MovePositionForInsertion(Sci::Position position
, Sci::Position startInsertion
, Sci::Position length
) {
2526 if (position
> startInsertion
) {
2527 return position
+ length
;
2532 // Move a position so it is still after the same character as before the deletion if that
2533 // character is still present else after the previous surviving character.
2534 static inline Sci::Position
MovePositionForDeletion(Sci::Position position
, Sci::Position startDeletion
, Sci::Position length
) {
2535 if (position
> startDeletion
) {
2536 const Sci::Position endDeletion
= startDeletion
+ length
;
2537 if (position
> endDeletion
) {
2538 return position
- length
;
2540 return startDeletion
;
2547 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2548 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
2549 if (paintState
== painting
) {
2550 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2552 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
2553 if (paintState
== painting
) {
2554 CheckForChangeOutsidePaint(
2555 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
2557 // Could check that change is before last visible line.
2561 if (mh
.modificationType
& SC_MOD_CHANGETABSTOPS
) {
2564 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
2565 if (paintState
== painting
) {
2566 CheckForChangeOutsidePaint(
2567 Range(mh
.position
, mh
.position
+ mh
.length
));
2572 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
2573 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2574 pdoc
->IncrementStyleClock();
2576 if (paintState
== notPainting
) {
2577 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2578 // Styling performed before this view
2581 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2584 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2585 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2588 // Move selection and brace highlights
2589 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2590 sel
.MovePositions(true, mh
.position
, mh
.length
);
2591 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2592 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2593 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2594 sel
.MovePositions(false, mh
.position
, mh
.length
);
2595 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2596 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2598 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
2599 // Some lines are hidden so may need shown.
2600 const Sci::Line lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2601 Sci::Position endNeedShown
= mh
.position
;
2602 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2603 if (pdoc
->ContainsLineEnd(mh
.text
, mh
.length
) && (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
2604 endNeedShown
= pdoc
->LineStart(lineOfPos
+1);
2605 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2606 // If the deletion includes any EOL then we extend the need shown area.
2607 endNeedShown
= mh
.position
+ mh
.length
;
2608 Sci::Line lineLast
= pdoc
->LineFromPosition(mh
.position
+mh
.length
);
2609 for (Sci::Line line
= lineOfPos
+ 1; line
<= lineLast
; line
++) {
2610 const Sci::Line lineMaxSubord
= pdoc
->GetLastChild(line
, -1, -1);
2611 if (lineLast
< lineMaxSubord
) {
2612 lineLast
= lineMaxSubord
;
2613 endNeedShown
= pdoc
->LineEnd(lineLast
);
2617 NeedShown(mh
.position
, endNeedShown
- mh
.position
);
2619 if (mh
.linesAdded
!= 0) {
2620 // Update contraction state for inserted and removed lines
2621 // lineOfPos should be calculated in context of state before modification, shouldn't it
2622 Sci::Line lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2623 if (mh
.position
> pdoc
->LineStart(lineOfPos
))
2624 lineOfPos
++; // Affecting subsequent lines
2625 if (mh
.linesAdded
> 0) {
2626 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2628 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2630 view
.LinesAddedOrRemoved(lineOfPos
, mh
.linesAdded
);
2632 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
2633 Sci::Line lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2634 if (vs
.annotationVisible
) {
2635 if (cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
)) {
2641 CheckModificationForWrap(mh
);
2642 if (mh
.linesAdded
!= 0) {
2643 // Avoid scrolling of display if change before current display
2644 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
2645 Sci::Line newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2646 if (newTop
!= topLine
) {
2648 SetVerticalScrollPos();
2652 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
2653 QueueIdleWork(WorkNeeded::workStyle
, pdoc
->Length());
2657 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
2658 QueueIdleWork(WorkNeeded::workStyle
, mh
.position
+ mh
.length
);
2659 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2664 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
2668 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
2669 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
2670 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
2671 // Fold changes can affect the drawing of following lines so redraw whole margin
2672 RedrawSelMargin(marginView
.highlightDelimiter
.isEnabled
? -1 : mh
.line
- 1, true);
2674 RedrawSelMargin(mh
.line
);
2678 if ((mh
.modificationType
& SC_MOD_CHANGEFOLD
) && (foldAutomatic
& SC_AUTOMATICFOLD_CHANGE
)) {
2679 FoldChanged(mh
.line
, mh
.foldLevelNow
, mh
.foldLevelPrev
);
2682 // NOW pay the piper WRT "deferred" visual updates
2683 if (IsLastStep(mh
)) {
2688 // If client wants to see this modification
2689 if (mh
.modificationType
& modEventMask
) {
2690 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
2691 // Real modification made to text of document.
2692 NotifyChange(); // Send EN_CHANGE
2695 SCNotification scn
= {};
2696 scn
.nmhdr
.code
= SCN_MODIFIED
;
2697 scn
.position
= mh
.position
;
2698 scn
.modificationType
= mh
.modificationType
;
2700 scn
.length
= mh
.length
;
2701 scn
.linesAdded
= mh
.linesAdded
;
2703 scn
.foldLevelNow
= mh
.foldLevelNow
;
2704 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2705 scn
.token
= mh
.token
;
2706 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
2711 void Editor::NotifyDeleted(Document
*, void *) {
2715 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2717 // Enumerates all macroable messages
2723 case SCI_REPLACESEL
:
2725 case SCI_INSERTTEXT
:
2726 case SCI_APPENDTEXT
:
2731 case SCI_SEARCHANCHOR
:
2732 case SCI_SEARCHNEXT
:
2733 case SCI_SEARCHPREV
:
2735 case SCI_LINEDOWNEXTEND
:
2737 case SCI_PARADOWNEXTEND
:
2739 case SCI_LINEUPEXTEND
:
2741 case SCI_PARAUPEXTEND
:
2743 case SCI_CHARLEFTEXTEND
:
2745 case SCI_CHARRIGHTEXTEND
:
2747 case SCI_WORDLEFTEXTEND
:
2749 case SCI_WORDRIGHTEXTEND
:
2750 case SCI_WORDPARTLEFT
:
2751 case SCI_WORDPARTLEFTEXTEND
:
2752 case SCI_WORDPARTRIGHT
:
2753 case SCI_WORDPARTRIGHTEXTEND
:
2754 case SCI_WORDLEFTEND
:
2755 case SCI_WORDLEFTENDEXTEND
:
2756 case SCI_WORDRIGHTEND
:
2757 case SCI_WORDRIGHTENDEXTEND
:
2759 case SCI_HOMEEXTEND
:
2761 case SCI_LINEENDEXTEND
:
2763 case SCI_HOMEWRAPEXTEND
:
2764 case SCI_LINEENDWRAP
:
2765 case SCI_LINEENDWRAPEXTEND
:
2766 case SCI_DOCUMENTSTART
:
2767 case SCI_DOCUMENTSTARTEXTEND
:
2768 case SCI_DOCUMENTEND
:
2769 case SCI_DOCUMENTENDEXTEND
:
2770 case SCI_STUTTEREDPAGEUP
:
2771 case SCI_STUTTEREDPAGEUPEXTEND
:
2772 case SCI_STUTTEREDPAGEDOWN
:
2773 case SCI_STUTTEREDPAGEDOWNEXTEND
:
2775 case SCI_PAGEUPEXTEND
:
2777 case SCI_PAGEDOWNEXTEND
:
2778 case SCI_EDITTOGGLEOVERTYPE
:
2780 case SCI_DELETEBACK
:
2785 case SCI_VCHOMEEXTEND
:
2786 case SCI_VCHOMEWRAP
:
2787 case SCI_VCHOMEWRAPEXTEND
:
2788 case SCI_VCHOMEDISPLAY
:
2789 case SCI_VCHOMEDISPLAYEXTEND
:
2790 case SCI_DELWORDLEFT
:
2791 case SCI_DELWORDRIGHT
:
2792 case SCI_DELWORDRIGHTEND
:
2793 case SCI_DELLINELEFT
:
2794 case SCI_DELLINERIGHT
:
2797 case SCI_LINEDELETE
:
2798 case SCI_LINETRANSPOSE
:
2799 case SCI_LINEREVERSE
:
2800 case SCI_LINEDUPLICATE
:
2803 case SCI_LINESCROLLDOWN
:
2804 case SCI_LINESCROLLUP
:
2805 case SCI_DELETEBACKNOTLINE
:
2806 case SCI_HOMEDISPLAY
:
2807 case SCI_HOMEDISPLAYEXTEND
:
2808 case SCI_LINEENDDISPLAY
:
2809 case SCI_LINEENDDISPLAYEXTEND
:
2810 case SCI_SETSELECTIONMODE
:
2811 case SCI_LINEDOWNRECTEXTEND
:
2812 case SCI_LINEUPRECTEXTEND
:
2813 case SCI_CHARLEFTRECTEXTEND
:
2814 case SCI_CHARRIGHTRECTEXTEND
:
2815 case SCI_HOMERECTEXTEND
:
2816 case SCI_VCHOMERECTEXTEND
:
2817 case SCI_LINEENDRECTEXTEND
:
2818 case SCI_PAGEUPRECTEXTEND
:
2819 case SCI_PAGEDOWNRECTEXTEND
:
2820 case SCI_SELECTIONDUPLICATE
:
2821 case SCI_COPYALLOWLINE
:
2822 case SCI_VERTICALCENTRECARET
:
2823 case SCI_MOVESELECTEDLINESUP
:
2824 case SCI_MOVESELECTEDLINESDOWN
:
2825 case SCI_SCROLLTOSTART
:
2826 case SCI_SCROLLTOEND
:
2829 // Filter out all others like display changes. Also, newlines are redundant
2830 // with char insert messages.
2833 // printf("Filtered out %ld of macro recording\n", iMessage);
2837 // Send notification
2838 SCNotification scn
= {};
2839 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2840 scn
.message
= iMessage
;
2841 scn
.wParam
= wParam
;
2842 scn
.lParam
= lParam
;
2846 // Something has changed that the container should know about
2847 void Editor::ContainerNeedsUpdate(int flags
) {
2848 needUpdateUI
|= flags
;
2852 * Force scroll and keep position relative to top of window.
2854 * If stuttered = true and not already at first/last row, move to first/last row of window.
2855 * If stuttered = true and already at first/last row, scroll as normal.
2857 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
2858 Sci::Line topLineNew
;
2859 SelectionPosition newPos
;
2861 const Sci::Line currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
2862 const Sci::Line topStutterLine
= topLine
+ caretYSlop
;
2863 const Sci::Line bottomStutterLine
=
2864 pdoc
->LineFromPosition(PositionFromLocation(
2865 Point::FromInts(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
2868 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
2869 topLineNew
= topLine
;
2870 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
2871 false, false, UserVirtualSpace());
2873 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
2874 topLineNew
= topLine
;
2875 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
2876 false, false, UserVirtualSpace());
2879 Point pt
= LocationFromPosition(sel
.MainCaret());
2881 topLineNew
= Platform::Clamp(
2882 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2883 newPos
= SPositionFromLocation(
2884 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(pt
.y
) + direction
* (vs
.lineHeight
* LinesToScroll())),
2885 false, false, UserVirtualSpace());
2888 if (topLineNew
!= topLine
) {
2889 SetTopLine(topLineNew
);
2890 MovePositionTo(newPos
, selt
);
2892 SetVerticalScrollPos();
2894 MovePositionTo(newPos
, selt
);
2898 void Editor::ChangeCaseOfSelection(int caseMapping
) {
2900 for (size_t r
=0; r
<sel
.Count(); r
++) {
2901 SelectionRange current
= sel
.Range(r
);
2902 SelectionRange currentNoVS
= current
;
2903 currentNoVS
.ClearVirtualSpace();
2904 size_t rangeBytes
= currentNoVS
.Length();
2905 if (rangeBytes
> 0) {
2906 std::string sText
= RangeText(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
2908 std::string sMapped
= CaseMapString(sText
, caseMapping
);
2910 if (sMapped
!= sText
) {
2911 size_t firstDifference
= 0;
2912 while (sMapped
[firstDifference
] == sText
[firstDifference
])
2914 size_t lastDifferenceText
= sText
.size() - 1;
2915 size_t lastDifferenceMapped
= sMapped
.size() - 1;
2916 while (sMapped
[lastDifferenceMapped
] == sText
[lastDifferenceText
]) {
2917 lastDifferenceText
--;
2918 lastDifferenceMapped
--;
2920 size_t endDifferenceText
= sText
.size() - 1 - lastDifferenceText
;
2922 static_cast<Sci::Position
>(currentNoVS
.Start().Position() + firstDifference
),
2923 static_cast<Sci::Position
>(rangeBytes
- firstDifference
- endDifferenceText
));
2924 const Sci::Position lengthChange
= static_cast<Sci::Position
>(lastDifferenceMapped
- firstDifference
+ 1);
2925 const Sci::Position lengthInserted
= pdoc
->InsertString(
2926 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2927 sMapped
.c_str() + firstDifference
,
2929 // Automatic movement changes selection so reset to exactly the same as it was.
2930 Sci::Position diffSizes
= static_cast<Sci::Position
>(sMapped
.size() - sText
.size()) + lengthInserted
- lengthChange
;
2931 if (diffSizes
!= 0) {
2932 if (current
.anchor
> current
.caret
)
2933 current
.anchor
.Add(diffSizes
);
2935 current
.caret
.Add(diffSizes
);
2937 sel
.Range(r
) = current
;
2943 void Editor::LineTranspose() {
2944 Sci::Line line
= pdoc
->LineFromPosition(sel
.MainCaret());
2948 const Sci::Position startPrevious
= pdoc
->LineStart(line
- 1);
2949 const std::string linePrevious
= RangeText(startPrevious
, pdoc
->LineEnd(line
- 1));
2951 Sci::Position startCurrent
= pdoc
->LineStart(line
);
2952 const std::string lineCurrent
= RangeText(startCurrent
, pdoc
->LineEnd(line
));
2954 pdoc
->DeleteChars(startCurrent
, static_cast<Sci::Position
>(lineCurrent
.length()));
2955 pdoc
->DeleteChars(startPrevious
, static_cast<Sci::Position
>(linePrevious
.length()));
2956 startCurrent
-= static_cast<Sci::Position
>(linePrevious
.length());
2958 startCurrent
+= pdoc
->InsertString(startPrevious
, lineCurrent
.c_str(),
2959 static_cast<Sci::Position
>(lineCurrent
.length()));
2960 pdoc
->InsertString(startCurrent
, linePrevious
.c_str(),
2961 static_cast<Sci::Position
>(linePrevious
.length()));
2962 // Move caret to start of current line
2963 MovePositionTo(SelectionPosition(startCurrent
));
2967 void Editor::LineReverse() {
2968 const Sci::Line lineStart
= pdoc
->LineFromPosition(sel
.RangeMain().Start().Position());
2969 const Sci::Line lineEnd
= pdoc
->LineFromPosition(sel
.RangeMain().End().Position()-1);
2970 const Sci::Line lineDiff
= lineEnd
- lineStart
;
2974 for (Sci::Line i
=(lineDiff
+1)/2-1; i
>=0; --i
) {
2975 const Sci::Line lineNum2
= lineEnd
- i
;
2976 const Sci::Line lineNum1
= lineStart
+ i
;
2977 Sci::Position lineStart2
= pdoc
->LineStart(lineNum2
);
2978 const Sci::Position lineStart1
= pdoc
->LineStart(lineNum1
);
2979 const std::string line2
= RangeText(lineStart2
, pdoc
->LineEnd(lineNum2
));
2980 const std::string line1
= RangeText(lineStart1
, pdoc
->LineEnd(lineNum1
));
2981 const Sci::Position lineLen2
= static_cast<Sci::Position
>(line2
.length());
2982 const Sci::Position lineLen1
= static_cast<Sci::Position
>(line1
.length());
2983 pdoc
->DeleteChars(lineStart2
, lineLen2
);
2984 pdoc
->DeleteChars(lineStart1
, lineLen1
);
2985 lineStart2
-= lineLen1
;
2986 pdoc
->InsertString(lineStart2
, line1
.c_str(), lineLen1
);
2987 pdoc
->InsertString(lineStart1
, line2
.c_str(), lineLen2
);
2989 // Wholly select all affected lines
2990 sel
.RangeMain() = SelectionRange(pdoc
->LineStart(lineStart
), pdoc
->LineStart(lineEnd
+1));
2993 void Editor::Duplicate(bool forLine
) {
2998 const char *eol
= "";
3001 eol
= StringFromEOLMode(pdoc
->eolMode
);
3002 eolLen
= istrlen(eol
);
3004 for (size_t r
=0; r
<sel
.Count(); r
++) {
3005 SelectionPosition start
= sel
.Range(r
).Start();
3006 SelectionPosition end
= sel
.Range(r
).End();
3008 Sci::Line line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
3009 start
= SelectionPosition(pdoc
->LineStart(line
));
3010 end
= SelectionPosition(pdoc
->LineEnd(line
));
3012 std::string text
= RangeText(start
.Position(), end
.Position());
3013 Sci::Position lengthInserted
= eolLen
;
3015 lengthInserted
= pdoc
->InsertString(end
.Position(), eol
, eolLen
);
3016 pdoc
->InsertString(end
.Position() + lengthInserted
, text
.c_str(), static_cast<Sci::Position
>(text
.length()));
3018 if (sel
.Count() && sel
.IsRectangular()) {
3019 SelectionPosition last
= sel
.Last();
3021 Sci::Line line
= pdoc
->LineFromPosition(last
.Position());
3022 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
3024 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
3025 sel
.Rectangular().anchor
= last
;
3027 sel
.Rectangular().caret
= last
;
3028 SetRectangularRange();
3032 void Editor::CancelModes() {
3033 sel
.SetMoveExtends(false);
3036 void Editor::NewLine() {
3037 InvalidateWholeSelection();
3038 if (sel
.IsRectangular() || !additionalSelectionTyping
) {
3039 // Remove non-main ranges
3040 sel
.DropAdditionalRanges();
3043 UndoGroup
ug(pdoc
, !sel
.Empty() || (sel
.Count() > 1));
3050 // Insert each line end
3051 size_t countInsertions
= 0;
3052 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3053 sel
.Range(r
).ClearVirtualSpace();
3054 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3055 const Sci::Position positionInsert
= sel
.Range(r
).caret
.Position();
3056 const Sci::Position insertLength
= pdoc
->InsertString(positionInsert
, eol
, istrlen(eol
));
3057 if (insertLength
> 0) {
3058 sel
.Range(r
) = SelectionRange(positionInsert
+ insertLength
);
3063 // Perform notifications after all the changes as the application may change the
3064 // selections in response to the characters.
3065 for (size_t i
= 0; i
< countInsertions
; i
++) {
3066 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3069 if (recordingMacro
) {
3073 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3081 EnsureCaretVisible();
3082 // Avoid blinking during rapid typing:
3083 ShowCaretAtCurrentPosition();
3086 SelectionPosition
Editor::PositionUpOrDown(SelectionPosition spStart
, int direction
, int lastX
) {
3087 const Point pt
= LocationFromPosition(spStart
);
3090 if (vs
.annotationVisible
) {
3091 const Sci::Line lineDoc
= pdoc
->LineFromPosition(spStart
.Position());
3092 const Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
3093 const int subLine
= static_cast<int>(pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
3095 if (direction
< 0 && subLine
== 0) {
3096 const Sci::Line lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
3097 if (lineDisplay
> 0) {
3098 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
3100 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
3101 skipLines
= pdoc
->AnnotationLines(lineDoc
);
3105 const Sci::Line newY
= static_cast<Sci::Line
>(pt
.y
) + (1 + skipLines
) * direction
* vs
.lineHeight
;
3107 lastX
= static_cast<Sci::Position
>(pt
.x
) + xOffset
;
3109 SelectionPosition posNew
= SPositionFromLocation(
3110 Point::FromInts(lastX
- xOffset
, newY
), false, false, UserVirtualSpace());
3112 if (direction
< 0) {
3113 // Line wrapping may lead to a location on the same line, so
3114 // seek back if that is the case.
3115 Point ptNew
= LocationFromPosition(posNew
.Position());
3116 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
3118 posNew
.SetVirtualSpace(0);
3119 ptNew
= LocationFromPosition(posNew
.Position());
3121 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
3122 // There is an equivalent case when moving down which skips
3124 Point ptNew
= LocationFromPosition(posNew
.Position());
3125 while ((posNew
.Position() > spStart
.Position()) && (ptNew
.y
> newY
)) {
3127 posNew
.SetVirtualSpace(0);
3128 ptNew
= LocationFromPosition(posNew
.Position());
3134 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
3135 if ((selt
== Selection::noSel
) && sel
.MoveExtends()) {
3136 selt
= Selection::selStream
;
3138 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
3139 if (sel
.IsRectangular()) {
3140 if (selt
== Selection::noSel
) {
3141 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
3143 caretToUse
= sel
.Rectangular().caret
;
3146 if (selt
== Selection::selRectangle
) {
3147 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3148 if (!sel
.IsRectangular()) {
3149 InvalidateWholeSelection();
3150 sel
.DropAdditionalRanges();
3152 const SelectionPosition posNew
= MovePositionSoVisible(
3153 PositionUpOrDown(caretToUse
, direction
, lastXChosen
), direction
);
3154 sel
.selType
= Selection::selRectangle
;
3155 sel
.Rectangular() = SelectionRange(posNew
, rangeBase
.anchor
);
3156 SetRectangularRange();
3157 MovedCaret(posNew
, caretToUse
, true);
3159 InvalidateWholeSelection();
3160 if (!additionalSelectionTyping
|| (sel
.IsRectangular())) {
3161 sel
.DropAdditionalRanges();
3163 sel
.selType
= Selection::selStream
;
3164 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3165 const int lastX
= (r
== sel
.Main()) ? lastXChosen
: -1;
3166 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3167 const SelectionPosition posNew
= MovePositionSoVisible(
3168 PositionUpOrDown(spCaretNow
, direction
, lastX
), direction
);
3169 sel
.Range(r
) = selt
== Selection::selStream
?
3170 SelectionRange(posNew
, sel
.Range(r
).anchor
) : SelectionRange(posNew
);
3172 sel
.RemoveDuplicates();
3173 MovedCaret(sel
.RangeMain().caret
, caretToUse
, true);
3177 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
3179 Sci::Position savedPos
= sel
.MainCaret();
3181 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
3182 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
3183 if (direction
> 0) {
3184 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
3185 if (selt
== Selection::noSel
) {
3186 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
3191 } while (!cs
.GetVisible(lineDoc
));
3194 Range
Editor::RangeDisplayLine(Sci::Line lineVisible
) {
3196 AutoSurface
surface(this);
3197 return view
.RangeDisplayLine(surface
, *this, lineVisible
, vs
);
3200 Sci::Position
Editor::StartEndDisplayLine(Sci::Position pos
, bool start
) {
3202 AutoSurface
surface(this);
3203 Sci::Position posRet
= view
.StartEndDisplayLine(surface
, *this, pos
, start
, vs
);
3204 if (posRet
== INVALID_POSITION
) {
3213 unsigned int WithExtends(unsigned int iMessage
) {
3215 case SCI_CHARLEFT
: return SCI_CHARLEFTEXTEND
;
3216 case SCI_CHARRIGHT
: return SCI_CHARRIGHTEXTEND
;
3218 case SCI_WORDLEFT
: return SCI_WORDLEFTEXTEND
;
3219 case SCI_WORDRIGHT
: return SCI_WORDRIGHTEXTEND
;
3220 case SCI_WORDLEFTEND
: return SCI_WORDLEFTENDEXTEND
;
3221 case SCI_WORDRIGHTEND
: return SCI_WORDRIGHTENDEXTEND
;
3222 case SCI_WORDPARTLEFT
: return SCI_WORDPARTLEFTEXTEND
;
3223 case SCI_WORDPARTRIGHT
: return SCI_WORDPARTRIGHTEXTEND
;
3225 case SCI_HOME
: return SCI_HOMEEXTEND
;
3226 case SCI_HOMEDISPLAY
: return SCI_HOMEDISPLAYEXTEND
;
3227 case SCI_HOMEWRAP
: return SCI_HOMEWRAPEXTEND
;
3228 case SCI_VCHOME
: return SCI_VCHOMEEXTEND
;
3229 case SCI_VCHOMEDISPLAY
: return SCI_VCHOMEDISPLAYEXTEND
;
3230 case SCI_VCHOMEWRAP
: return SCI_VCHOMEWRAPEXTEND
;
3232 case SCI_LINEEND
: return SCI_LINEENDEXTEND
;
3233 case SCI_LINEENDDISPLAY
: return SCI_LINEENDDISPLAYEXTEND
;
3234 case SCI_LINEENDWRAP
: return SCI_LINEENDWRAPEXTEND
;
3236 default: return iMessage
;
3240 int NaturalDirection(unsigned int iMessage
) {
3243 case SCI_CHARLEFTEXTEND
:
3244 case SCI_CHARLEFTRECTEXTEND
:
3246 case SCI_WORDLEFTEXTEND
:
3247 case SCI_WORDLEFTEND
:
3248 case SCI_WORDLEFTENDEXTEND
:
3249 case SCI_WORDPARTLEFT
:
3250 case SCI_WORDPARTLEFTEXTEND
:
3252 case SCI_HOMEEXTEND
:
3253 case SCI_HOMEDISPLAY
:
3254 case SCI_HOMEDISPLAYEXTEND
:
3256 case SCI_HOMEWRAPEXTEND
:
3257 // VC_HOME* mostly goes back
3259 case SCI_VCHOMEEXTEND
:
3260 case SCI_VCHOMEDISPLAY
:
3261 case SCI_VCHOMEDISPLAYEXTEND
:
3262 case SCI_VCHOMEWRAP
:
3263 case SCI_VCHOMEWRAPEXTEND
:
3271 bool IsRectExtend(unsigned int iMessage
) {
3273 case SCI_CHARLEFTRECTEXTEND
:
3274 case SCI_CHARRIGHTRECTEXTEND
:
3275 case SCI_HOMERECTEXTEND
:
3276 case SCI_VCHOMERECTEXTEND
:
3277 case SCI_LINEENDRECTEXTEND
:
3286 Sci::Position
Editor::VCHomeDisplayPosition(Sci::Position position
) {
3287 const Sci::Position homePos
= pdoc
->VCHomePosition(position
);
3288 const Sci::Position viewLineStart
= StartEndDisplayLine(position
, true);
3289 if (viewLineStart
> homePos
)
3290 return viewLineStart
;
3295 Sci::Position
Editor::VCHomeWrapPosition(Sci::Position position
) {
3296 const Sci::Position homePos
= pdoc
->VCHomePosition(position
);
3297 const Sci::Position viewLineStart
= StartEndDisplayLine(position
, true);
3298 if ((viewLineStart
< position
) && (viewLineStart
> homePos
))
3299 return viewLineStart
;
3304 Sci::Position
Editor::LineEndWrapPosition(Sci::Position position
) {
3305 const Sci::Position endPos
= StartEndDisplayLine(position
, false);
3306 const Sci::Position realEndPos
= pdoc
->LineEndPosition(position
);
3307 if (endPos
> realEndPos
// if moved past visible EOLs
3308 || position
>= endPos
) // if at end of display line already
3314 int Editor::HorizontalMove(unsigned int iMessage
) {
3315 if (sel
.MoveExtends()) {
3316 iMessage
= WithExtends(iMessage
);
3319 if (!multipleSelection
&& !sel
.IsRectangular()) {
3320 // Simplify selection down to 1
3321 sel
.SetSelection(sel
.RangeMain());
3324 // Invalidate each of the current selections
3325 InvalidateWholeSelection();
3327 if (IsRectExtend(iMessage
)) {
3328 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3329 if (!sel
.IsRectangular()) {
3330 sel
.DropAdditionalRanges();
3332 // Will change to rectangular if not currently rectangular
3333 SelectionPosition spCaret
= rangeBase
.caret
;
3335 case SCI_CHARLEFTRECTEXTEND
:
3336 if (pdoc
->IsLineEndPosition(spCaret
.Position()) && spCaret
.VirtualSpace()) {
3337 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3338 } else if ((virtualSpaceOptions
& SCVS_NOWRAPLINESTART
) == 0 || pdoc
->GetColumn(spCaret
.Position()) > 0) {
3339 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3342 case SCI_CHARRIGHTRECTEXTEND
:
3343 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3344 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3346 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3349 case SCI_HOMERECTEXTEND
:
3350 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3352 case SCI_VCHOMERECTEXTEND
:
3353 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3355 case SCI_LINEENDRECTEXTEND
:
3356 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3359 const int directionMove
= (spCaret
< rangeBase
.caret
) ? -1 : 1;
3360 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3361 sel
.selType
= Selection::selRectangle
;
3362 sel
.Rectangular() = SelectionRange(spCaret
, rangeBase
.anchor
);
3363 SetRectangularRange();
3364 } else if (sel
.IsRectangular()) {
3365 // Not a rectangular extension so switch to stream.
3366 const SelectionPosition selAtLimit
=
3367 (NaturalDirection(iMessage
) > 0) ? sel
.Limits().end
: sel
.Limits().start
;
3368 sel
.selType
= Selection::selStream
;
3369 sel
.SetSelection(SelectionRange(selAtLimit
));
3371 if (!additionalSelectionTyping
) {
3372 InvalidateWholeSelection();
3373 sel
.DropAdditionalRanges();
3375 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3376 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3377 SelectionPosition spCaret
= spCaretNow
;
3380 case SCI_CHARLEFTEXTEND
:
3381 if (spCaret
.VirtualSpace()) {
3382 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3383 } else if ((virtualSpaceOptions
& SCVS_NOWRAPLINESTART
) == 0 || pdoc
->GetColumn(spCaret
.Position()) > 0) {
3384 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3388 case SCI_CHARRIGHTEXTEND
:
3389 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(spCaret
.Position())) {
3390 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3392 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3396 case SCI_WORDLEFTEXTEND
:
3397 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), -1));
3400 case SCI_WORDRIGHTEXTEND
:
3401 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), 1));
3403 case SCI_WORDLEFTEND
:
3404 case SCI_WORDLEFTENDEXTEND
:
3405 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), -1));
3407 case SCI_WORDRIGHTEND
:
3408 case SCI_WORDRIGHTENDEXTEND
:
3409 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), 1));
3411 case SCI_WORDPARTLEFT
:
3412 case SCI_WORDPARTLEFTEXTEND
:
3413 spCaret
= SelectionPosition(pdoc
->WordPartLeft(spCaret
.Position()));
3415 case SCI_WORDPARTRIGHT
:
3416 case SCI_WORDPARTRIGHTEXTEND
:
3417 spCaret
= SelectionPosition(pdoc
->WordPartRight(spCaret
.Position()));
3420 case SCI_HOMEEXTEND
:
3421 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3423 case SCI_HOMEDISPLAY
:
3424 case SCI_HOMEDISPLAYEXTEND
:
3425 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), true));
3428 case SCI_HOMEWRAPEXTEND
:
3429 spCaret
= MovePositionSoVisible(StartEndDisplayLine(spCaret
.Position(), true), -1);
3430 if (spCaretNow
<= spCaret
)
3431 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3434 case SCI_VCHOMEEXTEND
:
3435 // VCHome alternates between beginning of line and beginning of text so may move back or forwards
3436 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3438 case SCI_VCHOMEDISPLAY
:
3439 case SCI_VCHOMEDISPLAYEXTEND
:
3440 spCaret
= SelectionPosition(VCHomeDisplayPosition(spCaret
.Position()));
3442 case SCI_VCHOMEWRAP
:
3443 case SCI_VCHOMEWRAPEXTEND
:
3444 spCaret
= SelectionPosition(VCHomeWrapPosition(spCaret
.Position()));
3447 case SCI_LINEENDEXTEND
:
3448 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3450 case SCI_LINEENDDISPLAY
:
3451 case SCI_LINEENDDISPLAYEXTEND
:
3452 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), false));
3454 case SCI_LINEENDWRAP
:
3455 case SCI_LINEENDWRAPEXTEND
:
3456 spCaret
= SelectionPosition(LineEndWrapPosition(spCaret
.Position()));
3460 PLATFORM_ASSERT(false);
3463 const int directionMove
= (spCaret
< spCaretNow
) ? -1 : 1;
3464 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3466 // Handle move versus extend, and special behaviour for non-empty left/right
3470 if (sel
.Range(r
).Empty()) {
3471 sel
.Range(r
) = SelectionRange(spCaret
);
3473 sel
.Range(r
) = SelectionRange(
3474 (iMessage
== SCI_CHARLEFT
) ? sel
.Range(r
).Start() : sel
.Range(r
).End());
3480 case SCI_WORDLEFTEND
:
3481 case SCI_WORDRIGHTEND
:
3482 case SCI_WORDPARTLEFT
:
3483 case SCI_WORDPARTRIGHT
:
3485 case SCI_HOMEDISPLAY
:
3488 case SCI_VCHOMEDISPLAY
:
3489 case SCI_VCHOMEWRAP
:
3491 case SCI_LINEENDDISPLAY
:
3492 case SCI_LINEENDWRAP
:
3493 sel
.Range(r
) = SelectionRange(spCaret
);
3496 case SCI_CHARLEFTEXTEND
:
3497 case SCI_CHARRIGHTEXTEND
:
3498 case SCI_WORDLEFTEXTEND
:
3499 case SCI_WORDRIGHTEXTEND
:
3500 case SCI_WORDLEFTENDEXTEND
:
3501 case SCI_WORDRIGHTENDEXTEND
:
3502 case SCI_WORDPARTLEFTEXTEND
:
3503 case SCI_WORDPARTRIGHTEXTEND
:
3504 case SCI_HOMEEXTEND
:
3505 case SCI_HOMEDISPLAYEXTEND
:
3506 case SCI_HOMEWRAPEXTEND
:
3507 case SCI_VCHOMEEXTEND
:
3508 case SCI_VCHOMEDISPLAYEXTEND
:
3509 case SCI_VCHOMEWRAPEXTEND
:
3510 case SCI_LINEENDEXTEND
:
3511 case SCI_LINEENDDISPLAYEXTEND
:
3512 case SCI_LINEENDWRAPEXTEND
: {
3513 SelectionRange rangeNew
= SelectionRange(spCaret
, sel
.Range(r
).anchor
);
3514 sel
.TrimOtherSelections(r
, SelectionRange(rangeNew
));
3515 sel
.Range(r
) = rangeNew
;
3520 PLATFORM_ASSERT(false);
3525 sel
.RemoveDuplicates();
3527 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3529 // Invalidate the new state of the selection
3530 InvalidateWholeSelection();
3533 // Need the line moving and so forth from MovePositionTo
3537 int Editor::DelWordOrLine(unsigned int iMessage
) {
3538 // Virtual space may be realised for SCI_DELWORDRIGHT or SCI_DELWORDRIGHTEND
3539 // which means 2 actions so wrap in an undo group.
3541 // Rightwards and leftwards deletions differ in treatment of virtual space.
3542 // Clear virtual space for leftwards, realise for rightwards.
3543 const bool leftwards
= (iMessage
== SCI_DELWORDLEFT
) || (iMessage
== SCI_DELLINELEFT
);
3545 if (!additionalSelectionTyping
) {
3546 InvalidateWholeSelection();
3547 sel
.DropAdditionalRanges();
3550 UndoGroup
ug0(pdoc
, (sel
.Count() > 1) || !leftwards
);
3552 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3554 // Delete to the left so first clear the virtual space.
3555 sel
.Range(r
).ClearVirtualSpace();
3557 // Delete to the right so first realise the virtual space.
3558 sel
.Range(r
) = SelectionRange(
3559 RealizeVirtualSpace(sel
.Range(r
).caret
));
3564 case SCI_DELWORDLEFT
:
3565 rangeDelete
= Range(
3566 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), -1),
3567 sel
.Range(r
).caret
.Position());
3569 case SCI_DELWORDRIGHT
:
3570 rangeDelete
= Range(
3571 sel
.Range(r
).caret
.Position(),
3572 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), 1));
3574 case SCI_DELWORDRIGHTEND
:
3575 rangeDelete
= Range(
3576 sel
.Range(r
).caret
.Position(),
3577 pdoc
->NextWordEnd(sel
.Range(r
).caret
.Position(), 1));
3579 case SCI_DELLINELEFT
:
3580 rangeDelete
= Range(
3581 pdoc
->LineStart(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())),
3582 sel
.Range(r
).caret
.Position());
3584 case SCI_DELLINERIGHT
:
3585 rangeDelete
= Range(
3586 sel
.Range(r
).caret
.Position(),
3587 pdoc
->LineEnd(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())));
3590 if (!RangeContainsProtected(rangeDelete
.start
, rangeDelete
.end
)) {
3591 pdoc
->DeleteChars(rangeDelete
.start
, rangeDelete
.end
- rangeDelete
.start
);
3595 // May need something stronger here: can selections overlap at this point?
3596 sel
.RemoveDuplicates();
3598 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3600 // Invalidate the new state of the selection
3601 InvalidateWholeSelection();
3607 int Editor::KeyCommand(unsigned int iMessage
) {
3610 CursorUpOrDown(1, Selection::noSel
);
3612 case SCI_LINEDOWNEXTEND
:
3613 CursorUpOrDown(1, Selection::selStream
);
3615 case SCI_LINEDOWNRECTEXTEND
:
3616 CursorUpOrDown(1, Selection::selRectangle
);
3619 ParaUpOrDown(1, Selection::noSel
);
3621 case SCI_PARADOWNEXTEND
:
3622 ParaUpOrDown(1, Selection::selStream
);
3624 case SCI_LINESCROLLDOWN
:
3625 ScrollTo(topLine
+ 1);
3626 MoveCaretInsideView(false);
3629 CursorUpOrDown(-1, Selection::noSel
);
3631 case SCI_LINEUPEXTEND
:
3632 CursorUpOrDown(-1, Selection::selStream
);
3634 case SCI_LINEUPRECTEXTEND
:
3635 CursorUpOrDown(-1, Selection::selRectangle
);
3638 ParaUpOrDown(-1, Selection::noSel
);
3640 case SCI_PARAUPEXTEND
:
3641 ParaUpOrDown(-1, Selection::selStream
);
3643 case SCI_LINESCROLLUP
:
3644 ScrollTo(topLine
- 1);
3645 MoveCaretInsideView(false);
3649 case SCI_CHARLEFTEXTEND
:
3650 case SCI_CHARLEFTRECTEXTEND
:
3652 case SCI_CHARRIGHTEXTEND
:
3653 case SCI_CHARRIGHTRECTEXTEND
:
3655 case SCI_WORDLEFTEXTEND
:
3657 case SCI_WORDRIGHTEXTEND
:
3658 case SCI_WORDLEFTEND
:
3659 case SCI_WORDLEFTENDEXTEND
:
3660 case SCI_WORDRIGHTEND
:
3661 case SCI_WORDRIGHTENDEXTEND
:
3662 case SCI_WORDPARTLEFT
:
3663 case SCI_WORDPARTLEFTEXTEND
:
3664 case SCI_WORDPARTRIGHT
:
3665 case SCI_WORDPARTRIGHTEXTEND
:
3667 case SCI_HOMEEXTEND
:
3668 case SCI_HOMERECTEXTEND
:
3669 case SCI_HOMEDISPLAY
:
3670 case SCI_HOMEDISPLAYEXTEND
:
3672 case SCI_HOMEWRAPEXTEND
:
3674 case SCI_VCHOMEEXTEND
:
3675 case SCI_VCHOMERECTEXTEND
:
3676 case SCI_VCHOMEDISPLAY
:
3677 case SCI_VCHOMEDISPLAYEXTEND
:
3678 case SCI_VCHOMEWRAP
:
3679 case SCI_VCHOMEWRAPEXTEND
:
3681 case SCI_LINEENDEXTEND
:
3682 case SCI_LINEENDRECTEXTEND
:
3683 case SCI_LINEENDDISPLAY
:
3684 case SCI_LINEENDDISPLAYEXTEND
:
3685 case SCI_LINEENDWRAP
:
3686 case SCI_LINEENDWRAPEXTEND
:
3687 return HorizontalMove(iMessage
);
3689 case SCI_DOCUMENTSTART
:
3693 case SCI_DOCUMENTSTARTEXTEND
:
3694 MovePositionTo(0, Selection::selStream
);
3697 case SCI_DOCUMENTEND
:
3698 MovePositionTo(pdoc
->Length());
3701 case SCI_DOCUMENTENDEXTEND
:
3702 MovePositionTo(pdoc
->Length(), Selection::selStream
);
3705 case SCI_STUTTEREDPAGEUP
:
3706 PageMove(-1, Selection::noSel
, true);
3708 case SCI_STUTTEREDPAGEUPEXTEND
:
3709 PageMove(-1, Selection::selStream
, true);
3711 case SCI_STUTTEREDPAGEDOWN
:
3712 PageMove(1, Selection::noSel
, true);
3714 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3715 PageMove(1, Selection::selStream
, true);
3720 case SCI_PAGEUPEXTEND
:
3721 PageMove(-1, Selection::selStream
);
3723 case SCI_PAGEUPRECTEXTEND
:
3724 PageMove(-1, Selection::selRectangle
);
3729 case SCI_PAGEDOWNEXTEND
:
3730 PageMove(1, Selection::selStream
);
3732 case SCI_PAGEDOWNRECTEXTEND
:
3733 PageMove(1, Selection::selRectangle
);
3735 case SCI_EDITTOGGLEOVERTYPE
:
3736 inOverstrike
= !inOverstrike
;
3737 ShowCaretAtCurrentPosition();
3738 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
3741 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3742 // Also unselect text
3744 if ((sel
.Count() > 1) && !sel
.IsRectangular()) {
3745 // Drop additional selections
3746 InvalidateWholeSelection();
3747 sel
.DropAdditionalRanges();
3750 case SCI_DELETEBACK
:
3752 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3755 EnsureCaretVisible();
3757 case SCI_DELETEBACKNOTLINE
:
3759 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3762 EnsureCaretVisible();
3766 if (caretSticky
== SC_CARETSTICKY_OFF
) {
3769 EnsureCaretVisible();
3770 ShowCaretAtCurrentPosition(); // Avoid blinking
3774 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3777 EnsureCaretVisible();
3778 ShowCaretAtCurrentPosition(); // Avoid blinking
3787 if (vs
.zoomLevel
< 20) {
3789 InvalidateStyleRedraw();
3794 if (vs
.zoomLevel
> -10) {
3796 InvalidateStyleRedraw();
3801 case SCI_DELWORDLEFT
:
3802 case SCI_DELWORDRIGHT
:
3803 case SCI_DELWORDRIGHTEND
:
3804 case SCI_DELLINELEFT
:
3805 case SCI_DELLINERIGHT
:
3806 return DelWordOrLine(iMessage
);
3808 case SCI_LINECOPY
: {
3809 const Sci::Line lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3810 const Sci::Line lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3811 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3812 pdoc
->LineStart(lineEnd
+ 1));
3816 const Sci::Line lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3817 const Sci::Line lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3818 const Sci::Position start
= pdoc
->LineStart(lineStart
);
3819 const Sci::Position end
= pdoc
->LineStart(lineEnd
+ 1);
3820 SetSelection(start
, end
);
3825 case SCI_LINEDELETE
: {
3826 const Sci::Line line
= pdoc
->LineFromPosition(sel
.MainCaret());
3827 const Sci::Position start
= pdoc
->LineStart(line
);
3828 const Sci::Position end
= pdoc
->LineStart(line
+ 1);
3829 pdoc
->DeleteChars(start
, end
- start
);
3832 case SCI_LINETRANSPOSE
:
3835 case SCI_LINEREVERSE
:
3838 case SCI_LINEDUPLICATE
:
3841 case SCI_SELECTIONDUPLICATE
:
3845 ChangeCaseOfSelection(cmLower
);
3848 ChangeCaseOfSelection(cmUpper
);
3850 case SCI_SCROLLTOSTART
:
3853 case SCI_SCROLLTOEND
:
3854 ScrollTo(MaxScrollPos());
3860 int Editor::KeyDefault(int, int) {
3864 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
3866 int msg
= kmap
.Find(key
, modifiers
);
3870 return static_cast<int>(WndProc(msg
, 0, 0));
3874 return KeyDefault(key
, modifiers
);
3878 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3879 return KeyDownWithModifiers(key
, ModifierFlags(shift
, ctrl
, alt
), consumed
);
3882 void Editor::Indent(bool forwards
) {
3884 for (size_t r
=0; r
<sel
.Count(); r
++) {
3885 Sci::Line lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
3886 Sci::Position caretPosition
= sel
.Range(r
).caret
.Position();
3887 Sci::Line lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
3888 if (lineOfAnchor
== lineCurrentPos
) {
3890 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
3891 caretPosition
= sel
.Range(r
).caret
.Position();
3892 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3894 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3895 int indentationStep
= pdoc
->IndentSize();
3896 const Sci::Position posSelect
= pdoc
->SetLineIndentation(
3897 lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
3898 sel
.Range(r
) = SelectionRange(posSelect
);
3900 if (pdoc
->useTabs
) {
3901 const Sci::Position lengthInserted
= pdoc
->InsertString(caretPosition
, "\t", 1);
3902 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3904 int numSpaces
= (pdoc
->tabInChars
) -
3905 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
3907 numSpaces
= pdoc
->tabInChars
;
3908 const std::string
spaceText(numSpaces
, ' ');
3909 const Sci::Position lengthInserted
= pdoc
->InsertString(caretPosition
, spaceText
.c_str(),
3910 static_cast<Sci::Position
>(spaceText
.length()));
3911 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3915 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3917 const int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3918 const int indentationStep
= pdoc
->IndentSize();
3919 const Sci::Position posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3920 sel
.Range(r
) = SelectionRange(posSelect
);
3922 Sci::Position newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
3926 Sci::Position newPos
= caretPosition
;
3927 while (pdoc
->GetColumn(newPos
) > newColumn
)
3929 sel
.Range(r
) = SelectionRange(newPos
);
3932 } else { // Multiline
3933 const Sci::Position anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
3934 const Sci::Position currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
3935 // Multiple lines selected so indent / dedent
3936 const Sci::Line lineTopSel
= std::min(lineOfAnchor
, lineCurrentPos
);
3937 Sci::Line lineBottomSel
= std::max(lineOfAnchor
, lineCurrentPos
);
3938 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
3939 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3940 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3941 if (lineOfAnchor
< lineCurrentPos
) {
3942 if (currentPosPosOnLine
== 0)
3943 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3945 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3947 if (anchorPosOnLine
== 0)
3948 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3950 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3954 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
3957 class CaseFolderASCII
: public CaseFolderTable
{
3962 ~CaseFolderASCII() override
{
3967 CaseFolder
*Editor::CaseFolderForEncoding() {
3968 // Simple default that only maps ASCII upper case to lower case.
3969 return new CaseFolderASCII();
3973 * Search of a text in the document, in the given range.
3974 * @return The position of the found text, -1 if not found.
3976 long Editor::FindText(
3977 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3978 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3979 sptr_t lParam
) { ///< @c Sci_TextToFind structure: The text to search for in the given range.
3981 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
3982 Sci::Position lengthFound
= istrlen(ft
->lpstrText
);
3983 if (!pdoc
->HasCaseFolder())
3984 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3986 long pos
= pdoc
->FindText(
3987 static_cast<Sci::Position
>(ft
->chrg
.cpMin
),
3988 static_cast<Sci::Position
>(ft
->chrg
.cpMax
),
3990 static_cast<int>(wParam
),
3993 ft
->chrgText
.cpMin
= pos
;
3994 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3996 return static_cast<int>(pos
);
3997 } catch (RegexError
&) {
3998 errorStatus
= SC_STATUS_WARN_REGEX
;
4004 * Relocatable search support : Searches relative to current selection
4005 * point and sets the selection to the found text range with
4009 * Anchor following searches at current selection start: This allows
4010 * multiple incremental interactive searches to be macro recorded
4011 * while still setting the selection to found text so the find/select
4012 * operation is self-contained.
4014 void Editor::SearchAnchor() {
4015 searchAnchor
= SelectionStart().Position();
4019 * Find text from current search anchor: Must call @c SearchAnchor first.
4020 * Used for next text and previous text requests.
4021 * @return The position of the found text, -1 if not found.
4023 long Editor::SearchText(
4024 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
4025 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
4026 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4027 sptr_t lParam
) { ///< The text to search for.
4029 const char *txt
= reinterpret_cast<char *>(lParam
);
4031 Sci::Position lengthFound
= istrlen(txt
);
4032 if (!pdoc
->HasCaseFolder())
4033 pdoc
->SetCaseFolder(CaseFolderForEncoding());
4035 if (iMessage
== SCI_SEARCHNEXT
) {
4036 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4037 static_cast<int>(wParam
),
4040 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4041 static_cast<int>(wParam
),
4044 } catch (RegexError
&) {
4045 errorStatus
= SC_STATUS_WARN_REGEX
;
4049 SetSelection(static_cast<int>(pos
), static_cast<int>(pos
+ lengthFound
));
4055 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
4057 for (char &ch
: ret
) {
4058 switch (caseMapping
) {
4060 if (ch
>= 'a' && ch
<= 'z')
4061 ch
= static_cast<char>(ch
- 'a' + 'A');
4064 if (ch
>= 'A' && ch
<= 'Z')
4065 ch
= static_cast<char>(ch
- 'A' + 'a');
4073 * Search for text in the target range of the document.
4074 * @return The position of the found text, -1 if not found.
4076 long Editor::SearchInTarget(const char *text
, Sci::Position length
) {
4077 Sci::Position lengthFound
= length
;
4079 if (!pdoc
->HasCaseFolder())
4080 pdoc
->SetCaseFolder(CaseFolderForEncoding());
4082 long pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4086 targetStart
= static_cast<int>(pos
);
4087 targetEnd
= static_cast<int>(pos
+ lengthFound
);
4090 } catch (RegexError
&) {
4091 errorStatus
= SC_STATUS_WARN_REGEX
;
4096 void Editor::GoToLine(Sci::Line lineNo
) {
4097 if (lineNo
> pdoc
->LinesTotal())
4098 lineNo
= pdoc
->LinesTotal();
4101 SetEmptySelection(pdoc
->LineStart(lineNo
));
4102 ShowCaretAtCurrentPosition();
4103 EnsureCaretVisible();
4106 static bool Close(Point pt1
, Point pt2
, Point threshold
) {
4107 if (std::abs(pt1
.x
- pt2
.x
) > threshold
.x
)
4109 if (std::abs(pt1
.y
- pt2
.y
) > threshold
.y
)
4114 std::string
Editor::RangeText(Sci::Position start
, Sci::Position end
) const {
4116 Sci::Position len
= end
- start
;
4117 std::string
ret(len
, '\0');
4118 for (int i
= 0; i
< len
; i
++) {
4119 ret
[i
] = pdoc
->CharAt(start
+ i
);
4123 return std::string();
4126 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
4128 if (allowLineCopy
) {
4129 Sci::Line currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4130 Sci::Position start
= pdoc
->LineStart(currentLine
);
4131 Sci::Position end
= pdoc
->LineEnd(currentLine
);
4133 std::string text
= RangeText(start
, end
);
4134 if (pdoc
->eolMode
!= SC_EOL_LF
)
4135 text
.push_back('\r');
4136 if (pdoc
->eolMode
!= SC_EOL_CR
)
4137 text
.push_back('\n');
4138 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4139 vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
4143 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
4144 if (sel
.selType
== Selection::selRectangle
)
4145 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
4146 for (const SelectionRange
¤t
: rangesInOrder
) {
4147 text
.append(RangeText(current
.Start().Position(), current
.End().Position()));
4148 if (sel
.selType
== Selection::selRectangle
) {
4149 if (pdoc
->eolMode
!= SC_EOL_LF
)
4150 text
.push_back('\r');
4151 if (pdoc
->eolMode
!= SC_EOL_CR
)
4152 text
.push_back('\n');
4155 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4156 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
4160 void Editor::CopyRangeToClipboard(Sci::Position start
, Sci::Position end
) {
4161 start
= pdoc
->ClampPositionIntoDocument(start
);
4162 end
= pdoc
->ClampPositionIntoDocument(end
);
4163 SelectionText selectedText
;
4164 std::string text
= RangeText(start
, end
);
4165 selectedText
.Copy(text
,
4166 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4167 CopyToClipboard(selectedText
);
4170 void Editor::CopyText(int length
, const char *text
) {
4171 SelectionText selectedText
;
4172 selectedText
.Copy(std::string(text
, length
),
4173 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4174 CopyToClipboard(selectedText
);
4177 void Editor::SetDragPosition(SelectionPosition newPos
) {
4178 if (newPos
.Position() >= 0) {
4179 newPos
= MovePositionOutsideChar(newPos
, 1);
4182 if (!(posDrag
== newPos
)) {
4184 if (FineTickerAvailable()) {
4185 FineTickerCancel(tickCaret
);
4186 if ((caret
.active
) && (caret
.period
> 0) && (newPos
.Position() < 0))
4187 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
4197 void Editor::DisplayCursor(Window::Cursor c
) {
4198 if (cursorMode
== SC_CURSORNORMAL
)
4201 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4204 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
4205 const int xMove
= static_cast<int>(ptStart
.x
- ptNow
.x
);
4206 const int yMove
= static_cast<int>(ptStart
.y
- ptNow
.y
);
4207 const int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
4208 return distanceSquared
> 16;
4211 void Editor::StartDrag() {
4212 // Always handled by subclasses
4213 //SetMouseCapture(true);
4214 //DisplayCursor(Window::cursorArrow);
4217 void Editor::DropAt(SelectionPosition position
, const char *value
, size_t lengthValue
, bool moving
, bool rectangular
) {
4218 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
4219 if (inDragDrop
== ddDragging
)
4220 dropWentOutside
= false;
4222 const bool positionWasInSelection
= PositionInSelection(position
.Position());
4224 const bool positionOnEdgeOfSelection
=
4225 (position
== SelectionStart()) || (position
== SelectionEnd());
4227 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
4228 (positionOnEdgeOfSelection
&& !moving
)) {
4230 SelectionPosition selStart
= SelectionStart();
4231 SelectionPosition selEnd
= SelectionEnd();
4235 SelectionPosition positionAfterDeletion
= position
;
4236 if ((inDragDrop
== ddDragging
) && moving
) {
4237 // Remove dragged out text
4238 if (rectangular
|| sel
.selType
== Selection::selLines
) {
4239 for (size_t r
=0; r
<sel
.Count(); r
++) {
4240 if (position
>= sel
.Range(r
).Start()) {
4241 if (position
> sel
.Range(r
).End()) {
4242 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
4244 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
4249 if (position
> selStart
) {
4250 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
4255 position
= positionAfterDeletion
;
4257 std::string convertedText
= Document::TransformLineEnds(value
, lengthValue
, pdoc
->eolMode
);
4260 PasteRectangular(position
, convertedText
.c_str(), static_cast<Sci::Position
>(convertedText
.length()));
4261 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4262 SetEmptySelection(position
);
4264 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
4265 position
= RealizeVirtualSpace(position
);
4266 const Sci::Position lengthInserted
= pdoc
->InsertString(
4267 position
.Position(), convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4268 if (lengthInserted
> 0) {
4269 SelectionPosition posAfterInsertion
= position
;
4270 posAfterInsertion
.Add(lengthInserted
);
4271 SetSelection(posAfterInsertion
, position
);
4274 } else if (inDragDrop
== ddDragging
) {
4275 SetEmptySelection(position
);
4279 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
4280 DropAt(position
, value
, strlen(value
), moving
, rectangular
);
4284 * @return true if given position is inside the selection,
4286 bool Editor::PositionInSelection(Sci::Position pos
) {
4287 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
4288 for (size_t r
=0; r
<sel
.Count(); r
++) {
4289 if (sel
.Range(r
).Contains(pos
))
4295 bool Editor::PointInSelection(Point pt
) {
4296 const SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
4297 const Point ptPos
= LocationFromPosition(pos
);
4298 for (size_t r
=0; r
<sel
.Count(); r
++) {
4299 const SelectionRange
&range
= sel
.Range(r
);
4300 if (range
.Contains(pos
)) {
4302 if (pos
== range
.Start()) {
4303 // see if just before selection
4304 if (pt
.x
< ptPos
.x
) {
4308 if (pos
== range
.End()) {
4309 // see if just after selection
4310 if (pt
.x
> ptPos
.x
) {
4321 bool Editor::PointInSelMargin(Point pt
) const {
4322 // Really means: "Point in a margin"
4323 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4324 PRectangle rcSelMargin
= GetClientRectangle();
4325 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.leftMarginWidth
);
4326 rcSelMargin
.left
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.fixedColumnWidth
);
4327 return rcSelMargin
.ContainsWholePixel(pt
);
4333 Window::Cursor
Editor::GetMarginCursor(Point pt
) const {
4335 for (const MarginStyle
&m
: vs
.ms
) {
4336 if ((pt
.x
>= x
) && (pt
.x
< x
+ m
.width
))
4337 return static_cast<Window::Cursor
>(m
.cursor
);
4340 return Window::cursorReverseArrow
;
4343 void Editor::TrimAndSetSelection(Sci::Position currentPos_
, Sci::Position anchor_
) {
4344 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
4345 SetSelection(currentPos_
, anchor_
);
4348 void Editor::LineSelection(Sci::Position lineCurrentPos_
, Sci::Position lineAnchorPos_
, bool wholeLine
) {
4349 Sci::Position selCurrentPos
, selAnchorPos
;
4351 Sci::Line lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
4352 Sci::Line lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
4353 if (lineAnchorPos_
< lineCurrentPos_
) {
4354 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
4355 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4356 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4357 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
4358 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4359 } else { // Same line, select it
4360 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4361 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4364 if (lineAnchorPos_
< lineCurrentPos_
) {
4365 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
4366 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4367 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4368 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4369 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
4370 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4371 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
4372 } else { // Same line, select it
4373 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4374 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4375 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4378 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
4381 void Editor::WordSelection(Sci::Position pos
) {
4382 if (pos
< wordSelectAnchorStartPos
) {
4383 // Extend backward to the word containing pos.
4384 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
4385 // This ensures that a series of empty lines isn't counted as a single "word".
4386 if (!pdoc
->IsLineEndPosition(pos
))
4387 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
4388 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
4389 } else if (pos
> wordSelectAnchorEndPos
) {
4390 // Extend forward to the word containing the character to the left of pos.
4391 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
4392 // This ensures that a series of empty lines isn't counted as a single "word".
4393 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
4394 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
4395 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
4397 // Select only the anchored word
4398 if (pos
>= originalAnchorPos
)
4399 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
4401 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
4405 void Editor::DwellEnd(bool mouseMoved
) {
4407 ticksToDwell
= dwellDelay
;
4409 ticksToDwell
= SC_TIME_FOREVER
;
4410 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4412 NotifyDwelling(ptMouseLast
, dwelling
);
4414 if (FineTickerAvailable()) {
4415 FineTickerCancel(tickDwell
);
4416 if (mouseMoved
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4417 //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
4422 void Editor::MouseLeave() {
4423 SetHotSpotRange(NULL
);
4424 if (!HaveMouseCapture()) {
4425 ptMouseLast
= Point(-1,-1);
4430 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
4431 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
4432 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
4435 void Editor::ButtonDownWithModifiers(Point pt
, unsigned int curTime
, int modifiers
) {
4436 SetHoverIndicatorPoint(pt
);
4437 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
4439 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
4440 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
4441 const bool alt
= (modifiers
& SCI_ALT
) != 0;
4442 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
4443 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4444 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4445 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4446 inDragDrop
= ddNone
;
4447 sel
.SetMoveExtends(false);
4449 if (NotifyMarginClick(pt
, modifiers
))
4452 NotifyIndicatorClick(true, newPos
.Position(), modifiers
);
4454 const bool inSelMargin
= PointInSelMargin(pt
);
4455 // In margin ctrl+(double)click should always select everything
4456 if (ctrl
&& inSelMargin
) {
4458 lastClickTime
= curTime
;
4462 if (shift
&& !inSelMargin
) {
4463 SetSelection(newPos
);
4465 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
, doubleClickCloseThreshold
)) {
4466 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4467 SetMouseCapture(true);
4468 if (FineTickerAvailable()) {
4469 FineTickerStart(tickScroll
, 100, 10);
4471 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
4472 SetEmptySelection(newPos
.Position());
4473 bool doubleClick
= false;
4474 // Stop mouse button bounce changing selection type
4475 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4477 // Inside margin selection type should be either selSubLine or selWholeLine.
4478 if (selectionType
== selSubLine
) {
4479 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
4480 // so we switch to selWholeLine in order to select whole line.
4481 selectionType
= selWholeLine
;
4482 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
4483 // If it is neither, reset selection type to line selection.
4484 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4487 if (selectionType
== selChar
) {
4488 selectionType
= selWord
;
4490 } else if (selectionType
== selWord
) {
4491 // Since we ended up here, we're inside a *triple* click, which should always select
4492 // whole line regardless of word wrap being enabled or not.
4493 selectionType
= selWholeLine
;
4495 selectionType
= selChar
;
4496 originalAnchorPos
= sel
.MainCaret();
4501 if (selectionType
== selWord
) {
4502 Sci::Position charPos
= originalAnchorPos
;
4503 if (sel
.MainCaret() == originalAnchorPos
) {
4504 charPos
= PositionFromLocation(pt
, false, true);
4505 charPos
= MovePositionOutsideChar(charPos
, -1);
4508 Sci::Position startWord
, endWord
;
4509 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
4510 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
4511 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
4513 // Selecting backwards, or anchor beyond last character on line. In these cases,
4514 // we select the word containing the character to the *left* of the anchor.
4515 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
4516 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
4517 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
4519 // Anchor at start of line; select nothing to begin with.
4520 startWord
= charPos
;
4525 wordSelectAnchorStartPos
= startWord
;
4526 wordSelectAnchorEndPos
= endWord
;
4527 wordSelectInitialCaretPos
= sel
.MainCaret();
4528 WordSelection(wordSelectInitialCaretPos
);
4529 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
4530 lineAnchorPos
= newPos
.Position();
4531 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4532 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4534 SetEmptySelection(sel
.MainCaret());
4536 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4538 NotifyDoubleClick(pt
, modifiers
);
4539 if (PositionIsHotspot(newCharPos
.Position()))
4540 NotifyHotSpotDoubleClicked(newCharPos
.Position(), modifiers
);
4542 } else { // Single click
4544 if (sel
.IsRectangular() || (sel
.Count() > 1)) {
4545 InvalidateWholeSelection();
4548 sel
.selType
= Selection::selStream
;
4550 // Single click in margin: select whole line or only subline if word wrap is enabled
4551 lineAnchorPos
= newPos
.Position();
4552 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4553 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4555 // Single shift+click in margin: select from line anchor to clicked line
4556 if (sel
.MainAnchor() > sel
.MainCaret())
4557 lineAnchorPos
= sel
.MainAnchor() - 1;
4559 lineAnchorPos
= sel
.MainAnchor();
4560 // Reset selection type if there is an empty selection.
4561 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
4562 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
4563 // This ensures that we continue selecting in the same selection mode.
4564 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
4565 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4566 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4569 SetDragPosition(SelectionPosition(Sci::invalidPosition
));
4570 SetMouseCapture(true);
4571 if (FineTickerAvailable()) {
4572 FineTickerStart(tickScroll
, 100, 10);
4575 if (PointIsHotspot(pt
)) {
4576 NotifyHotSpotClicked(newCharPos
.Position(), modifiers
);
4577 hotSpotClickPos
= newCharPos
.Position();
4580 if (PointInSelection(pt
) && !SelectionEmpty())
4581 inDragDrop
= ddInitial
;
4583 inDragDrop
= ddNone
;
4585 SetMouseCapture(true);
4586 if (FineTickerAvailable()) {
4587 FineTickerStart(tickScroll
, 100, 10);
4589 if (inDragDrop
!= ddInitial
) {
4590 SetDragPosition(SelectionPosition(Sci::invalidPosition
));
4592 if (ctrl
&& multipleSelection
) {
4593 SelectionRange
range(newPos
);
4594 sel
.TentativeSelection(range
);
4595 InvalidateSelection(range
, true);
4597 InvalidateSelection(SelectionRange(newPos
), true);
4598 if (sel
.Count() > 1)
4600 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
4602 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4603 SetSelection(newPos
, newPos
);
4606 SelectionPosition anchorCurrent
= newPos
;
4608 anchorCurrent
= sel
.IsRectangular() ?
4609 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
4610 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4611 selectionType
= selChar
;
4612 originalAnchorPos
= sel
.MainCaret();
4613 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
4614 SetRectangularRange();
4618 lastClickTime
= curTime
;
4620 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4621 ShowCaretAtCurrentPosition();
4624 void Editor::RightButtonDownWithModifiers(Point pt
, unsigned int, int modifiers
) {
4625 if (NotifyMarginRightClick(pt
, modifiers
))
4629 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4630 return ButtonDownWithModifiers(pt
, curTime
, ModifierFlags(shift
, ctrl
, alt
));
4633 bool Editor::PositionIsHotspot(Sci::Position position
) const {
4634 return vs
.styles
[pdoc
->StyleIndexAt(position
)].hotspot
;
4637 bool Editor::PointIsHotspot(Point pt
) {
4638 Sci::Position pos
= PositionFromLocation(pt
, true, true);
4639 if (pos
== INVALID_POSITION
)
4641 return PositionIsHotspot(pos
);
4644 void Editor::SetHoverIndicatorPosition(Sci::Position position
) {
4645 const Sci::Position hoverIndicatorPosPrev
= hoverIndicatorPos
;
4646 hoverIndicatorPos
= INVALID_POSITION
;
4647 if (!vs
.indicatorsDynamic
)
4649 if (position
!= INVALID_POSITION
) {
4650 for (const Decoration
*deco
: pdoc
->decorations
.View()) {
4651 if (vs
.indicators
[deco
->Indicator()].IsDynamic()) {
4652 if (pdoc
->decorations
.ValueAt(deco
->Indicator(), position
)) {
4653 hoverIndicatorPos
= position
;
4658 if (hoverIndicatorPosPrev
!= hoverIndicatorPos
) {
4663 void Editor::SetHoverIndicatorPoint(Point pt
) {
4664 if (!vs
.indicatorsDynamic
) {
4665 SetHoverIndicatorPosition(INVALID_POSITION
);
4667 SetHoverIndicatorPosition(PositionFromLocation(pt
, true, true));
4671 void Editor::SetHotSpotRange(Point
*pt
) {
4673 Sci::Position pos
= PositionFromLocation(*pt
, false, true);
4675 // If we don't limit this to word characters then the
4676 // range can encompass more than the run range and then
4677 // the underline will not be drawn properly.
4679 hsNew
.start
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4680 hsNew
.end
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4682 // Only invalidate the range if the hotspot range has changed...
4683 if (!(hsNew
== hotspot
)) {
4684 if (hotspot
.Valid()) {
4685 InvalidateRange(hotspot
.start
, hotspot
.end
);
4688 InvalidateRange(hotspot
.start
, hotspot
.end
);
4691 if (hotspot
.Valid()) {
4692 InvalidateRange(hotspot
.start
, hotspot
.end
);
4694 hotspot
= Range(Sci::invalidPosition
);
4698 Range
Editor::GetHotSpotRange() const {
4702 void Editor::ButtonMoveWithModifiers(Point pt
, int modifiers
) {
4703 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4707 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
4708 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4709 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
4711 if (inDragDrop
== ddInitial
) {
4712 if (DragThreshold(ptMouseLast
, pt
)) {
4713 SetMouseCapture(false);
4714 if (FineTickerAvailable()) {
4715 FineTickerCancel(tickScroll
);
4717 SetDragPosition(movePos
);
4718 CopySelectionRange(&drag
);
4725 PRectangle rcClient
= GetClientRectangle();
4726 Point ptOrigin
= GetVisibleOriginInMain();
4727 rcClient
.Move(0, -ptOrigin
.y
);
4728 if (FineTickerAvailable() && (dwellDelay
< SC_TIME_FOREVER
) && rcClient
.Contains(pt
)) {
4729 FineTickerStart(tickDwell
, dwellDelay
, dwellDelay
/10);
4731 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4732 if (HaveMouseCapture()) {
4734 // Slow down autoscrolling/selection
4735 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4736 if (autoScrollTimer
.ticksToWait
> 0)
4738 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4741 if (posDrag
.IsValid()) {
4742 SetDragPosition(movePos
);
4744 if (selectionType
== selChar
) {
4745 if (sel
.selType
== Selection::selStream
&& (modifiers
& SCI_ALT
) && mouseSelectionRectangularSwitch
) {
4746 sel
.selType
= Selection::selRectangle
;
4748 if (sel
.IsRectangular()) {
4749 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
4750 SetSelection(movePos
, sel
.RangeMain().anchor
);
4751 } else if (sel
.Count() > 1) {
4752 InvalidateSelection(sel
.RangeMain(), false);
4753 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
4754 sel
.TentativeSelection(range
);
4755 InvalidateSelection(range
, true);
4757 SetSelection(movePos
, sel
.RangeMain().anchor
);
4759 } else if (selectionType
== selWord
) {
4760 // Continue selecting by word
4761 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
4762 // No need to do anything. Previously this case was lumped
4763 // in with "Moved forward", but that can be harmful in this
4764 // case: a handler for the NotifyDoubleClick re-adjusts
4765 // the selection for a fancier definition of "word" (for
4766 // example, in Perl it is useful to include the leading
4767 // '$', '%' or '@' on variables for word selection). In this
4768 // the ButtonMove() called via Tick() for auto-scrolling
4769 // could result in the fancier word selection adjustment
4772 wordSelectInitialCaretPos
= -1;
4773 WordSelection(movePos
.Position());
4776 // Continue selecting by line
4777 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4782 Sci::Line lineMove
= DisplayFromPosition(movePos
.Position());
4783 if (pt
.y
> rcClient
.bottom
) {
4784 ScrollTo(lineMove
- LinesOnScreen() + 1);
4786 } else if (pt
.y
< rcClient
.top
) {
4790 EnsureCaretVisible(false, false, true);
4792 if (hotspot
.Valid() && !PointIsHotspot(pt
))
4793 SetHotSpotRange(NULL
);
4795 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,true) != hotSpotClickPos
) {
4796 if (inDragDrop
== ddNone
) {
4797 DisplayCursor(Window::cursorText
);
4799 hotSpotClickPos
= INVALID_POSITION
;
4803 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4804 if (PointInSelMargin(pt
)) {
4805 DisplayCursor(GetMarginCursor(pt
));
4806 SetHotSpotRange(NULL
);
4807 return; // No need to test for selection
4810 // Display regular (drag) cursor over selection
4811 if (PointInSelection(pt
) && !SelectionEmpty()) {
4812 DisplayCursor(Window::cursorArrow
);
4814 SetHoverIndicatorPoint(pt
);
4815 if (PointIsHotspot(pt
)) {
4816 DisplayCursor(Window::cursorHand
);
4817 SetHotSpotRange(&pt
);
4819 if (hoverIndicatorPos
!= Sci::invalidPosition
)
4820 DisplayCursor(Window::cursorHand
);
4822 DisplayCursor(Window::cursorText
);
4823 SetHotSpotRange(NULL
);
4829 void Editor::ButtonMove(Point pt
) {
4830 ButtonMoveWithModifiers(pt
, 0);
4833 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4834 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
4835 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
4836 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4837 if (hoverIndicatorPos
!= INVALID_POSITION
)
4838 InvalidateRange(newPos
.Position(), newPos
.Position() + 1);
4839 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4840 if (inDragDrop
== ddInitial
) {
4841 inDragDrop
= ddNone
;
4842 SetEmptySelection(newPos
);
4843 selectionType
= selChar
;
4844 originalAnchorPos
= sel
.MainCaret();
4846 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
4847 hotSpotClickPos
= INVALID_POSITION
;
4848 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4849 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4850 NotifyHotSpotReleaseClick(newCharPos
.Position(), ctrl
? SCI_CTRL
: 0);
4852 if (HaveMouseCapture()) {
4853 if (PointInSelMargin(pt
)) {
4854 DisplayCursor(GetMarginCursor(pt
));
4856 DisplayCursor(Window::cursorText
);
4857 SetHotSpotRange(NULL
);
4860 SetMouseCapture(false);
4861 if (FineTickerAvailable()) {
4862 FineTickerCancel(tickScroll
);
4864 NotifyIndicatorClick(false, newPos
.Position(), 0);
4865 if (inDragDrop
== ddDragging
) {
4866 SelectionPosition selStart
= SelectionStart();
4867 SelectionPosition selEnd
= SelectionEnd();
4868 if (selStart
< selEnd
) {
4869 if (drag
.Length()) {
4870 const int length
= static_cast<int>(drag
.Length());
4872 const Sci::Position lengthInserted
= pdoc
->InsertString(
4873 newPos
.Position(), drag
.Data(), length
);
4874 if (lengthInserted
> 0) {
4875 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4877 } else if (newPos
< selStart
) {
4878 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4879 const Sci::Position lengthInserted
= pdoc
->InsertString(
4880 newPos
.Position(), drag
.Data(), length
);
4881 if (lengthInserted
> 0) {
4882 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4884 } else if (newPos
> selEnd
) {
4885 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4886 newPos
.Add(-static_cast<int>(drag
.Length()));
4887 const Sci::Position lengthInserted
= pdoc
->InsertString(
4888 newPos
.Position(), drag
.Data(), length
);
4889 if (lengthInserted
> 0) {
4890 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4893 SetEmptySelection(newPos
.Position());
4897 selectionType
= selChar
;
4900 if (selectionType
== selChar
) {
4901 if (sel
.Count() > 1) {
4903 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
4904 InvalidateWholeSelection();
4906 SetSelection(newPos
, sel
.RangeMain().anchor
);
4909 sel
.CommitTentative();
4911 SetRectangularRange();
4912 lastClickTime
= curTime
;
4914 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4915 if (sel
.selType
== Selection::selStream
) {
4918 inDragDrop
= ddNone
;
4919 EnsureCaretVisible(false);
4923 // Called frequently to perform background UI including
4924 // caret blinking and automatic scrolling.
4925 void Editor::Tick() {
4926 if (HaveMouseCapture()) {
4928 ButtonMove(ptMouseLast
);
4930 if (caret
.period
> 0) {
4931 timer
.ticksToWait
-= timer
.tickSize
;
4932 if (timer
.ticksToWait
<= 0) {
4933 caret
.on
= !caret
.on
;
4934 timer
.ticksToWait
= caret
.period
;
4940 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
4941 scrollWidth
= view
.lineWidthMaxSeen
;
4944 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4945 (ticksToDwell
> 0) &&
4946 (!HaveMouseCapture()) &&
4947 (ptMouseLast
.y
>= 0)) {
4948 ticksToDwell
-= timer
.tickSize
;
4949 if (ticksToDwell
<= 0) {
4951 NotifyDwelling(ptMouseLast
, dwelling
);
4956 bool Editor::Idle() {
4957 bool needWrap
= Wrapping() && wrapPending
.NeedsWrap();
4960 // Wrap lines during idle.
4961 WrapLines(WrapScope::wsIdle
);
4963 needWrap
= wrapPending
.NeedsWrap();
4964 } else if (needIdleStyling
) {
4968 // Add more idle things to do here, but make sure idleDone is
4969 // set correctly before the function returns. returning
4970 // false will stop calling this idle function until SetIdle() is
4973 const bool idleDone
= !needWrap
&& !needIdleStyling
; // && thatDone && theOtherThingDone...
4978 void Editor::SetTicking(bool) {
4979 // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
4980 // derived platform class but fine grained timers should now be implemented.
4981 // Either way, execution should not arrive here so assert failure.
4985 void Editor::TickFor(TickReason reason
) {
4988 caret
.on
= !caret
.on
;
4995 ButtonMove(ptMouseLast
);
4999 FineTickerCancel(tickWiden
);
5002 if ((!HaveMouseCapture()) &&
5003 (ptMouseLast
.y
>= 0)) {
5005 NotifyDwelling(ptMouseLast
, dwelling
);
5007 FineTickerCancel(tickDwell
);
5010 // tickPlatform handled by subclass
5015 bool Editor::FineTickerAvailable() {
5019 // FineTickerStart is be overridden by subclasses that support fine ticking so
5020 // this method should never be called.
5021 bool Editor::FineTickerRunning(TickReason
) {
5026 // FineTickerStart is be overridden by subclasses that support fine ticking so
5027 // this method should never be called.
5028 void Editor::FineTickerStart(TickReason
, int, int) {
5032 // FineTickerCancel is be overridden by subclasses that support fine ticking so
5033 // this method should never be called.
5034 void Editor::FineTickerCancel(TickReason
) {
5038 void Editor::SetFocusState(bool focusState
) {
5039 hasFocus
= focusState
;
5040 NotifyFocus(hasFocus
);
5044 ShowCaretAtCurrentPosition();
5047 Sci::Position
Editor::PositionAfterArea(PRectangle rcArea
) const {
5048 // The start of the document line after the display line after the area
5049 // This often means that the line after a modification is restyled which helps
5050 // detect multiline comment additions and heals single line comments
5051 Sci::Line lineAfter
= TopLineOfMain() + static_cast<Sci::Line
>(rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
5052 if (lineAfter
< cs
.LinesDisplayed())
5053 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
5055 return pdoc
->Length();
5058 // Style to a position within the view. If this causes a change at end of last line then
5059 // affects later lines so style all the viewed text.
5060 void Editor::StyleToPositionInView(Sci::Position pos
) {
5061 Sci::Position endWindow
= PositionAfterArea(GetClientDrawingRectangle());
5062 if (pos
> endWindow
)
5064 const int styleAtEnd
= pdoc
->StyleIndexAt(pos
-1);
5065 pdoc
->EnsureStyledTo(pos
);
5066 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleIndexAt(pos
-1))) {
5067 // Style at end of line changed so is multi-line change like starting a comment
5068 // so require rest of window to be styled.
5069 DiscardOverdraw(); // Prepared bitmaps may be invalid
5070 // DiscardOverdraw may have truncated client drawing area so recalculate endWindow
5071 endWindow
= PositionAfterArea(GetClientDrawingRectangle());
5072 pdoc
->EnsureStyledTo(endWindow
);
5076 Sci::Position
Editor::PositionAfterMaxStyling(Sci::Position posMax
, bool scrolling
) const {
5077 if ((idleStyling
== SC_IDLESTYLING_NONE
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5078 // Both states do not limit styling
5082 // Try to keep time taken by styling reasonable so interaction remains smooth.
5083 // When scrolling, allow less time to ensure responsive
5084 const double secondsAllowed
= scrolling
? 0.005 : 0.02;
5086 const Sci::Line linesToStyle
= Platform::Clamp(static_cast<int>(secondsAllowed
/ pdoc
->durationStyleOneLine
),
5088 const Sci::Line stylingMaxLine
= std::min(
5089 static_cast<Sci::Line
>(pdoc
->LineFromPosition(pdoc
->GetEndStyled()) + linesToStyle
),
5090 pdoc
->LinesTotal());
5091 return std::min(static_cast<Sci::Position
>(pdoc
->LineStart(stylingMaxLine
)), posMax
);
5094 void Editor::StartIdleStyling(bool truncatedLastStyling
) {
5095 if ((idleStyling
== SC_IDLESTYLING_ALL
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5096 if (pdoc
->GetEndStyled() < pdoc
->Length()) {
5097 // Style remainder of document in idle time
5098 needIdleStyling
= true;
5100 } else if (truncatedLastStyling
) {
5101 needIdleStyling
= true;
5104 if (needIdleStyling
) {
5109 // Style for an area but bound the amount of styling to remain responsive
5110 void Editor::StyleAreaBounded(PRectangle rcArea
, bool scrolling
) {
5111 const Sci::Position posAfterArea
= PositionAfterArea(rcArea
);
5112 const Sci::Position posAfterMax
= PositionAfterMaxStyling(posAfterArea
, scrolling
);
5113 if (posAfterMax
< posAfterArea
) {
5114 // Idle styling may be performed before current visible area
5115 // Style a bit now then style further in idle time
5116 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5118 // Can style all wanted now.
5119 StyleToPositionInView(posAfterArea
);
5121 StartIdleStyling(posAfterMax
< posAfterArea
);
5124 void Editor::IdleStyling() {
5125 const Sci::Position posAfterArea
= PositionAfterArea(GetClientRectangle());
5126 const Sci::Position endGoal
= (idleStyling
>= SC_IDLESTYLING_AFTERVISIBLE
) ?
5127 pdoc
->Length() : posAfterArea
;
5128 const Sci::Position posAfterMax
= PositionAfterMaxStyling(endGoal
, false);
5129 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5130 if (pdoc
->GetEndStyled() >= endGoal
) {
5131 needIdleStyling
= false;
5135 void Editor::IdleWork() {
5136 // Style the line after the modification as this allows modifications that change just the
5137 // line of the modification to heal instead of propagating to the rest of the window.
5138 if (workNeeded
.items
& WorkNeeded::workStyle
) {
5139 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(workNeeded
.upTo
) + 2));
5145 void Editor::QueueIdleWork(WorkNeeded::workItems items
, Sci::Position upTo
) {
5146 workNeeded
.Need(items
, upTo
);
5149 bool Editor::PaintContains(PRectangle rc
) {
5153 return rcPaint
.Contains(rc
);
5157 bool Editor::PaintContainsMargin() {
5158 if (wMargin
.GetID()) {
5159 // With separate margin view, paint of text view
5160 // never contains margin.
5163 PRectangle rcSelMargin
= GetClientRectangle();
5164 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
);
5165 return PaintContains(rcSelMargin
);
5168 void Editor::CheckForChangeOutsidePaint(Range r
) {
5169 if (paintState
== painting
&& !paintingAllText
) {
5170 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5174 PRectangle rcRange
= RectangleFromRange(r
, 0);
5175 PRectangle rcText
= GetTextRectangle();
5176 if (rcRange
.top
< rcText
.top
) {
5177 rcRange
.top
= rcText
.top
;
5179 if (rcRange
.bottom
> rcText
.bottom
) {
5180 rcRange
.bottom
= rcText
.bottom
;
5183 if (!PaintContains(rcRange
)) {
5185 paintAbandonedByStyling
= true;
5190 void Editor::SetBraceHighlight(Sci::Position pos0
, Sci::Position pos1
, int matchStyle
) {
5191 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5192 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5193 CheckForChangeOutsidePaint(Range(braces
[0]));
5194 CheckForChangeOutsidePaint(Range(pos0
));
5197 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5198 CheckForChangeOutsidePaint(Range(braces
[1]));
5199 CheckForChangeOutsidePaint(Range(pos1
));
5202 bracesMatchStyle
= matchStyle
;
5203 if (paintState
== notPainting
) {
5209 void Editor::SetAnnotationHeights(Sci::Line start
, Sci::Line end
) {
5210 if (vs
.annotationVisible
) {
5212 bool changedHeight
= false;
5213 for (Sci::Line line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
5214 int linesWrapped
= 1;
5216 AutoSurface
surface(this);
5217 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5218 if (surface
&& ll
) {
5219 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5220 linesWrapped
= ll
->lines
;
5223 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
5224 changedHeight
= true;
5226 if (changedHeight
) {
5232 void Editor::SetDocPointer(Document
*document
) {
5233 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5234 pdoc
->RemoveWatcher(this, 0);
5236 if (document
== NULL
) {
5237 pdoc
= new Document();
5243 // Ensure all positions within document
5248 braces
[0] = Sci::invalidPosition
;
5249 braces
[1] = Sci::invalidPosition
;
5251 vs
.ReleaseAllExtendedStyles();
5253 SetRepresentations();
5255 // Reset the contraction state to fully shown.
5257 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5258 SetAnnotationHeights(0, pdoc
->LinesTotal());
5259 view
.llc
.Deallocate();
5262 hotspot
= Range(Sci::invalidPosition
);
5263 hoverIndicatorPos
= Sci::invalidPosition
;
5265 view
.ClearAllTabstops();
5267 pdoc
->AddWatcher(this, 0);
5272 void Editor::SetAnnotationVisible(int visible
) {
5273 if (vs
.annotationVisible
!= visible
) {
5274 const bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
5275 vs
.annotationVisible
= visible
;
5276 if (changedFromOrToHidden
) {
5277 int dir
= vs
.annotationVisible
? 1 : -1;
5278 for (Sci::Line line
=0; line
<pdoc
->LinesTotal(); line
++) {
5279 int annotationLines
= pdoc
->AnnotationLines(line
);
5280 if (annotationLines
> 0) {
5281 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
5291 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5293 Sci::Line
Editor::ExpandLine(Sci::Line line
) {
5294 Sci::Line lineMaxSubord
= pdoc
->GetLastChild(line
);
5296 while (line
<= lineMaxSubord
) {
5297 cs
.SetVisible(line
, line
, true);
5298 const int level
= pdoc
->GetLevel(line
);
5299 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5300 if (cs
.GetExpanded(line
)) {
5301 line
= ExpandLine(line
);
5303 line
= pdoc
->GetLastChild(line
);
5308 return lineMaxSubord
;
5311 void Editor::SetFoldExpanded(Sci::Line lineDoc
, bool expanded
) {
5312 if (cs
.SetExpanded(lineDoc
, expanded
)) {
5317 void Editor::FoldLine(Sci::Line line
, int action
) {
5319 if (action
== SC_FOLDACTION_TOGGLE
) {
5320 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5321 line
= pdoc
->GetFoldParent(line
);
5325 action
= (cs
.GetExpanded(line
)) ? SC_FOLDACTION_CONTRACT
: SC_FOLDACTION_EXPAND
;
5328 if (action
== SC_FOLDACTION_CONTRACT
) {
5329 const Sci::Line lineMaxSubord
= pdoc
->GetLastChild(line
);
5330 if (lineMaxSubord
> line
) {
5331 cs
.SetExpanded(line
, false);
5332 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5334 const Sci::Line lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
5335 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5336 // This does not re-expand the fold
5337 EnsureCaretVisible();
5342 if (!(cs
.GetVisible(line
))) {
5343 EnsureLineVisible(line
, false);
5346 cs
.SetExpanded(line
, true);
5355 void Editor::FoldExpand(Sci::Line line
, int action
, int level
) {
5356 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5357 if (action
== SC_FOLDACTION_TOGGLE
) {
5358 expanding
= !cs
.GetExpanded(line
);
5360 // Ensure child lines lexed and fold information extracted before
5361 // flipping the state.
5362 pdoc
->GetLastChild(line
, LevelNumber(level
));
5363 SetFoldExpanded(line
, expanding
);
5364 if (expanding
&& (cs
.HiddenLines() == 0))
5367 Sci::Line lineMaxSubord
= pdoc
->GetLastChild(line
, LevelNumber(level
));
5369 cs
.SetVisible(line
, lineMaxSubord
, expanding
);
5370 while (line
<= lineMaxSubord
) {
5371 const int levelLine
= pdoc
->GetLevel(line
);
5372 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5373 SetFoldExpanded(line
, expanding
);
5381 Sci::Line
Editor::ContractedFoldNext(Sci::Line lineStart
) const {
5382 for (Sci::Line line
= lineStart
; line
<pdoc
->LinesTotal();) {
5383 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
5385 line
= cs
.ContractedNext(line
+1);
5394 * Recurse up from this line to find any folds that prevent this line from being visible
5395 * and unfold them all.
5397 void Editor::EnsureLineVisible(Sci::Line lineDoc
, bool enforcePolicy
) {
5399 // In case in need of wrapping to ensure DisplayFromDoc works.
5400 if (lineDoc
>= wrapPending
.start
)
5401 WrapLines(WrapScope::wsAll
);
5403 if (!cs
.GetVisible(lineDoc
)) {
5404 // Back up to find a non-blank line
5405 Sci::Line lookLine
= lineDoc
;
5406 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
5407 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
5408 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
5410 Sci::Line lineParent
= pdoc
->GetFoldParent(lookLine
);
5411 if (lineParent
< 0) {
5412 // Backed up to a top level line, so try to find parent of initial line
5413 lineParent
= pdoc
->GetFoldParent(lineDoc
);
5415 if (lineParent
>= 0) {
5416 if (lineDoc
!= lineParent
)
5417 EnsureLineVisible(lineParent
, enforcePolicy
);
5418 if (!cs
.GetExpanded(lineParent
)) {
5419 cs
.SetExpanded(lineParent
, true);
5420 ExpandLine(lineParent
);
5426 if (enforcePolicy
) {
5427 const Sci::Line lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5428 if (visiblePolicy
& VISIBLE_SLOP
) {
5429 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5430 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5431 SetVerticalScrollPos();
5433 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5434 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5435 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5436 SetVerticalScrollPos();
5440 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5441 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5442 SetVerticalScrollPos();
5449 void Editor::FoldAll(int action
) {
5450 pdoc
->EnsureStyledTo(pdoc
->Length());
5451 Sci::Line maxLine
= pdoc
->LinesTotal();
5452 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5453 if (action
== SC_FOLDACTION_TOGGLE
) {
5454 // Discover current state
5455 for (int lineSeek
= 0; lineSeek
< maxLine
; lineSeek
++) {
5456 if (pdoc
->GetLevel(lineSeek
) & SC_FOLDLEVELHEADERFLAG
) {
5457 expanding
= !cs
.GetExpanded(lineSeek
);
5463 cs
.SetVisible(0, maxLine
-1, true);
5464 for (int line
= 0; line
< maxLine
; line
++) {
5465 const int levelLine
= pdoc
->GetLevel(line
);
5466 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5467 SetFoldExpanded(line
, true);
5471 for (int line
= 0; line
< maxLine
; line
++) {
5472 const int level
= pdoc
->GetLevel(line
);
5473 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
5474 (SC_FOLDLEVELBASE
== LevelNumber(level
))) {
5475 SetFoldExpanded(line
, false);
5476 Sci::Line lineMaxSubord
= pdoc
->GetLastChild(line
, -1);
5477 if (lineMaxSubord
> line
) {
5478 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5487 void Editor::FoldChanged(Sci::Line line
, int levelNow
, int levelPrev
) {
5488 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
5489 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
5490 // Adding a fold point.
5491 if (cs
.SetExpanded(line
, true)) {
5494 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5496 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
5497 const Sci::Line prevLine
= line
- 1;
5498 const int prevLineLevel
= pdoc
->GetLevel(prevLine
);
5500 // Combining two blocks where the first block is collapsed (e.g. by deleting the line(s) which separate(s) the two blocks)
5501 if ((LevelNumber(prevLineLevel
) == LevelNumber(levelNow
)) && !cs
.GetVisible(prevLine
))
5502 FoldLine(pdoc
->GetFoldParent(prevLine
), SC_FOLDACTION_EXPAND
);
5504 if (!cs
.GetExpanded(line
)) {
5505 // Removing the fold from one that has been contracted so should expand
5506 // otherwise lines are left invisible with no way to make them visible
5507 if (cs
.SetExpanded(line
, true)) {
5510 // Combining two blocks where the second one is collapsed (e.g. by adding characters in the line which separates the two blocks)
5511 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5514 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) &&
5515 (LevelNumber(levelPrev
) > LevelNumber(levelNow
))) {
5516 if (cs
.HiddenLines()) {
5517 // See if should still be hidden
5518 Sci::Line parentLine
= pdoc
->GetFoldParent(line
);
5519 if ((parentLine
< 0) || (cs
.GetExpanded(parentLine
) && cs
.GetVisible(parentLine
))) {
5520 cs
.SetVisible(line
, line
, true);
5527 // Combining two blocks where the first one is collapsed (e.g. by adding characters in the line which separates the two blocks)
5528 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) && (LevelNumber(levelPrev
) < LevelNumber(levelNow
))) {
5529 if (cs
.HiddenLines()) {
5530 const Sci::Line parentLine
= pdoc
->GetFoldParent(line
);
5531 if (!cs
.GetExpanded(parentLine
) && cs
.GetVisible(line
))
5532 FoldLine(parentLine
, SC_FOLDACTION_EXPAND
);
5537 void Editor::NeedShown(Sci::Position pos
, Sci::Position len
) {
5538 if (foldAutomatic
& SC_AUTOMATICFOLD_SHOW
) {
5539 const Sci::Line lineStart
= pdoc
->LineFromPosition(pos
);
5540 const Sci::Line lineEnd
= pdoc
->LineFromPosition(pos
+len
);
5541 for (Sci::Line line
= lineStart
; line
<= lineEnd
; line
++) {
5542 EnsureLineVisible(line
, false);
5545 NotifyNeedShown(pos
, len
);
5549 Sci::Position
Editor::GetTag(char *tagValue
, int tagNumber
) {
5550 const char *text
= 0;
5551 Sci::Position length
= 0;
5552 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
5553 char name
[3] = "\\?";
5554 name
[1] = static_cast<char>(tagNumber
+ '0');
5556 text
= pdoc
->SubstituteByPosition(name
, &length
);
5560 memcpy(tagValue
, text
, length
+ 1);
5567 Sci::Position
Editor::ReplaceTarget(bool replacePatterns
, const char *text
, Sci::Position length
) {
5570 length
= istrlen(text
);
5571 if (replacePatterns
) {
5572 text
= pdoc
->SubstituteByPosition(text
, &length
);
5577 if (targetStart
!= targetEnd
)
5578 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5579 targetEnd
= targetStart
;
5580 const Sci::Position lengthInserted
= pdoc
->InsertString(targetStart
, text
, length
);
5581 targetEnd
= targetStart
+ lengthInserted
;
5585 bool Editor::IsUnicodeMode() const {
5586 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5589 int Editor::CodePage() const {
5591 return pdoc
->dbcsCodePage
;
5596 int Editor::WrapCount(int line
) {
5597 AutoSurface
surface(this);
5598 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5600 if (surface
&& ll
) {
5601 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5608 void Editor::AddStyledText(char *buffer
, Sci::Position appendLength
) {
5609 // The buffer consists of alternating character bytes and style bytes
5610 Sci::Position textLength
= appendLength
/ 2;
5611 std::string
text(textLength
, '\0');
5613 for (i
= 0; i
< textLength
; i
++) {
5614 text
[i
] = buffer
[i
*2];
5616 const Sci::Position lengthInserted
= pdoc
->InsertString(CurrentPosition(), text
.c_str(), textLength
);
5617 for (i
= 0; i
< textLength
; i
++) {
5618 text
[i
] = buffer
[i
*2+1];
5620 pdoc
->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
5621 pdoc
->SetStyles(textLength
, text
.c_str());
5622 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5625 bool Editor::ValidMargin(uptr_t wParam
) const {
5626 return wParam
< vs
.ms
.size();
5629 static char *CharPtrFromSPtr(sptr_t lParam
) {
5630 return reinterpret_cast<char *>(lParam
);
5633 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5634 vs
.EnsureStyle(wParam
);
5636 case SCI_STYLESETFORE
:
5637 vs
.styles
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
5639 case SCI_STYLESETBACK
:
5640 vs
.styles
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
5642 case SCI_STYLESETBOLD
:
5643 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
5645 case SCI_STYLESETWEIGHT
:
5646 vs
.styles
[wParam
].weight
= static_cast<int>(lParam
);
5648 case SCI_STYLESETITALIC
:
5649 vs
.styles
[wParam
].italic
= lParam
!= 0;
5651 case SCI_STYLESETEOLFILLED
:
5652 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5654 case SCI_STYLESETSIZE
:
5655 vs
.styles
[wParam
].size
= static_cast<int>(lParam
* SC_FONT_SIZE_MULTIPLIER
);
5657 case SCI_STYLESETSIZEFRACTIONAL
:
5658 vs
.styles
[wParam
].size
= static_cast<int>(lParam
);
5660 case SCI_STYLESETFONT
:
5662 vs
.SetStyleFontName(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5665 case SCI_STYLESETUNDERLINE
:
5666 vs
.styles
[wParam
].underline
= lParam
!= 0;
5668 case SCI_STYLESETCASE
:
5669 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5671 case SCI_STYLESETCHARACTERSET
:
5672 vs
.styles
[wParam
].characterSet
= static_cast<int>(lParam
);
5673 pdoc
->SetCaseFolder(nullptr);
5675 case SCI_STYLESETVISIBLE
:
5676 vs
.styles
[wParam
].visible
= lParam
!= 0;
5678 case SCI_STYLESETCHANGEABLE
:
5679 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5681 case SCI_STYLESETHOTSPOT
:
5682 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5685 InvalidateStyleRedraw();
5688 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5689 vs
.EnsureStyle(wParam
);
5691 case SCI_STYLEGETFORE
:
5692 return vs
.styles
[wParam
].fore
.AsLong();
5693 case SCI_STYLEGETBACK
:
5694 return vs
.styles
[wParam
].back
.AsLong();
5695 case SCI_STYLEGETBOLD
:
5696 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
5697 case SCI_STYLEGETWEIGHT
:
5698 return vs
.styles
[wParam
].weight
;
5699 case SCI_STYLEGETITALIC
:
5700 return vs
.styles
[wParam
].italic
? 1 : 0;
5701 case SCI_STYLEGETEOLFILLED
:
5702 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5703 case SCI_STYLEGETSIZE
:
5704 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
5705 case SCI_STYLEGETSIZEFRACTIONAL
:
5706 return vs
.styles
[wParam
].size
;
5707 case SCI_STYLEGETFONT
:
5708 return StringResult(lParam
, vs
.styles
[wParam
].fontName
);
5709 case SCI_STYLEGETUNDERLINE
:
5710 return vs
.styles
[wParam
].underline
? 1 : 0;
5711 case SCI_STYLEGETCASE
:
5712 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5713 case SCI_STYLEGETCHARACTERSET
:
5714 return vs
.styles
[wParam
].characterSet
;
5715 case SCI_STYLEGETVISIBLE
:
5716 return vs
.styles
[wParam
].visible
? 1 : 0;
5717 case SCI_STYLEGETCHANGEABLE
:
5718 return vs
.styles
[wParam
].changeable
? 1 : 0;
5719 case SCI_STYLEGETHOTSPOT
:
5720 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5725 void Editor::SetSelectionNMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5726 InvalidateRange(sel
.Range(wParam
).Start().Position(), sel
.Range(wParam
).End().Position());
5729 case SCI_SETSELECTIONNCARET
:
5730 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
5733 case SCI_SETSELECTIONNANCHOR
:
5734 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
5737 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
5738 sel
.Range(wParam
).caret
.SetVirtualSpace(static_cast<int>(lParam
));
5741 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
5742 sel
.Range(wParam
).anchor
.SetVirtualSpace(static_cast<int>(lParam
));
5745 case SCI_SETSELECTIONNSTART
:
5746 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
5749 case SCI_SETSELECTIONNEND
:
5750 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
5754 InvalidateRange(sel
.Range(wParam
).Start().Position(), sel
.Range(wParam
).End().Position());
5755 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
5758 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
5759 const size_t len
= val
? strlen(val
) : 0;
5761 char *ptr
= CharPtrFromSPtr(lParam
);
5763 memcpy(ptr
, val
, len
+1);
5767 return len
; // Not including NUL
5770 sptr_t
Editor::BytesResult(sptr_t lParam
, const unsigned char *val
, size_t len
) {
5771 // No NUL termination: len is number of valid/displayed bytes
5772 if ((lParam
) && (len
> 0)) {
5773 char *ptr
= CharPtrFromSPtr(lParam
);
5775 memcpy(ptr
, val
, len
);
5779 return val
? len
: 0;
5782 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5783 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5785 // Optional macro recording hook
5787 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5793 return pdoc
->Length() + 1;
5796 char *ptr
= CharPtrFromSPtr(lParam
);
5797 unsigned int iChar
= 0;
5798 for (; iChar
< wParam
- 1; iChar
++)
5799 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5808 pdoc
->DeleteChars(0, pdoc
->Length());
5809 SetEmptySelection(0);
5810 const char *text
= CharPtrFromSPtr(lParam
);
5811 pdoc
->InsertString(0, text
, istrlen(text
));
5815 case SCI_GETTEXTLENGTH
:
5816 return pdoc
->Length();
5827 case SCI_COPYALLOWLINE
:
5831 case SCI_VERTICALCENTRECARET
:
5832 VerticalCentreCaret();
5835 case SCI_MOVESELECTEDLINESUP
:
5836 MoveSelectedLinesUp();
5839 case SCI_MOVESELECTEDLINESDOWN
:
5840 MoveSelectedLinesDown();
5844 CopyRangeToClipboard(static_cast<int>(wParam
), static_cast<int>(lParam
));
5848 CopyText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5853 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5856 EnsureCaretVisible();
5862 EnsureCaretVisible();
5871 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5873 case SCI_EMPTYUNDOBUFFER
:
5874 pdoc
->DeleteUndoHistory();
5877 case SCI_GETFIRSTVISIBLELINE
:
5880 case SCI_SETFIRSTVISIBLELINE
:
5881 ScrollTo(static_cast<int>(wParam
));
5884 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5885 Sci::Position lineStart
= pdoc
->LineStart(static_cast<Sci::Line
>(wParam
));
5886 Sci::Position lineEnd
= pdoc
->LineStart(static_cast<Sci::Line
>(wParam
+ 1));
5888 return lineEnd
- lineStart
;
5890 char *ptr
= CharPtrFromSPtr(lParam
);
5891 Sci::Position iPlace
= 0;
5892 for (Sci::Position iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5893 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5898 case SCI_GETLINECOUNT
:
5899 if (pdoc
->LinesTotal() == 0)
5902 return pdoc
->LinesTotal();
5905 return !pdoc
->IsSavePoint();
5908 Sci::Position nStart
= static_cast<Sci::Position
>(wParam
);
5909 Sci::Position nEnd
= static_cast<Sci::Position
>(lParam
);
5911 nEnd
= pdoc
->Length();
5913 nStart
= nEnd
; // Remove selection
5914 InvalidateSelection(SelectionRange(nStart
, nEnd
));
5916 sel
.selType
= Selection::selStream
;
5917 SetSelection(nEnd
, nStart
);
5918 EnsureCaretVisible();
5922 case SCI_GETSELTEXT
: {
5923 SelectionText selectedText
;
5924 CopySelectionRange(&selectedText
);
5926 return selectedText
.LengthWithTerminator();
5928 char *ptr
= CharPtrFromSPtr(lParam
);
5929 unsigned int iChar
= 0;
5930 if (selectedText
.Length()) {
5931 for (; iChar
< selectedText
.LengthWithTerminator(); iChar
++)
5932 ptr
[iChar
] = selectedText
.Data()[iChar
];
5940 case SCI_LINEFROMPOSITION
:
5941 if (static_cast<int>(wParam
) < 0)
5943 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
5945 case SCI_POSITIONFROMLINE
:
5946 if (static_cast<int>(wParam
) < 0)
5947 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
5949 return 0; // Even if there is no text, there is a first line that starts at 0
5950 if (static_cast<Sci::Line
>(wParam
) > pdoc
->LinesTotal())
5952 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5954 return pdoc
->LineStart(static_cast<int>(wParam
));
5956 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5957 case SCI_LINELENGTH
:
5958 if ((static_cast<int>(wParam
) < 0) ||
5959 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5961 return pdoc
->LineStart(static_cast<int>(wParam
) + 1) - pdoc
->LineStart(static_cast<int>(wParam
));
5963 case SCI_REPLACESEL
: {
5968 char *replacement
= CharPtrFromSPtr(lParam
);
5969 const Sci::Position lengthInserted
= pdoc
->InsertString(
5970 sel
.MainCaret(), replacement
, istrlen(replacement
));
5971 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5972 EnsureCaretVisible();
5976 case SCI_SETTARGETSTART
:
5977 targetStart
= static_cast<int>(wParam
);
5980 case SCI_GETTARGETSTART
:
5983 case SCI_SETTARGETEND
:
5984 targetEnd
= static_cast<int>(wParam
);
5987 case SCI_GETTARGETEND
:
5990 case SCI_SETTARGETRANGE
:
5991 targetStart
= static_cast<int>(wParam
);
5992 targetEnd
= static_cast<int>(lParam
);
5995 case SCI_TARGETWHOLEDOCUMENT
:
5997 targetEnd
= pdoc
->Length();
6000 case SCI_TARGETFROMSELECTION
:
6001 if (sel
.MainCaret() < sel
.MainAnchor()) {
6002 targetStart
= sel
.MainCaret();
6003 targetEnd
= sel
.MainAnchor();
6005 targetStart
= sel
.MainAnchor();
6006 targetEnd
= sel
.MainCaret();
6010 case SCI_GETTARGETTEXT
: {
6011 std::string text
= RangeText(targetStart
, targetEnd
);
6012 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(text
.c_str()), text
.length());
6015 case SCI_REPLACETARGET
:
6016 PLATFORM_ASSERT(lParam
);
6017 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), static_cast<Sci::Position
>(wParam
));
6019 case SCI_REPLACETARGETRE
:
6020 PLATFORM_ASSERT(lParam
);
6021 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), static_cast<Sci::Position
>(wParam
));
6023 case SCI_SEARCHINTARGET
:
6024 PLATFORM_ASSERT(lParam
);
6025 return SearchInTarget(CharPtrFromSPtr(lParam
), static_cast<Sci::Position
>(wParam
));
6027 case SCI_SETSEARCHFLAGS
:
6028 searchFlags
= static_cast<int>(wParam
);
6031 case SCI_GETSEARCHFLAGS
:
6035 return GetTag(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6037 case SCI_POSITIONBEFORE
:
6038 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) - 1, -1, true);
6040 case SCI_POSITIONAFTER
:
6041 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) + 1, 1, true);
6043 case SCI_POSITIONRELATIVE
:
6044 return Platform::Clamp(pdoc
->GetRelativePosition(static_cast<int>(wParam
), static_cast<int>(lParam
)), 0, pdoc
->Length());
6046 case SCI_LINESCROLL
:
6047 ScrollTo(topLine
+ static_cast<Sci::Line
>(lParam
));
6048 HorizontalScrollTo(xOffset
+ static_cast<int>(wParam
) * static_cast<int>(vs
.spaceWidth
));
6051 case SCI_SETXOFFSET
:
6052 xOffset
= static_cast<int>(wParam
);
6053 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6054 SetHorizontalScrollPos();
6058 case SCI_GETXOFFSET
:
6061 case SCI_CHOOSECARETX
:
6065 case SCI_SCROLLCARET
:
6066 EnsureCaretVisible();
6069 case SCI_SETREADONLY
:
6070 pdoc
->SetReadOnly(wParam
!= 0);
6073 case SCI_GETREADONLY
:
6074 return pdoc
->IsReadOnly();
6079 case SCI_POINTXFROMPOSITION
:
6083 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
6084 // Convert to view-relative
6085 return static_cast<int>(pt
.x
) - vs
.textStart
+ vs
.fixedColumnWidth
;
6088 case SCI_POINTYFROMPOSITION
:
6092 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
6093 return static_cast<int>(pt
.y
);
6097 return FindText(wParam
, lParam
);
6099 case SCI_GETTEXTRANGE
: {
6102 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6103 Sci::Position cpMax
= static_cast<Sci::Position
>(tr
->chrg
.cpMax
);
6105 cpMax
= pdoc
->Length();
6106 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
6107 int len
= static_cast<int>(cpMax
- tr
->chrg
.cpMin
); // No -1 as cpMin and cpMax are referring to inter character positions
6108 pdoc
->GetCharRange(tr
->lpstrText
, static_cast<int>(tr
->chrg
.cpMin
), len
);
6109 // Spec says copied text is terminated with a NUL
6110 tr
->lpstrText
[len
] = '\0';
6111 return len
; // Not including NUL
6114 case SCI_HIDESELECTION
:
6115 view
.hideSelection
= wParam
!= 0;
6119 case SCI_FORMATRANGE
:
6120 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
6122 case SCI_GETMARGINLEFT
:
6123 return vs
.leftMarginWidth
;
6125 case SCI_GETMARGINRIGHT
:
6126 return vs
.rightMarginWidth
;
6128 case SCI_SETMARGINLEFT
:
6129 lastXChosen
+= static_cast<int>(lParam
) - vs
.leftMarginWidth
;
6130 vs
.leftMarginWidth
= static_cast<int>(lParam
);
6131 InvalidateStyleRedraw();
6134 case SCI_SETMARGINRIGHT
:
6135 vs
.rightMarginWidth
= static_cast<int>(lParam
);
6136 InvalidateStyleRedraw();
6139 // Control specific mesages
6144 const Sci::Position lengthInserted
= pdoc
->InsertString(
6145 CurrentPosition(), CharPtrFromSPtr(lParam
), static_cast<Sci::Position
>(wParam
));
6146 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
6150 case SCI_ADDSTYLEDTEXT
:
6152 AddStyledText(CharPtrFromSPtr(lParam
), static_cast<Sci::Position
>(wParam
));
6155 case SCI_INSERTTEXT
: {
6158 Sci::Position insertPos
= static_cast<Sci::Position
>(wParam
);
6159 if (static_cast<int>(wParam
) == -1)
6160 insertPos
= CurrentPosition();
6161 Sci::Position newCurrent
= CurrentPosition();
6162 char *sz
= CharPtrFromSPtr(lParam
);
6163 const Sci::Position lengthInserted
= pdoc
->InsertString(insertPos
, sz
, istrlen(sz
));
6164 if (newCurrent
> insertPos
)
6165 newCurrent
+= lengthInserted
;
6166 SetEmptySelection(newCurrent
);
6170 case SCI_CHANGEINSERTION
:
6171 PLATFORM_ASSERT(lParam
);
6172 pdoc
->ChangeInsertion(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6175 case SCI_APPENDTEXT
:
6176 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6183 case SCI_DELETERANGE
:
6184 pdoc
->DeleteChars(static_cast<int>(wParam
), static_cast<int>(lParam
));
6187 case SCI_CLEARDOCUMENTSTYLE
:
6188 ClearDocumentStyle();
6191 case SCI_SETUNDOCOLLECTION
:
6192 pdoc
->SetUndoCollection(wParam
!= 0);
6195 case SCI_GETUNDOCOLLECTION
:
6196 return pdoc
->IsCollectingUndo();
6198 case SCI_BEGINUNDOACTION
:
6199 pdoc
->BeginUndoAction();
6202 case SCI_ENDUNDOACTION
:
6203 pdoc
->EndUndoAction();
6206 case SCI_GETCARETPERIOD
:
6207 return caret
.period
;
6209 case SCI_SETCARETPERIOD
:
6210 CaretSetPeriod(static_cast<int>(wParam
));
6213 case SCI_GETWORDCHARS
:
6214 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
6216 case SCI_SETWORDCHARS
: {
6217 pdoc
->SetDefaultCharClasses(false);
6220 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6224 case SCI_GETWHITESPACECHARS
:
6225 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
6227 case SCI_SETWHITESPACECHARS
: {
6230 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6234 case SCI_GETPUNCTUATIONCHARS
:
6235 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
6237 case SCI_SETPUNCTUATIONCHARS
: {
6240 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
6244 case SCI_SETCHARSDEFAULT
:
6245 pdoc
->SetDefaultCharClasses(true);
6249 return pdoc
->Length();
6252 pdoc
->Allocate(static_cast<Sci::Position
>(wParam
));
6256 return pdoc
->CharAt(static_cast<Sci::Position
>(wParam
));
6258 case SCI_SETCURRENTPOS
:
6259 if (sel
.IsRectangular()) {
6260 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
6261 SetRectangularRange();
6264 SetSelection(static_cast<Sci::Position
>(wParam
), sel
.MainAnchor());
6268 case SCI_GETCURRENTPOS
:
6269 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
6272 if (sel
.IsRectangular()) {
6273 sel
.Rectangular().anchor
.SetPosition(static_cast<Sci::Position
>(wParam
));
6274 SetRectangularRange();
6277 SetSelection(sel
.MainCaret(), static_cast<Sci::Position
>(wParam
));
6282 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
6284 case SCI_SETSELECTIONSTART
:
6285 SetSelection(std::max(sel
.MainCaret(), static_cast<Sci::Position
>(wParam
)), static_cast<Sci::Position
>(wParam
));
6288 case SCI_GETSELECTIONSTART
:
6289 return sel
.LimitsForRectangularElseMain().start
.Position();
6291 case SCI_SETSELECTIONEND
:
6292 SetSelection(static_cast<Sci::Position
>(wParam
), std::min(sel
.MainAnchor(), static_cast<Sci::Position
>(wParam
)));
6295 case SCI_GETSELECTIONEND
:
6296 return sel
.LimitsForRectangularElseMain().end
.Position();
6298 case SCI_SETEMPTYSELECTION
:
6299 SetEmptySelection(static_cast<int>(wParam
));
6302 case SCI_SETPRINTMAGNIFICATION
:
6303 view
.printParameters
.magnification
= static_cast<int>(wParam
);
6306 case SCI_GETPRINTMAGNIFICATION
:
6307 return view
.printParameters
.magnification
;
6309 case SCI_SETPRINTCOLOURMODE
:
6310 view
.printParameters
.colourMode
= static_cast<int>(wParam
);
6313 case SCI_GETPRINTCOLOURMODE
:
6314 return view
.printParameters
.colourMode
;
6316 case SCI_SETPRINTWRAPMODE
:
6317 view
.printParameters
.wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6320 case SCI_GETPRINTWRAPMODE
:
6321 return view
.printParameters
.wrapState
;
6323 case SCI_GETSTYLEAT
:
6324 if (static_cast<int>(wParam
) >= pdoc
->Length())
6327 return pdoc
->StyleAt(static_cast<int>(wParam
));
6337 case SCI_SETSAVEPOINT
:
6338 pdoc
->SetSavePoint();
6341 case SCI_GETSTYLEDTEXT
: {
6344 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6346 for (long iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6347 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(static_cast<int>(iChar
));
6348 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(static_cast<int>(iChar
));
6350 tr
->lpstrText
[iPlace
] = '\0';
6351 tr
->lpstrText
[iPlace
+ 1] = '\0';
6356 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6358 case SCI_MARKERLINEFROMHANDLE
:
6359 return pdoc
->LineFromHandle(static_cast<int>(wParam
));
6361 case SCI_MARKERDELETEHANDLE
:
6362 pdoc
->DeleteMarkFromHandle(static_cast<int>(wParam
));
6366 return vs
.viewWhitespace
;
6369 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6373 case SCI_GETTABDRAWMODE
:
6374 return vs
.tabDrawMode
;
6376 case SCI_SETTABDRAWMODE
:
6377 vs
.tabDrawMode
= static_cast<TabDrawMode
>(wParam
);
6381 case SCI_GETWHITESPACESIZE
:
6382 return vs
.whitespaceSize
;
6384 case SCI_SETWHITESPACESIZE
:
6385 vs
.whitespaceSize
= static_cast<int>(wParam
);
6389 case SCI_POSITIONFROMPOINT
:
6390 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6393 case SCI_POSITIONFROMPOINTCLOSE
:
6394 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6397 case SCI_CHARPOSITIONFROMPOINT
:
6398 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6401 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
6402 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6406 GoToLine(static_cast<int>(wParam
));
6410 SetEmptySelection(static_cast<int>(wParam
));
6411 EnsureCaretVisible();
6414 case SCI_GETCURLINE
: {
6415 const Sci::Line lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
6416 const Sci::Position lineStart
= pdoc
->LineStart(lineCurrentPos
);
6417 const Sci::Position lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6419 return 1 + lineEnd
- lineStart
;
6421 PLATFORM_ASSERT(wParam
> 0);
6422 char *ptr
= CharPtrFromSPtr(lParam
);
6423 unsigned int iPlace
= 0;
6424 for (Sci::Position iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6425 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6428 return sel
.MainCaret() - lineStart
;
6431 case SCI_GETENDSTYLED
:
6432 return pdoc
->GetEndStyled();
6434 case SCI_GETEOLMODE
:
6435 return pdoc
->eolMode
;
6437 case SCI_SETEOLMODE
:
6438 pdoc
->eolMode
= static_cast<int>(wParam
);
6441 case SCI_SETLINEENDTYPESALLOWED
:
6442 if (pdoc
->SetLineEndTypesAllowed(static_cast<int>(wParam
))) {
6444 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6445 SetAnnotationHeights(0, pdoc
->LinesTotal());
6446 InvalidateStyleRedraw();
6450 case SCI_GETLINEENDTYPESALLOWED
:
6451 return pdoc
->GetLineEndTypesAllowed();
6453 case SCI_GETLINEENDTYPESACTIVE
:
6454 return pdoc
->GetLineEndTypesActive();
6456 case SCI_STARTSTYLING
:
6457 pdoc
->StartStyling(static_cast<int>(wParam
), static_cast<char>(lParam
));
6460 case SCI_SETSTYLING
:
6461 if (static_cast<int>(wParam
) < 0)
6462 errorStatus
= SC_STATUS_FAILURE
;
6464 pdoc
->SetStyleFor(static_cast<int>(wParam
), static_cast<char>(lParam
));
6467 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6470 pdoc
->SetStyles(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6473 case SCI_SETBUFFEREDDRAW
:
6474 view
.bufferedDraw
= wParam
!= 0;
6477 case SCI_GETBUFFEREDDRAW
:
6478 return view
.bufferedDraw
;
6480 case SCI_GETTWOPHASEDRAW
:
6481 return view
.phasesDraw
== EditView::phasesTwo
;
6483 case SCI_SETTWOPHASEDRAW
:
6484 if (view
.SetTwoPhaseDraw(wParam
!= 0))
6485 InvalidateStyleRedraw();
6488 case SCI_GETPHASESDRAW
:
6489 return view
.phasesDraw
;
6491 case SCI_SETPHASESDRAW
:
6492 if (view
.SetPhasesDraw(static_cast<int>(wParam
)))
6493 InvalidateStyleRedraw();
6496 case SCI_SETFONTQUALITY
:
6497 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
6498 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
6499 InvalidateStyleRedraw();
6502 case SCI_GETFONTQUALITY
:
6503 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
6505 case SCI_SETTABWIDTH
:
6507 pdoc
->tabInChars
= static_cast<int>(wParam
);
6508 if (pdoc
->indentInChars
== 0)
6509 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6511 InvalidateStyleRedraw();
6514 case SCI_GETTABWIDTH
:
6515 return pdoc
->tabInChars
;
6517 case SCI_CLEARTABSTOPS
:
6518 if (view
.ClearTabstops(static_cast<int>(wParam
))) {
6519 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6520 NotifyModified(pdoc
, mh
, NULL
);
6524 case SCI_ADDTABSTOP
:
6525 if (view
.AddTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
))) {
6526 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6527 NotifyModified(pdoc
, mh
, NULL
);
6531 case SCI_GETNEXTTABSTOP
:
6532 return view
.GetNextTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
));
6535 pdoc
->indentInChars
= static_cast<int>(wParam
);
6536 if (pdoc
->indentInChars
!= 0)
6537 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6539 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6540 InvalidateStyleRedraw();
6544 return pdoc
->indentInChars
;
6546 case SCI_SETUSETABS
:
6547 pdoc
->useTabs
= wParam
!= 0;
6548 InvalidateStyleRedraw();
6551 case SCI_GETUSETABS
:
6552 return pdoc
->useTabs
;
6554 case SCI_SETLINEINDENTATION
:
6555 pdoc
->SetLineIndentation(static_cast<int>(wParam
), static_cast<int>(lParam
));
6558 case SCI_GETLINEINDENTATION
:
6559 return pdoc
->GetLineIndentation(static_cast<int>(wParam
));
6561 case SCI_GETLINEINDENTPOSITION
:
6562 return pdoc
->GetLineIndentPosition(static_cast<int>(wParam
));
6564 case SCI_SETTABINDENTS
:
6565 pdoc
->tabIndents
= wParam
!= 0;
6568 case SCI_GETTABINDENTS
:
6569 return pdoc
->tabIndents
;
6571 case SCI_SETBACKSPACEUNINDENTS
:
6572 pdoc
->backspaceUnindents
= wParam
!= 0;
6575 case SCI_GETBACKSPACEUNINDENTS
:
6576 return pdoc
->backspaceUnindents
;
6578 case SCI_SETMOUSEDWELLTIME
:
6579 dwellDelay
= static_cast<int>(wParam
);
6580 ticksToDwell
= dwellDelay
;
6583 case SCI_GETMOUSEDWELLTIME
:
6586 case SCI_WORDSTARTPOSITION
:
6587 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), -1, lParam
!= 0);
6589 case SCI_WORDENDPOSITION
:
6590 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), 1, lParam
!= 0);
6592 case SCI_ISRANGEWORD
:
6593 return pdoc
->IsWordAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
6595 case SCI_SETIDLESTYLING
:
6596 idleStyling
= static_cast<int>(wParam
);
6599 case SCI_GETIDLESTYLING
:
6602 case SCI_SETWRAPMODE
:
6603 if (vs
.SetWrapState(static_cast<int>(wParam
))) {
6605 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6606 InvalidateStyleRedraw();
6607 ReconfigureScrollBars();
6611 case SCI_GETWRAPMODE
:
6612 return vs
.wrapState
;
6614 case SCI_SETWRAPVISUALFLAGS
:
6615 if (vs
.SetWrapVisualFlags(static_cast<int>(wParam
))) {
6616 InvalidateStyleRedraw();
6617 ReconfigureScrollBars();
6621 case SCI_GETWRAPVISUALFLAGS
:
6622 return vs
.wrapVisualFlags
;
6624 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6625 if (vs
.SetWrapVisualFlagsLocation(static_cast<int>(wParam
))) {
6626 InvalidateStyleRedraw();
6630 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6631 return vs
.wrapVisualFlagsLocation
;
6633 case SCI_SETWRAPSTARTINDENT
:
6634 if (vs
.SetWrapVisualStartIndent(static_cast<int>(wParam
))) {
6635 InvalidateStyleRedraw();
6636 ReconfigureScrollBars();
6640 case SCI_GETWRAPSTARTINDENT
:
6641 return vs
.wrapVisualStartIndent
;
6643 case SCI_SETWRAPINDENTMODE
:
6644 if (vs
.SetWrapIndentMode(static_cast<int>(wParam
))) {
6645 InvalidateStyleRedraw();
6646 ReconfigureScrollBars();
6650 case SCI_GETWRAPINDENTMODE
:
6651 return vs
.wrapIndentMode
;
6653 case SCI_SETLAYOUTCACHE
:
6654 view
.llc
.SetLevel(static_cast<int>(wParam
));
6657 case SCI_GETLAYOUTCACHE
:
6658 return view
.llc
.GetLevel();
6660 case SCI_SETPOSITIONCACHE
:
6661 view
.posCache
.SetSize(wParam
);
6664 case SCI_GETPOSITIONCACHE
:
6665 return view
.posCache
.GetSize();
6667 case SCI_SETSCROLLWIDTH
:
6668 PLATFORM_ASSERT(wParam
> 0);
6669 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6670 view
.lineWidthMaxSeen
= 0;
6671 scrollWidth
= static_cast<int>(wParam
);
6676 case SCI_GETSCROLLWIDTH
:
6679 case SCI_SETSCROLLWIDTHTRACKING
:
6680 trackLineWidth
= wParam
!= 0;
6683 case SCI_GETSCROLLWIDTHTRACKING
:
6684 return trackLineWidth
;
6690 case SCI_LINESSPLIT
:
6691 LinesSplit(static_cast<int>(wParam
));
6695 PLATFORM_ASSERT(wParam
< vs
.styles
.size());
6696 PLATFORM_ASSERT(lParam
);
6697 return TextWidth(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6699 case SCI_TEXTHEIGHT
:
6701 return vs
.lineHeight
;
6703 case SCI_SETENDATLASTLINE
:
6704 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6705 if (endAtLastLine
!= (wParam
!= 0)) {
6706 endAtLastLine
= wParam
!= 0;
6711 case SCI_GETENDATLASTLINE
:
6712 return endAtLastLine
;
6714 case SCI_SETCARETSTICKY
:
6715 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
6716 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
6717 caretSticky
= static_cast<int>(wParam
);
6721 case SCI_GETCARETSTICKY
:
6724 case SCI_TOGGLECARETSTICKY
:
6725 caretSticky
= !caretSticky
;
6729 return pdoc
->GetColumn(static_cast<int>(wParam
));
6731 case SCI_FINDCOLUMN
:
6732 return pdoc
->FindColumn(static_cast<int>(wParam
), static_cast<int>(lParam
));
6734 case SCI_SETHSCROLLBAR
:
6735 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6736 horizontalScrollBarVisible
= wParam
!= 0;
6738 ReconfigureScrollBars();
6742 case SCI_GETHSCROLLBAR
:
6743 return horizontalScrollBarVisible
;
6745 case SCI_SETVSCROLLBAR
:
6746 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6747 verticalScrollBarVisible
= wParam
!= 0;
6749 ReconfigureScrollBars();
6750 if (verticalScrollBarVisible
)
6751 SetVerticalScrollPos();
6755 case SCI_GETVSCROLLBAR
:
6756 return verticalScrollBarVisible
;
6758 case SCI_SETINDENTATIONGUIDES
:
6759 vs
.viewIndentationGuides
= IndentView(wParam
);
6763 case SCI_GETINDENTATIONGUIDES
:
6764 return vs
.viewIndentationGuides
;
6766 case SCI_SETHIGHLIGHTGUIDE
:
6767 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6768 highlightGuideColumn
= static_cast<int>(wParam
);
6773 case SCI_GETHIGHLIGHTGUIDE
:
6774 return highlightGuideColumn
;
6776 case SCI_GETLINEENDPOSITION
:
6777 return pdoc
->LineEnd(static_cast<int>(wParam
));
6779 case SCI_SETCODEPAGE
:
6780 if (ValidCodePage(static_cast<int>(wParam
))) {
6781 if (pdoc
->SetDBCSCodePage(static_cast<int>(wParam
))) {
6783 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6784 SetAnnotationHeights(0, pdoc
->LinesTotal());
6785 InvalidateStyleRedraw();
6786 SetRepresentations();
6791 case SCI_GETCODEPAGE
:
6792 return pdoc
->dbcsCodePage
;
6794 case SCI_SETIMEINTERACTION
:
6795 imeInteraction
= static_cast<EditModel::IMEInteraction
>(wParam
);
6798 case SCI_GETIMEINTERACTION
:
6799 return imeInteraction
;
6801 // Marker definition and setting
6802 case SCI_MARKERDEFINE
:
6803 if (wParam
<= MARKER_MAX
) {
6804 vs
.markers
[wParam
].markType
= static_cast<int>(lParam
);
6805 vs
.CalcLargestMarkerHeight();
6807 InvalidateStyleData();
6811 case SCI_MARKERSYMBOLDEFINED
:
6812 if (wParam
<= MARKER_MAX
)
6813 return vs
.markers
[wParam
].markType
;
6817 case SCI_MARKERSETFORE
:
6818 if (wParam
<= MARKER_MAX
)
6819 vs
.markers
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6820 InvalidateStyleData();
6823 case SCI_MARKERSETBACKSELECTED
:
6824 if (wParam
<= MARKER_MAX
)
6825 vs
.markers
[wParam
].backSelected
= ColourDesired(static_cast<long>(lParam
));
6826 InvalidateStyleData();
6829 case SCI_MARKERENABLEHIGHLIGHT
:
6830 marginView
.highlightDelimiter
.isEnabled
= wParam
== 1;
6833 case SCI_MARKERSETBACK
:
6834 if (wParam
<= MARKER_MAX
)
6835 vs
.markers
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6836 InvalidateStyleData();
6839 case SCI_MARKERSETALPHA
:
6840 if (wParam
<= MARKER_MAX
)
6841 vs
.markers
[wParam
].alpha
= static_cast<int>(lParam
);
6842 InvalidateStyleRedraw();
6844 case SCI_MARKERADD
: {
6845 int markerID
= pdoc
->AddMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6848 case SCI_MARKERADDSET
:
6850 pdoc
->AddMarkSet(static_cast<int>(wParam
), static_cast<int>(lParam
));
6853 case SCI_MARKERDELETE
:
6854 pdoc
->DeleteMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6857 case SCI_MARKERDELETEALL
:
6858 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6862 return pdoc
->GetMark(static_cast<int>(wParam
));
6864 case SCI_MARKERNEXT
:
6865 return pdoc
->MarkerNext(static_cast<int>(wParam
), static_cast<int>(lParam
));
6867 case SCI_MARKERPREVIOUS
: {
6868 for (int iLine
= static_cast<int>(wParam
); iLine
>= 0; iLine
--) {
6869 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6875 case SCI_MARKERDEFINEPIXMAP
:
6876 if (wParam
<= MARKER_MAX
) {
6877 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6878 vs
.CalcLargestMarkerHeight();
6880 InvalidateStyleData();
6884 case SCI_RGBAIMAGESETWIDTH
:
6885 sizeRGBAImage
.x
= static_cast<XYPOSITION
>(wParam
);
6888 case SCI_RGBAIMAGESETHEIGHT
:
6889 sizeRGBAImage
.y
= static_cast<XYPOSITION
>(wParam
);
6892 case SCI_RGBAIMAGESETSCALE
:
6893 scaleRGBAImage
= static_cast<float>(wParam
);
6896 case SCI_MARKERDEFINERGBAIMAGE
:
6897 if (wParam
<= MARKER_MAX
) {
6898 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0f
, reinterpret_cast<unsigned char *>(lParam
));
6899 vs
.CalcLargestMarkerHeight();
6901 InvalidateStyleData();
6905 case SCI_SETMARGINTYPEN
:
6906 if (ValidMargin(wParam
)) {
6907 vs
.ms
[wParam
].style
= static_cast<int>(lParam
);
6908 InvalidateStyleRedraw();
6912 case SCI_GETMARGINTYPEN
:
6913 if (ValidMargin(wParam
))
6914 return vs
.ms
[wParam
].style
;
6918 case SCI_SETMARGINWIDTHN
:
6919 if (ValidMargin(wParam
)) {
6920 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6921 if (vs
.ms
[wParam
].width
!= lParam
) {
6922 lastXChosen
+= static_cast<int>(lParam
) - vs
.ms
[wParam
].width
;
6923 vs
.ms
[wParam
].width
= static_cast<int>(lParam
);
6924 InvalidateStyleRedraw();
6929 case SCI_GETMARGINWIDTHN
:
6930 if (ValidMargin(wParam
))
6931 return vs
.ms
[wParam
].width
;
6935 case SCI_SETMARGINMASKN
:
6936 if (ValidMargin(wParam
)) {
6937 vs
.ms
[wParam
].mask
= static_cast<int>(lParam
);
6938 InvalidateStyleRedraw();
6942 case SCI_GETMARGINMASKN
:
6943 if (ValidMargin(wParam
))
6944 return vs
.ms
[wParam
].mask
;
6948 case SCI_SETMARGINSENSITIVEN
:
6949 if (ValidMargin(wParam
)) {
6950 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6951 InvalidateStyleRedraw();
6955 case SCI_GETMARGINSENSITIVEN
:
6956 if (ValidMargin(wParam
))
6957 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6961 case SCI_SETMARGINCURSORN
:
6962 if (ValidMargin(wParam
))
6963 vs
.ms
[wParam
].cursor
= static_cast<int>(lParam
);
6966 case SCI_GETMARGINCURSORN
:
6967 if (ValidMargin(wParam
))
6968 return vs
.ms
[wParam
].cursor
;
6972 case SCI_SETMARGINBACKN
:
6973 if (ValidMargin(wParam
)) {
6974 vs
.ms
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6975 InvalidateStyleRedraw();
6979 case SCI_GETMARGINBACKN
:
6980 if (ValidMargin(wParam
))
6981 return vs
.ms
[wParam
].back
.AsLong();
6985 case SCI_SETMARGINS
:
6987 vs
.ms
.resize(wParam
);
6990 case SCI_GETMARGINS
:
6991 return vs
.ms
.size();
6993 case SCI_STYLECLEARALL
:
6995 InvalidateStyleRedraw();
6998 case SCI_STYLESETFORE
:
6999 case SCI_STYLESETBACK
:
7000 case SCI_STYLESETBOLD
:
7001 case SCI_STYLESETWEIGHT
:
7002 case SCI_STYLESETITALIC
:
7003 case SCI_STYLESETEOLFILLED
:
7004 case SCI_STYLESETSIZE
:
7005 case SCI_STYLESETSIZEFRACTIONAL
:
7006 case SCI_STYLESETFONT
:
7007 case SCI_STYLESETUNDERLINE
:
7008 case SCI_STYLESETCASE
:
7009 case SCI_STYLESETCHARACTERSET
:
7010 case SCI_STYLESETVISIBLE
:
7011 case SCI_STYLESETCHANGEABLE
:
7012 case SCI_STYLESETHOTSPOT
:
7013 StyleSetMessage(iMessage
, wParam
, lParam
);
7016 case SCI_STYLEGETFORE
:
7017 case SCI_STYLEGETBACK
:
7018 case SCI_STYLEGETBOLD
:
7019 case SCI_STYLEGETWEIGHT
:
7020 case SCI_STYLEGETITALIC
:
7021 case SCI_STYLEGETEOLFILLED
:
7022 case SCI_STYLEGETSIZE
:
7023 case SCI_STYLEGETSIZEFRACTIONAL
:
7024 case SCI_STYLEGETFONT
:
7025 case SCI_STYLEGETUNDERLINE
:
7026 case SCI_STYLEGETCASE
:
7027 case SCI_STYLEGETCHARACTERSET
:
7028 case SCI_STYLEGETVISIBLE
:
7029 case SCI_STYLEGETCHANGEABLE
:
7030 case SCI_STYLEGETHOTSPOT
:
7031 return StyleGetMessage(iMessage
, wParam
, lParam
);
7033 case SCI_STYLERESETDEFAULT
:
7034 vs
.ResetDefaultStyle();
7035 InvalidateStyleRedraw();
7037 case SCI_SETSTYLEBITS
:
7038 vs
.EnsureStyle(0xff);
7041 case SCI_GETSTYLEBITS
:
7044 case SCI_SETLINESTATE
:
7045 return pdoc
->SetLineState(static_cast<int>(wParam
), static_cast<int>(lParam
));
7047 case SCI_GETLINESTATE
:
7048 return pdoc
->GetLineState(static_cast<int>(wParam
));
7050 case SCI_GETMAXLINESTATE
:
7051 return pdoc
->GetMaxLineState();
7053 case SCI_GETCARETLINEVISIBLE
:
7054 return vs
.showCaretLineBackground
;
7055 case SCI_SETCARETLINEVISIBLE
:
7056 vs
.showCaretLineBackground
= wParam
!= 0;
7057 InvalidateStyleRedraw();
7059 case SCI_GETCARETLINEVISIBLEALWAYS
:
7060 return vs
.alwaysShowCaretLineBackground
;
7061 case SCI_SETCARETLINEVISIBLEALWAYS
:
7062 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
7063 InvalidateStyleRedraw();
7066 case SCI_GETCARETLINEFRAME
:
7067 return vs
.caretLineFrame
;
7068 case SCI_SETCARETLINEFRAME
:
7069 vs
.caretLineFrame
= static_cast<int>(wParam
);
7070 InvalidateStyleRedraw();
7072 case SCI_GETCARETLINEBACK
:
7073 return vs
.caretLineBackground
.AsLong();
7074 case SCI_SETCARETLINEBACK
:
7075 vs
.caretLineBackground
= static_cast<int>(wParam
);
7076 InvalidateStyleRedraw();
7078 case SCI_GETCARETLINEBACKALPHA
:
7079 return vs
.caretLineAlpha
;
7080 case SCI_SETCARETLINEBACKALPHA
:
7081 vs
.caretLineAlpha
= static_cast<int>(wParam
);
7082 InvalidateStyleRedraw();
7087 case SCI_VISIBLEFROMDOCLINE
:
7088 return cs
.DisplayFromDoc(static_cast<int>(wParam
));
7090 case SCI_DOCLINEFROMVISIBLE
:
7091 return cs
.DocFromDisplay(static_cast<int>(wParam
));
7094 return WrapCount(static_cast<int>(wParam
));
7096 case SCI_SETFOLDLEVEL
: {
7097 int prev
= pdoc
->SetLevel(static_cast<int>(wParam
), static_cast<int>(lParam
));
7098 if (prev
!= static_cast<int>(lParam
))
7103 case SCI_GETFOLDLEVEL
:
7104 return pdoc
->GetLevel(static_cast<int>(wParam
));
7106 case SCI_GETLASTCHILD
:
7107 return pdoc
->GetLastChild(static_cast<int>(wParam
), static_cast<int>(lParam
));
7109 case SCI_GETFOLDPARENT
:
7110 return pdoc
->GetFoldParent(static_cast<int>(wParam
));
7113 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), true);
7120 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), false);
7125 case SCI_GETLINEVISIBLE
:
7126 return cs
.GetVisible(static_cast<int>(wParam
));
7128 case SCI_GETALLLINESVISIBLE
:
7129 return cs
.HiddenLines() ? 0 : 1;
7131 case SCI_SETFOLDEXPANDED
:
7132 SetFoldExpanded(static_cast<int>(wParam
), lParam
!= 0);
7135 case SCI_GETFOLDEXPANDED
:
7136 return cs
.GetExpanded(static_cast<int>(wParam
));
7138 case SCI_SETAUTOMATICFOLD
:
7139 foldAutomatic
= static_cast<int>(wParam
);
7142 case SCI_GETAUTOMATICFOLD
:
7143 return foldAutomatic
;
7145 case SCI_SETFOLDFLAGS
:
7146 foldFlags
= static_cast<int>(wParam
);
7150 case SCI_TOGGLEFOLDSHOWTEXT
:
7151 cs
.SetFoldDisplayText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7152 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
7155 case SCI_FOLDDISPLAYTEXTSETSTYLE
:
7156 foldDisplayTextStyle
= static_cast<int>(wParam
);
7160 case SCI_TOGGLEFOLD
:
7161 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
7165 FoldLine(static_cast<int>(wParam
), static_cast<int>(lParam
));
7168 case SCI_FOLDCHILDREN
:
7169 FoldExpand(static_cast<int>(wParam
), static_cast<int>(lParam
), pdoc
->GetLevel(static_cast<int>(wParam
)));
7173 FoldAll(static_cast<int>(wParam
));
7176 case SCI_EXPANDCHILDREN
:
7177 FoldExpand(static_cast<int>(wParam
), SC_FOLDACTION_EXPAND
, static_cast<int>(lParam
));
7180 case SCI_CONTRACTEDFOLDNEXT
:
7181 return ContractedFoldNext(static_cast<int>(wParam
));
7183 case SCI_ENSUREVISIBLE
:
7184 EnsureLineVisible(static_cast<int>(wParam
), false);
7187 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
7188 EnsureLineVisible(static_cast<int>(wParam
), true);
7191 case SCI_SCROLLRANGE
:
7192 ScrollRange(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7195 case SCI_SEARCHANCHOR
:
7199 case SCI_SEARCHNEXT
:
7200 case SCI_SEARCHPREV
:
7201 return SearchText(iMessage
, wParam
, lParam
);
7203 case SCI_SETXCARETPOLICY
:
7204 caretXPolicy
= static_cast<int>(wParam
);
7205 caretXSlop
= static_cast<int>(lParam
);
7208 case SCI_SETYCARETPOLICY
:
7209 caretYPolicy
= static_cast<int>(wParam
);
7210 caretYSlop
= static_cast<int>(lParam
);
7213 case SCI_SETVISIBLEPOLICY
:
7214 visiblePolicy
= static_cast<int>(wParam
);
7215 visibleSlop
= static_cast<int>(lParam
);
7218 case SCI_LINESONSCREEN
:
7219 return LinesOnScreen();
7221 case SCI_SETSELFORE
:
7222 vs
.selColours
.fore
= ColourOptional(wParam
, lParam
);
7223 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(lParam
));
7224 InvalidateStyleRedraw();
7227 case SCI_SETSELBACK
:
7228 vs
.selColours
.back
= ColourOptional(wParam
, lParam
);
7229 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(lParam
));
7230 InvalidateStyleRedraw();
7233 case SCI_SETSELALPHA
:
7234 vs
.selAlpha
= static_cast<int>(wParam
);
7235 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7236 InvalidateStyleRedraw();
7239 case SCI_GETSELALPHA
:
7242 case SCI_GETSELEOLFILLED
:
7243 return vs
.selEOLFilled
;
7245 case SCI_SETSELEOLFILLED
:
7246 vs
.selEOLFilled
= wParam
!= 0;
7247 InvalidateStyleRedraw();
7250 case SCI_SETWHITESPACEFORE
:
7251 vs
.whitespaceColours
.fore
= ColourOptional(wParam
, lParam
);
7252 InvalidateStyleRedraw();
7255 case SCI_SETWHITESPACEBACK
:
7256 vs
.whitespaceColours
.back
= ColourOptional(wParam
, lParam
);
7257 InvalidateStyleRedraw();
7260 case SCI_SETCARETFORE
:
7261 vs
.caretcolour
= ColourDesired(static_cast<long>(wParam
));
7262 InvalidateStyleRedraw();
7265 case SCI_GETCARETFORE
:
7266 return vs
.caretcolour
.AsLong();
7268 case SCI_SETCARETSTYLE
:
7269 if (wParam
<= CARETSTYLE_BLOCK
)
7270 vs
.caretStyle
= static_cast<int>(wParam
);
7272 /* Default to the line caret */
7273 vs
.caretStyle
= CARETSTYLE_LINE
;
7274 InvalidateStyleRedraw();
7277 case SCI_GETCARETSTYLE
:
7278 return vs
.caretStyle
;
7280 case SCI_SETCARETWIDTH
:
7281 if (static_cast<int>(wParam
) <= 0)
7283 else if (wParam
>= 3)
7286 vs
.caretWidth
= static_cast<int>(wParam
);
7287 InvalidateStyleRedraw();
7290 case SCI_GETCARETWIDTH
:
7291 return vs
.caretWidth
;
7293 case SCI_ASSIGNCMDKEY
:
7294 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7295 Platform::HighShortFromLong(static_cast<long>(wParam
)), static_cast<unsigned int>(lParam
));
7298 case SCI_CLEARCMDKEY
:
7299 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7300 Platform::HighShortFromLong(static_cast<long>(wParam
)), SCI_NULL
);
7303 case SCI_CLEARALLCMDKEYS
:
7307 case SCI_INDICSETSTYLE
:
7308 if (wParam
<= INDIC_MAX
) {
7309 vs
.indicators
[wParam
].sacNormal
.style
= static_cast<int>(lParam
);
7310 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7311 InvalidateStyleRedraw();
7315 case SCI_INDICGETSTYLE
:
7316 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.style
: 0;
7318 case SCI_INDICSETFORE
:
7319 if (wParam
<= INDIC_MAX
) {
7320 vs
.indicators
[wParam
].sacNormal
.fore
= ColourDesired(static_cast<long>(lParam
));
7321 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7322 InvalidateStyleRedraw();
7326 case SCI_INDICGETFORE
:
7327 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.fore
.AsLong() : 0;
7329 case SCI_INDICSETHOVERSTYLE
:
7330 if (wParam
<= INDIC_MAX
) {
7331 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7332 InvalidateStyleRedraw();
7336 case SCI_INDICGETHOVERSTYLE
:
7337 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.style
: 0;
7339 case SCI_INDICSETHOVERFORE
:
7340 if (wParam
<= INDIC_MAX
) {
7341 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7342 InvalidateStyleRedraw();
7346 case SCI_INDICGETHOVERFORE
:
7347 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.fore
.AsLong() : 0;
7349 case SCI_INDICSETFLAGS
:
7350 if (wParam
<= INDIC_MAX
) {
7351 vs
.indicators
[wParam
].SetFlags(static_cast<int>(lParam
));
7352 InvalidateStyleRedraw();
7356 case SCI_INDICGETFLAGS
:
7357 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].Flags() : 0;
7359 case SCI_INDICSETUNDER
:
7360 if (wParam
<= INDIC_MAX
) {
7361 vs
.indicators
[wParam
].under
= lParam
!= 0;
7362 InvalidateStyleRedraw();
7366 case SCI_INDICGETUNDER
:
7367 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
7369 case SCI_INDICSETALPHA
:
7370 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7371 vs
.indicators
[wParam
].fillAlpha
= static_cast<int>(lParam
);
7372 InvalidateStyleRedraw();
7376 case SCI_INDICGETALPHA
:
7377 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
7379 case SCI_INDICSETOUTLINEALPHA
:
7380 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7381 vs
.indicators
[wParam
].outlineAlpha
= static_cast<int>(lParam
);
7382 InvalidateStyleRedraw();
7386 case SCI_INDICGETOUTLINEALPHA
:
7387 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
7389 case SCI_SETINDICATORCURRENT
:
7390 pdoc
->DecorationSetCurrentIndicator(static_cast<int>(wParam
));
7392 case SCI_GETINDICATORCURRENT
:
7393 return pdoc
->decorations
.GetCurrentIndicator();
7394 case SCI_SETINDICATORVALUE
:
7395 pdoc
->decorations
.SetCurrentValue(static_cast<int>(wParam
));
7397 case SCI_GETINDICATORVALUE
:
7398 return pdoc
->decorations
.GetCurrentValue();
7400 case SCI_INDICATORFILLRANGE
:
7401 pdoc
->DecorationFillRange(static_cast<int>(wParam
), pdoc
->decorations
.GetCurrentValue(), static_cast<int>(lParam
));
7404 case SCI_INDICATORCLEARRANGE
:
7405 pdoc
->DecorationFillRange(static_cast<int>(wParam
), 0, static_cast<int>(lParam
));
7408 case SCI_INDICATORALLONFOR
:
7409 return pdoc
->decorations
.AllOnFor(static_cast<int>(wParam
));
7411 case SCI_INDICATORVALUEAT
:
7412 return pdoc
->decorations
.ValueAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
7414 case SCI_INDICATORSTART
:
7415 return pdoc
->decorations
.Start(static_cast<int>(wParam
), static_cast<int>(lParam
));
7417 case SCI_INDICATOREND
:
7418 return pdoc
->decorations
.End(static_cast<int>(wParam
), static_cast<int>(lParam
));
7421 case SCI_LINEDOWNEXTEND
:
7423 case SCI_PARADOWNEXTEND
:
7425 case SCI_LINEUPEXTEND
:
7427 case SCI_PARAUPEXTEND
:
7429 case SCI_CHARLEFTEXTEND
:
7431 case SCI_CHARRIGHTEXTEND
:
7433 case SCI_WORDLEFTEXTEND
:
7435 case SCI_WORDRIGHTEXTEND
:
7436 case SCI_WORDLEFTEND
:
7437 case SCI_WORDLEFTENDEXTEND
:
7438 case SCI_WORDRIGHTEND
:
7439 case SCI_WORDRIGHTENDEXTEND
:
7441 case SCI_HOMEEXTEND
:
7443 case SCI_LINEENDEXTEND
:
7445 case SCI_HOMEWRAPEXTEND
:
7446 case SCI_LINEENDWRAP
:
7447 case SCI_LINEENDWRAPEXTEND
:
7448 case SCI_DOCUMENTSTART
:
7449 case SCI_DOCUMENTSTARTEXTEND
:
7450 case SCI_DOCUMENTEND
:
7451 case SCI_DOCUMENTENDEXTEND
:
7452 case SCI_SCROLLTOSTART
:
7453 case SCI_SCROLLTOEND
:
7455 case SCI_STUTTEREDPAGEUP
:
7456 case SCI_STUTTEREDPAGEUPEXTEND
:
7457 case SCI_STUTTEREDPAGEDOWN
:
7458 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7461 case SCI_PAGEUPEXTEND
:
7463 case SCI_PAGEDOWNEXTEND
:
7464 case SCI_EDITTOGGLEOVERTYPE
:
7466 case SCI_DELETEBACK
:
7472 case SCI_VCHOMEEXTEND
:
7473 case SCI_VCHOMEWRAP
:
7474 case SCI_VCHOMEWRAPEXTEND
:
7475 case SCI_VCHOMEDISPLAY
:
7476 case SCI_VCHOMEDISPLAYEXTEND
:
7479 case SCI_DELWORDLEFT
:
7480 case SCI_DELWORDRIGHT
:
7481 case SCI_DELWORDRIGHTEND
:
7482 case SCI_DELLINELEFT
:
7483 case SCI_DELLINERIGHT
:
7486 case SCI_LINEDELETE
:
7487 case SCI_LINETRANSPOSE
:
7488 case SCI_LINEREVERSE
:
7489 case SCI_LINEDUPLICATE
:
7492 case SCI_LINESCROLLDOWN
:
7493 case SCI_LINESCROLLUP
:
7494 case SCI_WORDPARTLEFT
:
7495 case SCI_WORDPARTLEFTEXTEND
:
7496 case SCI_WORDPARTRIGHT
:
7497 case SCI_WORDPARTRIGHTEXTEND
:
7498 case SCI_DELETEBACKNOTLINE
:
7499 case SCI_HOMEDISPLAY
:
7500 case SCI_HOMEDISPLAYEXTEND
:
7501 case SCI_LINEENDDISPLAY
:
7502 case SCI_LINEENDDISPLAYEXTEND
:
7503 case SCI_LINEDOWNRECTEXTEND
:
7504 case SCI_LINEUPRECTEXTEND
:
7505 case SCI_CHARLEFTRECTEXTEND
:
7506 case SCI_CHARRIGHTRECTEXTEND
:
7507 case SCI_HOMERECTEXTEND
:
7508 case SCI_VCHOMERECTEXTEND
:
7509 case SCI_LINEENDRECTEXTEND
:
7510 case SCI_PAGEUPRECTEXTEND
:
7511 case SCI_PAGEDOWNRECTEXTEND
:
7512 case SCI_SELECTIONDUPLICATE
:
7513 return KeyCommand(iMessage
);
7515 case SCI_BRACEHIGHLIGHT
:
7516 SetBraceHighlight(static_cast<int>(wParam
), static_cast<int>(lParam
), STYLE_BRACELIGHT
);
7519 case SCI_BRACEHIGHLIGHTINDICATOR
:
7520 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7521 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
7522 vs
.braceHighlightIndicator
= static_cast<int>(lParam
);
7526 case SCI_BRACEBADLIGHT
:
7527 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7530 case SCI_BRACEBADLIGHTINDICATOR
:
7531 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7532 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
7533 vs
.braceBadLightIndicator
= static_cast<int>(lParam
);
7537 case SCI_BRACEMATCH
:
7538 // wParam is position of char to find brace for,
7539 // lParam is maximum amount of text to restyle to find it
7540 return pdoc
->BraceMatch(static_cast<int>(wParam
), static_cast<int>(lParam
));
7542 case SCI_GETVIEWEOL
:
7545 case SCI_SETVIEWEOL
:
7546 vs
.viewEOL
= wParam
!= 0;
7547 InvalidateStyleRedraw();
7551 vs
.zoomLevel
= static_cast<int>(wParam
);
7552 InvalidateStyleRedraw();
7557 return vs
.zoomLevel
;
7559 case SCI_GETEDGECOLUMN
:
7560 return vs
.theEdge
.column
;
7562 case SCI_SETEDGECOLUMN
:
7563 vs
.theEdge
.column
= static_cast<int>(wParam
);
7564 InvalidateStyleRedraw();
7567 case SCI_GETEDGEMODE
:
7568 return vs
.edgeState
;
7570 case SCI_SETEDGEMODE
:
7571 vs
.edgeState
= static_cast<int>(wParam
);
7572 InvalidateStyleRedraw();
7575 case SCI_GETEDGECOLOUR
:
7576 return vs
.theEdge
.colour
.AsLong();
7578 case SCI_SETEDGECOLOUR
:
7579 vs
.theEdge
.colour
= ColourDesired(static_cast<long>(wParam
));
7580 InvalidateStyleRedraw();
7583 case SCI_MULTIEDGEADDLINE
:
7584 vs
.theMultiEdge
.push_back(EdgeProperties(wParam
, lParam
));
7585 InvalidateStyleRedraw();
7588 case SCI_MULTIEDGECLEARALL
:
7589 std::vector
<EdgeProperties
>().swap(vs
.theMultiEdge
); // Free vector and memory, C++03 compatible
7590 InvalidateStyleRedraw();
7593 case SCI_GETACCESSIBILITY
:
7594 return SC_ACCESSIBILITY_DISABLED
;
7596 case SCI_SETACCESSIBILITY
:
7597 // May be implemented by platform code.
7600 case SCI_GETDOCPOINTER
:
7601 return reinterpret_cast<sptr_t
>(pdoc
);
7603 case SCI_SETDOCPOINTER
:
7605 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7608 case SCI_CREATEDOCUMENT
: {
7609 Document
*doc
= new Document();
7611 return reinterpret_cast<sptr_t
>(doc
);
7614 case SCI_ADDREFDOCUMENT
:
7615 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7618 case SCI_RELEASEDOCUMENT
:
7619 (reinterpret_cast<Document
*>(lParam
))->Release();
7622 case SCI_CREATELOADER
: {
7623 Document
*doc
= new Document();
7625 doc
->Allocate(static_cast<int>(wParam
));
7626 doc
->SetUndoCollection(false);
7627 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
7630 case SCI_SETMODEVENTMASK
:
7631 modEventMask
= static_cast<int>(wParam
);
7634 case SCI_GETMODEVENTMASK
:
7635 return modEventMask
;
7637 case SCI_CONVERTEOLS
:
7638 pdoc
->ConvertLineEnds(static_cast<int>(wParam
));
7639 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7642 case SCI_SETLENGTHFORENCODE
:
7643 lengthForEncode
= static_cast<int>(wParam
);
7646 case SCI_SELECTIONISRECTANGLE
:
7647 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7649 case SCI_SETSELECTIONMODE
: {
7652 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7653 sel
.selType
= Selection::selStream
;
7655 case SC_SEL_RECTANGLE
:
7656 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7657 sel
.selType
= Selection::selRectangle
;
7660 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7661 sel
.selType
= Selection::selLines
;
7664 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7665 sel
.selType
= Selection::selThin
;
7668 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7669 sel
.selType
= Selection::selStream
;
7671 InvalidateWholeSelection();
7674 case SCI_GETSELECTIONMODE
:
7675 switch (sel
.selType
) {
7676 case Selection::selStream
:
7677 return SC_SEL_STREAM
;
7678 case Selection::selRectangle
:
7679 return SC_SEL_RECTANGLE
;
7680 case Selection::selLines
:
7681 return SC_SEL_LINES
;
7682 case Selection::selThin
:
7685 return SC_SEL_STREAM
;
7687 case SCI_GETLINESELSTARTPOSITION
:
7688 case SCI_GETLINESELENDPOSITION
: {
7689 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(static_cast<int>(wParam
))),
7690 SelectionPosition(pdoc
->LineEnd(static_cast<int>(wParam
))));
7691 for (size_t r
=0; r
<sel
.Count(); r
++) {
7692 const SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7693 if (portion
.start
.IsValid()) {
7694 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
7697 return INVALID_POSITION
;
7700 case SCI_SETOVERTYPE
:
7701 inOverstrike
= wParam
!= 0;
7704 case SCI_GETOVERTYPE
:
7705 return inOverstrike
? 1 : 0;
7708 SetFocusState(wParam
!= 0);
7715 errorStatus
= static_cast<int>(wParam
);
7721 case SCI_SETMOUSEDOWNCAPTURES
:
7722 mouseDownCaptures
= wParam
!= 0;
7725 case SCI_GETMOUSEDOWNCAPTURES
:
7726 return mouseDownCaptures
;
7728 case SCI_SETMOUSEWHEELCAPTURES
:
7729 mouseWheelCaptures
= wParam
!= 0;
7732 case SCI_GETMOUSEWHEELCAPTURES
:
7733 return mouseWheelCaptures
;
7736 cursorMode
= static_cast<int>(wParam
);
7737 DisplayCursor(Window::cursorText
);
7743 case SCI_SETCONTROLCHARSYMBOL
:
7744 vs
.controlCharSymbol
= static_cast<int>(wParam
);
7745 InvalidateStyleRedraw();
7748 case SCI_GETCONTROLCHARSYMBOL
:
7749 return vs
.controlCharSymbol
;
7751 case SCI_SETREPRESENTATION
:
7752 reprs
.SetRepresentation(reinterpret_cast<const char *>(wParam
), CharPtrFromSPtr(lParam
));
7755 case SCI_GETREPRESENTATION
: {
7756 const Representation
*repr
= reprs
.RepresentationFromCharacter(
7757 reinterpret_cast<const char *>(wParam
), UTF8MaxBytes
);
7759 return StringResult(lParam
, repr
->stringRep
.c_str());
7764 case SCI_CLEARREPRESENTATION
:
7765 reprs
.ClearRepresentation(reinterpret_cast<const char *>(wParam
));
7768 case SCI_STARTRECORD
:
7769 recordingMacro
= true;
7772 case SCI_STOPRECORD
:
7773 recordingMacro
= false;
7776 case SCI_MOVECARETINSIDEVIEW
:
7777 MoveCaretInsideView();
7780 case SCI_SETFOLDMARGINCOLOUR
:
7781 vs
.foldmarginColour
= ColourOptional(wParam
, lParam
);
7782 InvalidateStyleRedraw();
7785 case SCI_SETFOLDMARGINHICOLOUR
:
7786 vs
.foldmarginHighlightColour
= ColourOptional(wParam
, lParam
);
7787 InvalidateStyleRedraw();
7790 case SCI_SETHOTSPOTACTIVEFORE
:
7791 vs
.hotspotColours
.fore
= ColourOptional(wParam
, lParam
);
7792 InvalidateStyleRedraw();
7795 case SCI_GETHOTSPOTACTIVEFORE
:
7796 return vs
.hotspotColours
.fore
.AsLong();
7798 case SCI_SETHOTSPOTACTIVEBACK
:
7799 vs
.hotspotColours
.back
= ColourOptional(wParam
, lParam
);
7800 InvalidateStyleRedraw();
7803 case SCI_GETHOTSPOTACTIVEBACK
:
7804 return vs
.hotspotColours
.back
.AsLong();
7806 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7807 vs
.hotspotUnderline
= wParam
!= 0;
7808 InvalidateStyleRedraw();
7811 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7812 return vs
.hotspotUnderline
? 1 : 0;
7814 case SCI_SETHOTSPOTSINGLELINE
:
7815 vs
.hotspotSingleLine
= wParam
!= 0;
7816 InvalidateStyleRedraw();
7819 case SCI_GETHOTSPOTSINGLELINE
:
7820 return vs
.hotspotSingleLine
? 1 : 0;
7822 case SCI_SETPASTECONVERTENDINGS
:
7823 convertPastes
= wParam
!= 0;
7826 case SCI_GETPASTECONVERTENDINGS
:
7827 return convertPastes
? 1 : 0;
7829 case SCI_GETCHARACTERPOINTER
:
7830 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
7832 case SCI_GETRANGEPOINTER
:
7833 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7835 case SCI_GETGAPPOSITION
:
7836 return pdoc
->GapPosition();
7838 case SCI_SETEXTRAASCENT
:
7839 vs
.extraAscent
= static_cast<int>(wParam
);
7840 InvalidateStyleRedraw();
7843 case SCI_GETEXTRAASCENT
:
7844 return vs
.extraAscent
;
7846 case SCI_SETEXTRADESCENT
:
7847 vs
.extraDescent
= static_cast<int>(wParam
);
7848 InvalidateStyleRedraw();
7851 case SCI_GETEXTRADESCENT
:
7852 return vs
.extraDescent
;
7854 case SCI_MARGINSETSTYLEOFFSET
:
7855 vs
.marginStyleOffset
= static_cast<int>(wParam
);
7856 InvalidateStyleRedraw();
7859 case SCI_MARGINGETSTYLEOFFSET
:
7860 return vs
.marginStyleOffset
;
7862 case SCI_SETMARGINOPTIONS
:
7863 marginOptions
= static_cast<int>(wParam
);
7866 case SCI_GETMARGINOPTIONS
:
7867 return marginOptions
;
7869 case SCI_MARGINSETTEXT
:
7870 pdoc
->MarginSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7873 case SCI_MARGINGETTEXT
: {
7874 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7875 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7878 case SCI_MARGINSETSTYLE
:
7879 pdoc
->MarginSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7882 case SCI_MARGINGETSTYLE
: {
7883 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7887 case SCI_MARGINSETSTYLES
:
7888 pdoc
->MarginSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7891 case SCI_MARGINGETSTYLES
: {
7892 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7893 return BytesResult(lParam
, st
.styles
, st
.length
);
7896 case SCI_MARGINTEXTCLEARALL
:
7897 pdoc
->MarginClearAll();
7900 case SCI_ANNOTATIONSETTEXT
:
7901 pdoc
->AnnotationSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7904 case SCI_ANNOTATIONGETTEXT
: {
7905 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7906 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7909 case SCI_ANNOTATIONGETSTYLE
: {
7910 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7914 case SCI_ANNOTATIONSETSTYLE
:
7915 pdoc
->AnnotationSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7918 case SCI_ANNOTATIONSETSTYLES
:
7919 pdoc
->AnnotationSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7922 case SCI_ANNOTATIONGETSTYLES
: {
7923 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7924 return BytesResult(lParam
, st
.styles
, st
.length
);
7927 case SCI_ANNOTATIONGETLINES
:
7928 return pdoc
->AnnotationLines(static_cast<int>(wParam
));
7930 case SCI_ANNOTATIONCLEARALL
:
7931 pdoc
->AnnotationClearAll();
7934 case SCI_ANNOTATIONSETVISIBLE
:
7935 SetAnnotationVisible(static_cast<int>(wParam
));
7938 case SCI_ANNOTATIONGETVISIBLE
:
7939 return vs
.annotationVisible
;
7941 case SCI_ANNOTATIONSETSTYLEOFFSET
:
7942 vs
.annotationStyleOffset
= static_cast<int>(wParam
);
7943 InvalidateStyleRedraw();
7946 case SCI_ANNOTATIONGETSTYLEOFFSET
:
7947 return vs
.annotationStyleOffset
;
7949 case SCI_RELEASEALLEXTENDEDSTYLES
:
7950 vs
.ReleaseAllExtendedStyles();
7953 case SCI_ALLOCATEEXTENDEDSTYLES
:
7954 return vs
.AllocateExtendedStyles(static_cast<int>(wParam
));
7956 case SCI_ADDUNDOACTION
:
7957 pdoc
->AddUndoAction(static_cast<int>(wParam
), lParam
& UNDO_MAY_COALESCE
);
7960 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH
:
7961 mouseSelectionRectangularSwitch
= wParam
!= 0;
7964 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH
:
7965 return mouseSelectionRectangularSwitch
;
7967 case SCI_SETMULTIPLESELECTION
:
7968 multipleSelection
= wParam
!= 0;
7972 case SCI_GETMULTIPLESELECTION
:
7973 return multipleSelection
;
7975 case SCI_SETADDITIONALSELECTIONTYPING
:
7976 additionalSelectionTyping
= wParam
!= 0;
7980 case SCI_GETADDITIONALSELECTIONTYPING
:
7981 return additionalSelectionTyping
;
7983 case SCI_SETMULTIPASTE
:
7984 multiPasteMode
= static_cast<int>(wParam
);
7987 case SCI_GETMULTIPASTE
:
7988 return multiPasteMode
;
7990 case SCI_SETADDITIONALCARETSBLINK
:
7991 view
.additionalCaretsBlink
= wParam
!= 0;
7995 case SCI_GETADDITIONALCARETSBLINK
:
7996 return view
.additionalCaretsBlink
;
7998 case SCI_SETADDITIONALCARETSVISIBLE
:
7999 view
.additionalCaretsVisible
= wParam
!= 0;
8003 case SCI_GETADDITIONALCARETSVISIBLE
:
8004 return view
.additionalCaretsVisible
;
8006 case SCI_GETSELECTIONS
:
8009 case SCI_GETSELECTIONEMPTY
:
8012 case SCI_CLEARSELECTIONS
:
8014 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
8018 case SCI_SETSELECTION
:
8019 sel
.SetSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
8023 case SCI_ADDSELECTION
:
8024 sel
.AddSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
8025 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
8029 case SCI_DROPSELECTIONN
:
8030 sel
.DropSelection(static_cast<int>(wParam
));
8031 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
8035 case SCI_SETMAINSELECTION
:
8036 sel
.SetMain(static_cast<int>(wParam
));
8037 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
8041 case SCI_GETMAINSELECTION
:
8044 case SCI_SETSELECTIONNCARET
:
8045 case SCI_SETSELECTIONNANCHOR
:
8046 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
8047 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
8048 case SCI_SETSELECTIONNSTART
:
8049 case SCI_SETSELECTIONNEND
:
8050 SetSelectionNMessage(iMessage
, wParam
, lParam
);
8053 case SCI_GETSELECTIONNCARET
:
8054 return sel
.Range(wParam
).caret
.Position();
8056 case SCI_GETSELECTIONNANCHOR
:
8057 return sel
.Range(wParam
).anchor
.Position();
8059 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
8060 return sel
.Range(wParam
).caret
.VirtualSpace();
8062 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
8063 return sel
.Range(wParam
).anchor
.VirtualSpace();
8065 case SCI_GETSELECTIONNSTART
:
8066 return sel
.Range(wParam
).Start().Position();
8068 case SCI_GETSELECTIONNEND
:
8069 return sel
.Range(wParam
).End().Position();
8071 case SCI_SETRECTANGULARSELECTIONCARET
:
8072 if (!sel
.IsRectangular())
8074 sel
.selType
= Selection::selRectangle
;
8075 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
8076 SetRectangularRange();
8080 case SCI_GETRECTANGULARSELECTIONCARET
:
8081 return sel
.Rectangular().caret
.Position();
8083 case SCI_SETRECTANGULARSELECTIONANCHOR
:
8084 if (!sel
.IsRectangular())
8086 sel
.selType
= Selection::selRectangle
;
8087 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
8088 SetRectangularRange();
8092 case SCI_GETRECTANGULARSELECTIONANCHOR
:
8093 return sel
.Rectangular().anchor
.Position();
8095 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
8096 if (!sel
.IsRectangular())
8098 sel
.selType
= Selection::selRectangle
;
8099 sel
.Rectangular().caret
.SetVirtualSpace(static_cast<int>(wParam
));
8100 SetRectangularRange();
8104 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
8105 return sel
.Rectangular().caret
.VirtualSpace();
8107 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
8108 if (!sel
.IsRectangular())
8110 sel
.selType
= Selection::selRectangle
;
8111 sel
.Rectangular().anchor
.SetVirtualSpace(static_cast<int>(wParam
));
8112 SetRectangularRange();
8116 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
8117 return sel
.Rectangular().anchor
.VirtualSpace();
8119 case SCI_SETVIRTUALSPACEOPTIONS
:
8120 virtualSpaceOptions
= static_cast<int>(wParam
);
8123 case SCI_GETVIRTUALSPACEOPTIONS
:
8124 return virtualSpaceOptions
;
8126 case SCI_SETADDITIONALSELFORE
:
8127 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(wParam
));
8128 InvalidateStyleRedraw();
8131 case SCI_SETADDITIONALSELBACK
:
8132 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(wParam
));
8133 InvalidateStyleRedraw();
8136 case SCI_SETADDITIONALSELALPHA
:
8137 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
8138 InvalidateStyleRedraw();
8141 case SCI_GETADDITIONALSELALPHA
:
8142 return vs
.selAdditionalAlpha
;
8144 case SCI_SETADDITIONALCARETFORE
:
8145 vs
.additionalCaretColour
= ColourDesired(static_cast<long>(wParam
));
8146 InvalidateStyleRedraw();
8149 case SCI_GETADDITIONALCARETFORE
:
8150 return vs
.additionalCaretColour
.AsLong();
8152 case SCI_ROTATESELECTION
:
8154 InvalidateWholeSelection();
8157 case SCI_SWAPMAINANCHORCARET
:
8158 InvalidateSelection(sel
.RangeMain());
8159 sel
.RangeMain().Swap();
8162 case SCI_MULTIPLESELECTADDNEXT
:
8163 MultipleSelectAdd(addOne
);
8166 case SCI_MULTIPLESELECTADDEACH
:
8167 MultipleSelectAdd(addEach
);
8170 case SCI_CHANGELEXERSTATE
:
8171 pdoc
->ChangeLexerState(static_cast<int>(wParam
), static_cast<int>(lParam
));
8174 case SCI_SETIDENTIFIER
:
8175 SetCtrlID(static_cast<int>(wParam
));
8178 case SCI_GETIDENTIFIER
:
8181 case SCI_SETTECHNOLOGY
:
8182 // No action by default
8185 case SCI_GETTECHNOLOGY
:
8188 case SCI_COUNTCHARACTERS
:
8189 return pdoc
->CountCharacters(static_cast<int>(wParam
), static_cast<int>(lParam
));
8192 return DefWndProc(iMessage
, wParam
, lParam
);
8194 //Platform::DebugPrintf("end wnd proc\n");