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.
25 #include "Scintilla.h"
27 #include "StringCopy.h"
29 #include "SplitVector.h"
30 #include "Partitioning.h"
31 #include "RunStyles.h"
32 #include "ContractionState.h"
33 #include "CellBuffer.h"
36 #include "Indicator.h"
38 #include "LineMarker.h"
40 #include "ViewStyle.h"
41 #include "CharClassify.h"
42 #include "Decoration.h"
43 #include "CaseFolder.h"
45 #include "UniConversion.h"
46 #include "Selection.h"
47 #include "PositionCache.h"
48 #include "EditModel.h"
49 #include "MarginView.h"
54 using namespace Scintilla
;
58 return whether this modification represents an operation that
59 may reasonably be deferred (not done now OR [possibly] at all)
61 static bool CanDeferToLastStep(const DocModification
&mh
) {
62 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
63 return true; // CAN skip
64 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
65 return false; // MUST do
66 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
67 return true; // CAN skip
68 return false; // PRESUMABLY must do
71 static bool CanEliminate(const DocModification
&mh
) {
73 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
77 return whether this modification represents the FINAL step
78 in a [possibly lengthy] multi-step Undo/Redo sequence
80 static bool IsLastStep(const DocModification
&mh
) {
82 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
83 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
84 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
85 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
89 ticking(false), ticksToWait(0), tickerID(0) {}
92 state(false), idlerID(0) {}
94 static inline bool IsAllSpacesOrTabs(const char *s
, unsigned int len
) {
95 for (unsigned int i
= 0; i
< len
; i
++) {
96 // This is safe because IsSpaceOrTab() will return false for null terminators
97 if (!IsSpaceOrTab(s
[i
]))
107 technology
= SC_TECHNOLOGY_DEFAULT
;
108 scaleRGBAImage
= 100.0f
;
110 cursorMode
= SC_CURSORNORMAL
;
114 mouseDownCaptures
= true;
117 doubleClickCloseThreshold
= Point(3, 3);
118 dwellDelay
= SC_TIME_FOREVER
;
119 ticksToDwell
= SC_TIME_FOREVER
;
124 dropWentOutside
= false;
125 posDrop
= SelectionPosition(invalidPosition
);
126 hotSpotClickPos
= INVALID_POSITION
;
127 selectionType
= selChar
;
131 originalAnchorPos
= 0;
132 wordSelectAnchorStartPos
= 0;
133 wordSelectAnchorEndPos
= 0;
134 wordSelectInitialCaretPos
= -1;
136 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
139 caretYPolicy
= CARET_EVEN
;
148 horizontalScrollBarVisible
= true;
150 verticalScrollBarVisible
= true;
151 endAtLastLine
= true;
152 caretSticky
= SC_CARETSTICKY_OFF
;
153 marginOptions
= SC_MARGINOPTION_NONE
;
154 mouseSelectionRectangularSwitch
= false;
155 multipleSelection
= false;
156 additionalSelectionTyping
= false;
157 multiPasteMode
= SC_MULTIPASTE_ONCE
;
158 virtualSpaceOptions
= SCVS_NONE
;
167 lengthForEncode
= -1;
170 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
172 paintState
= notPainting
;
173 paintAbandonedByStyling
= false;
174 paintingAllText
= false;
175 willRedrawAll
= false;
176 idleStyling
= SC_IDLESTYLING_NONE
;
177 needIdleStyling
= false;
179 modEventMask
= SC_MODEVENTMASKALL
;
181 pdoc
->AddWatcher(this, 0);
183 recordingMacro
= false;
186 convertPastes
= true;
188 SetRepresentations();
192 pdoc
->RemoveWatcher(this, 0);
196 void Editor::Finalise() {
201 void Editor::SetRepresentations() {
205 const char *reps
[] = {
206 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
207 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
208 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
209 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
211 for (size_t j
=0; j
< ELEMENTS(reps
); j
++) {
212 char c
[2] = { static_cast<char>(j
), 0 };
213 reprs
.SetRepresentation(c
, reps
[j
]);
217 // As well as Unicode mode, ISO-8859-1 should use these
218 if (IsUnicodeMode()) {
219 const char *repsC1
[] = {
220 "PAD", "HOP", "BPH", "NBH", "IND", "NEL", "SSA", "ESA",
221 "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
222 "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
223 "SOS", "SGCI", "SCI", "CSI", "ST", "OSC", "PM", "APC"
225 for (size_t j
=0; j
< ELEMENTS(repsC1
); j
++) {
226 char c1
[3] = { '\xc2', static_cast<char>(0x80+j
), 0 };
227 reprs
.SetRepresentation(c1
, repsC1
[j
]);
229 reprs
.SetRepresentation("\xe2\x80\xa8", "LS");
230 reprs
.SetRepresentation("\xe2\x80\xa9", "PS");
233 // UTF-8 invalid bytes
234 if (IsUnicodeMode()) {
235 for (int k
=0x80; k
< 0x100; k
++) {
236 char hiByte
[2] = { static_cast<char>(k
), 0 };
238 sprintf(hexits
, "x%2X", k
);
239 reprs
.SetRepresentation(hiByte
, hexits
);
244 void Editor::DropGraphics(bool freeObjects
) {
245 marginView
.DropGraphics(freeObjects
);
246 view
.DropGraphics(freeObjects
);
249 void Editor::AllocateGraphics() {
250 marginView
.AllocateGraphics(vs
);
251 view
.AllocateGraphics(vs
);
254 void Editor::InvalidateStyleData() {
256 vs
.technology
= technology
;
259 view
.llc
.Invalidate(LineLayout::llInvalid
);
260 view
.posCache
.Clear();
263 void Editor::InvalidateStyleRedraw() {
265 InvalidateStyleData();
269 void Editor::RefreshStyleData() {
272 AutoSurface
surface(this);
274 vs
.Refresh(*surface
, pdoc
->tabInChars
);
277 SetRectangularRange();
281 Point
Editor::GetVisibleOriginInMain() const {
285 Point
Editor::DocumentPointFromView(Point ptView
) const {
286 Point ptDocument
= ptView
;
287 if (wMargin
.GetID()) {
288 Point ptOrigin
= GetVisibleOriginInMain();
289 ptDocument
.x
+= ptOrigin
.x
;
290 ptDocument
.y
+= ptOrigin
.y
;
292 ptDocument
.x
+= xOffset
;
293 ptDocument
.y
+= topLine
* vs
.lineHeight
;
298 int Editor::TopLineOfMain() const {
305 PRectangle
Editor::GetClientRectangle() const {
306 Window
&win
= const_cast<Window
&>(wMain
);
307 return win
.GetClientPosition();
310 PRectangle
Editor::GetClientDrawingRectangle() {
311 return GetClientRectangle();
314 PRectangle
Editor::GetTextRectangle() const {
315 PRectangle rc
= GetClientRectangle();
316 rc
.left
+= vs
.textStart
;
317 rc
.right
-= vs
.rightMarginWidth
;
321 int Editor::LinesOnScreen() const {
322 PRectangle rcClient
= GetClientRectangle();
323 int htClient
= static_cast<int>(rcClient
.bottom
- rcClient
.top
);
324 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
325 return htClient
/ vs
.lineHeight
;
328 int Editor::LinesToScroll() const {
329 int retVal
= LinesOnScreen() - 1;
336 int Editor::MaxScrollPos() const {
337 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
338 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
339 int retVal
= cs
.LinesDisplayed();
341 retVal
-= LinesOnScreen();
352 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
353 if (sp
.Position() < 0) {
354 return SelectionPosition(0);
355 } else if (sp
.Position() > pdoc
->Length()) {
356 return SelectionPosition(pdoc
->Length());
358 // If not at end of line then set offset to 0
359 if (!pdoc
->IsLineEndPosition(sp
.Position()))
360 sp
.SetVirtualSpace(0);
365 Point
Editor::LocationFromPosition(SelectionPosition pos
) {
367 AutoSurface
surface(this);
368 return view
.LocationFromPosition(surface
, *this, pos
, topLine
, vs
);
371 Point
Editor::LocationFromPosition(int pos
) {
372 return LocationFromPosition(SelectionPosition(pos
));
375 int Editor::XFromPosition(int pos
) {
376 Point pt
= LocationFromPosition(pos
);
377 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
380 int Editor::XFromPosition(SelectionPosition sp
) {
381 Point pt
= LocationFromPosition(sp
);
382 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
385 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
387 AutoSurface
surface(this);
389 if (canReturnInvalid
) {
390 PRectangle rcClient
= GetTextRectangle();
391 // May be in scroll view coordinates so translate back to main view
392 Point ptOrigin
= GetVisibleOriginInMain();
393 rcClient
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
394 if (!rcClient
.Contains(pt
))
395 return SelectionPosition(INVALID_POSITION
);
396 if (pt
.x
< vs
.textStart
)
397 return SelectionPosition(INVALID_POSITION
);
399 return SelectionPosition(INVALID_POSITION
);
401 pt
= DocumentPointFromView(pt
);
402 return view
.SPositionFromLocation(surface
, *this, pt
, canReturnInvalid
, charPosition
, virtualSpace
, vs
);
405 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
406 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
410 * Find the document position corresponding to an x coordinate on a particular document line.
411 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
412 * This method is used for rectangular selections and does not work on wrapped lines.
414 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
416 if (lineDoc
>= pdoc
->LinesTotal())
417 return SelectionPosition(pdoc
->Length());
418 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
419 AutoSurface
surface(this);
420 return view
.SPositionFromLineX(surface
, *this, lineDoc
, x
, vs
);
423 int Editor::PositionFromLineX(int lineDoc
, int x
) {
424 return SPositionFromLineX(lineDoc
, x
).Position();
427 int Editor::LineFromLocation(Point pt
) const {
428 return cs
.DocFromDisplay(static_cast<int>(pt
.y
) / vs
.lineHeight
+ topLine
);
431 void Editor::SetTopLine(int topLineNew
) {
432 if ((topLine
!= topLineNew
) && (topLineNew
>= 0)) {
433 topLine
= topLineNew
;
434 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
436 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
440 * If painting then abandon the painting because a wider redraw is needed.
441 * @return true if calling code should stop drawing.
443 bool Editor::AbandonPaint() {
444 if ((paintState
== painting
) && !paintingAllText
) {
445 paintState
= paintAbandoned
;
447 return paintState
== paintAbandoned
;
450 void Editor::RedrawRect(PRectangle rc
) {
451 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
453 // Clip the redraw rectangle into the client area
454 PRectangle rcClient
= GetClientRectangle();
455 if (rc
.top
< rcClient
.top
)
456 rc
.top
= rcClient
.top
;
457 if (rc
.bottom
> rcClient
.bottom
)
458 rc
.bottom
= rcClient
.bottom
;
459 if (rc
.left
< rcClient
.left
)
460 rc
.left
= rcClient
.left
;
461 if (rc
.right
> rcClient
.right
)
462 rc
.right
= rcClient
.right
;
464 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
465 wMain
.InvalidateRectangle(rc
);
469 void Editor::DiscardOverdraw() {
470 // Overridden on platforms that may draw outside visible area.
473 void Editor::Redraw() {
474 //Platform::DebugPrintf("Redraw all\n");
475 PRectangle rcClient
= GetClientRectangle();
476 wMain
.InvalidateRectangle(rcClient
);
478 wMargin
.InvalidateAll();
479 //wMain.InvalidateAll();
482 void Editor::RedrawSelMargin(int line
, bool allAfter
) {
483 const bool markersInText
= vs
.maskInLine
|| vs
.maskDrawInText
;
484 if (!wMargin
.GetID() || markersInText
) { // May affect text area so may need to abandon and retry
485 if (AbandonPaint()) {
489 if (wMargin
.GetID() && markersInText
) {
493 PRectangle rcMarkers
= GetClientRectangle();
494 if (!markersInText
) {
495 // Normal case: just draw the margin
496 rcMarkers
.right
= rcMarkers
.left
+ vs
.fixedColumnWidth
;
499 PRectangle rcLine
= RectangleFromRange(Range(pdoc
->LineStart(line
)), 0);
501 // Inflate line rectangle if there are image markers with height larger than line height
502 if (vs
.largestMarkerHeight
> vs
.lineHeight
) {
503 int delta
= (vs
.largestMarkerHeight
- vs
.lineHeight
+ 1) / 2;
505 rcLine
.bottom
+= delta
;
506 if (rcLine
.top
< rcMarkers
.top
)
507 rcLine
.top
= rcMarkers
.top
;
508 if (rcLine
.bottom
> rcMarkers
.bottom
)
509 rcLine
.bottom
= rcMarkers
.bottom
;
512 rcMarkers
.top
= rcLine
.top
;
514 rcMarkers
.bottom
= rcLine
.bottom
;
515 if (rcMarkers
.Empty())
518 if (wMargin
.GetID()) {
519 Point ptOrigin
= GetVisibleOriginInMain();
520 rcMarkers
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
521 wMargin
.InvalidateRectangle(rcMarkers
);
523 wMain
.InvalidateRectangle(rcMarkers
);
527 PRectangle
Editor::RectangleFromRange(Range r
, int overlap
) {
528 const int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.First()));
529 const int maxLine
= cs
.DisplayLastFromDoc(pdoc
->LineFromPosition(r
.Last()));
530 const PRectangle rcClientDrawing
= GetClientDrawingRectangle();
532 const int leftTextOverlap
= ((xOffset
== 0) && (vs
.leftMarginWidth
> 0)) ? 1 : 0;
533 rc
.left
= static_cast<XYPOSITION
>(vs
.textStart
- leftTextOverlap
);
534 rc
.top
= static_cast<XYPOSITION
>((minLine
- TopLineOfMain()) * vs
.lineHeight
- overlap
);
535 if (rc
.top
< rcClientDrawing
.top
)
536 rc
.top
= rcClientDrawing
.top
;
537 // Extend to right of prepared area if any to prevent artifacts from caret line highlight
538 rc
.right
= rcClientDrawing
.right
;
539 rc
.bottom
= static_cast<XYPOSITION
>((maxLine
- TopLineOfMain() + 1) * vs
.lineHeight
+ overlap
);
544 void Editor::InvalidateRange(int start
, int end
) {
545 RedrawRect(RectangleFromRange(Range(start
, end
), view
.LinesOverlap() ? vs
.lineOverlap
: 0));
548 int Editor::CurrentPosition() const {
549 return sel
.MainCaret();
552 bool Editor::SelectionEmpty() const {
556 SelectionPosition
Editor::SelectionStart() {
557 return sel
.RangeMain().Start();
560 SelectionPosition
Editor::SelectionEnd() {
561 return sel
.RangeMain().End();
564 void Editor::SetRectangularRange() {
565 if (sel
.IsRectangular()) {
566 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
567 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
568 if (sel
.selType
== Selection::selThin
) {
571 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
572 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
573 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
574 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
575 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
576 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
577 range
.ClearVirtualSpace();
578 if (line
== lineAnchorRect
)
579 sel
.SetSelection(range
);
581 sel
.AddSelectionWithoutTrim(range
);
586 void Editor::ThinRectangularRange() {
587 if (sel
.IsRectangular()) {
588 sel
.selType
= Selection::selThin
;
589 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
590 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
592 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
594 SetRectangularRange();
598 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
599 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
600 invalidateWholeSelection
= true;
602 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
603 // +1 for lastAffected ensures caret repainted
604 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
605 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
606 if (invalidateWholeSelection
) {
607 for (size_t r
=0; r
<sel
.Count(); r
++) {
608 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
609 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
610 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
611 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
614 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
615 InvalidateRange(firstAffected
, lastAffected
);
618 void Editor::InvalidateWholeSelection() {
619 InvalidateSelection(sel
.RangeMain(), true);
622 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
623 currentPos_
= ClampPositionIntoDocument(currentPos_
);
624 anchor_
= ClampPositionIntoDocument(anchor_
);
625 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
626 /* For Line selection - ensure the anchor and caret are always
627 at the beginning and end of the region lines. */
628 if (sel
.selType
== Selection::selLines
) {
629 if (currentPos_
> anchor_
) {
630 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
631 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
633 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
634 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
637 SelectionRange
rangeNew(currentPos_
, anchor_
);
638 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
639 InvalidateSelection(rangeNew
);
641 sel
.RangeMain() = rangeNew
;
642 SetRectangularRange();
644 SetHoverIndicatorPosition(sel
.MainCaret());
646 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
649 QueueIdleWork(WorkNeeded::workUpdateUI
);
652 void Editor::SetSelection(int currentPos_
, int anchor_
) {
653 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
656 // Just move the caret on the main selection
657 void Editor::SetSelection(SelectionPosition currentPos_
) {
658 currentPos_
= ClampPositionIntoDocument(currentPos_
);
659 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
660 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
661 InvalidateSelection(SelectionRange(currentPos_
));
663 if (sel
.IsRectangular()) {
665 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
666 SetRectangularRange();
669 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
672 SetHoverIndicatorPosition(sel
.MainCaret());
674 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
677 QueueIdleWork(WorkNeeded::workUpdateUI
);
680 void Editor::SetSelection(int currentPos_
) {
681 SetSelection(SelectionPosition(currentPos_
));
684 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
685 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
686 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
687 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
688 InvalidateSelection(rangeNew
);
691 sel
.RangeMain() = rangeNew
;
692 SetRectangularRange();
694 SetHoverIndicatorPosition(sel
.MainCaret());
696 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
699 QueueIdleWork(WorkNeeded::workUpdateUI
);
702 void Editor::SetEmptySelection(int currentPos_
) {
703 SetEmptySelection(SelectionPosition(currentPos_
));
706 void Editor::MultipleSelectAdd(AddNumber addNumber
) {
707 if (SelectionEmpty() || !multipleSelection
) {
708 // Select word at caret
709 const int startWord
= pdoc
->ExtendWordSelect(sel
.MainCaret(), -1, true);
710 const int endWord
= pdoc
->ExtendWordSelect(startWord
, 1, true);
711 TrimAndSetSelection(endWord
, startWord
);
715 if (!pdoc
->HasCaseFolder())
716 pdoc
->SetCaseFolder(CaseFolderForEncoding());
718 const Range
rangeMainSelection(sel
.RangeMain().Start().Position(), sel
.RangeMain().End().Position());
719 const std::string selectedText
= RangeText(rangeMainSelection
.start
, rangeMainSelection
.end
);
721 const Range
rangeTarget(targetStart
, targetEnd
);
722 std::vector
<Range
> searchRanges
;
723 // Search should be over the target range excluding the current selection so
724 // may need to search 2 ranges, after the selection then before the selection.
725 if (rangeTarget
.Overlaps(rangeMainSelection
)) {
726 // Common case is that the selection is completely within the target but
727 // may also have overlap at start or end.
728 if (rangeMainSelection
.end
< rangeTarget
.end
)
729 searchRanges
.push_back(Range(rangeMainSelection
.end
, rangeTarget
.end
));
730 if (rangeTarget
.start
< rangeMainSelection
.start
)
731 searchRanges
.push_back(Range(rangeTarget
.start
, rangeMainSelection
.start
));
734 searchRanges
.push_back(rangeTarget
);
737 for (std::vector
<Range
>::const_iterator it
= searchRanges
.begin(); it
!= searchRanges
.end(); ++it
) {
738 int searchStart
= it
->start
;
739 const int searchEnd
= it
->end
;
741 int lengthFound
= static_cast<int>(selectedText
.length());
742 int pos
= pdoc
->FindText(searchStart
, searchEnd
, selectedText
.c_str(),
743 searchFlags
, &lengthFound
);
745 sel
.AddSelection(SelectionRange(pos
+ lengthFound
, pos
));
746 ScrollRange(sel
.RangeMain());
748 if (addNumber
== addOne
)
750 searchStart
= pos
+ lengthFound
;
759 bool Editor::RangeContainsProtected(int start
, int end
) const {
760 if (vs
.ProtectionActive()) {
766 for (int pos
= start
; pos
< end
; pos
++) {
767 if (vs
.styles
[pdoc
->StyleIndexAt(pos
)].IsProtected())
774 bool Editor::SelectionContainsProtected() {
775 for (size_t r
=0; r
<sel
.Count(); r
++) {
776 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
777 sel
.Range(r
).End().Position())) {
785 * Asks document to find a good position and then moves out of any invisible positions.
787 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
788 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
791 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
792 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
793 if (posMoved
!= pos
.Position())
794 pos
.SetPosition(posMoved
);
795 if (vs
.ProtectionActive()) {
797 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleIndexAt(pos
.Position() - 1)].IsProtected()) {
798 while ((pos
.Position() < pdoc
->Length()) &&
799 (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position())].IsProtected()))
802 } else if (moveDir
< 0) {
803 if (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position())].IsProtected()) {
804 while ((pos
.Position() > 0) &&
805 (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position() - 1)].IsProtected()))
813 void Editor::MovedCaret(SelectionPosition newPos
, SelectionPosition previousPos
, bool ensureVisible
) {
814 const int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
816 // In case in need of wrapping to ensure DisplayFromDoc works.
817 if (currentLine
>= wrapPending
.start
)
819 XYScrollPosition newXY
= XYScrollToMakeVisible(
820 SelectionRange(posDrag
.IsValid() ? posDrag
: newPos
), xysDefault
);
821 if (previousPos
.IsValid() && (newXY
.xOffset
== xOffset
)) {
822 // simple vertical scroll then invalidate
823 ScrollTo(newXY
.topLine
);
824 InvalidateSelection(SelectionRange(previousPos
), true);
830 ShowCaretAtCurrentPosition();
833 SetHoverIndicatorPosition(sel
.MainCaret());
834 QueueIdleWork(WorkNeeded::workUpdateUI
);
836 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
841 void Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
842 const SelectionPosition spCaret
= ((sel
.Count() == 1) && sel
.Empty()) ?
843 sel
.Last() : SelectionPosition(INVALID_POSITION
);
845 int delta
= newPos
.Position() - sel
.MainCaret();
846 newPos
= ClampPositionIntoDocument(newPos
);
847 newPos
= MovePositionOutsideChar(newPos
, delta
);
848 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
849 // Can't turn into multiple selection so clear additional selections
850 InvalidateSelection(SelectionRange(newPos
), true);
851 sel
.DropAdditionalRanges();
853 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
854 // Switching to rectangular
855 InvalidateSelection(sel
.RangeMain(), false);
856 SelectionRange rangeMain
= sel
.RangeMain();
858 sel
.Rectangular() = rangeMain
;
860 if (selt
!= Selection::noSel
) {
863 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
864 SetSelection(newPos
);
866 SetEmptySelection(newPos
);
869 MovedCaret(newPos
, spCaret
, ensureVisible
);
872 void Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
873 MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
876 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
877 pos
= ClampPositionIntoDocument(pos
);
878 pos
= MovePositionOutsideChar(pos
, moveDir
);
879 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
880 if (cs
.GetVisible(lineDoc
)) {
883 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
885 // lineDisplay is already line before fold as lines in fold use display line of line after fold
886 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
887 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
889 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
890 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
895 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
896 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
899 Point
Editor::PointMainCaret() {
900 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
904 * Choose the x position that the caret will try to stick to
905 * as it moves up and down.
907 void Editor::SetLastXChosen() {
908 Point pt
= PointMainCaret();
909 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
912 void Editor::ScrollTo(int line
, bool moveThumb
) {
913 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
914 if (topLineNew
!= topLine
) {
915 // Try to optimise small scrolls
917 int linesToMove
= topLine
- topLineNew
;
918 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
919 willRedrawAll
= !performBlit
;
921 SetTopLine(topLineNew
);
922 // Optimize by styling the view as this will invalidate any needed area
923 // which could abort the initial paint if discovered later.
924 StyleAreaBounded(GetClientRectangle(), true);
926 // Perform redraw rather than scroll if many lines would be redrawn anyway.
928 ScrollText(linesToMove
);
932 willRedrawAll
= false;
937 SetVerticalScrollPos();
942 void Editor::ScrollText(int /* linesToMove */) {
943 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
947 void Editor::HorizontalScrollTo(int xPos
) {
948 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
951 if (!Wrapping() && (xOffset
!= xPos
)) {
953 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
954 SetHorizontalScrollPos();
955 RedrawRect(GetClientRectangle());
959 void Editor::VerticalCentreCaret() {
960 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
961 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
962 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
963 if (topLine
!= newTop
) {
964 SetTopLine(newTop
> 0 ? newTop
: 0);
965 RedrawRect(GetClientRectangle());
969 // Avoid 64 bit compiler warnings.
970 // Scintilla does not support text buffers larger than 2**31
971 static int istrlen(const char *s
) {
972 return static_cast<int>(s
? strlen(s
) : 0);
975 void Editor::MoveSelectedLines(int lineDelta
) {
977 // if selection doesn't start at the beginning of the line, set the new start
978 int selectionStart
= SelectionStart().Position();
979 int startLine
= pdoc
->LineFromPosition(selectionStart
);
980 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
981 selectionStart
= beginningOfStartLine
;
983 // if selection doesn't end at the beginning of a line greater than that of the start,
984 // then set it at the beginning of the next one
985 int selectionEnd
= SelectionEnd().Position();
986 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
987 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
988 bool appendEol
= false;
989 if (selectionEnd
> beginningOfEndLine
990 || selectionStart
== selectionEnd
) {
991 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
992 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
995 // if there's nowhere for the selection to move
996 // (i.e. at the beginning going up or at the end going down),
997 // stop it right there!
998 if ((selectionStart
== 0 && lineDelta
< 0)
999 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
1000 || selectionStart
== selectionEnd
) {
1006 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
1007 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
1009 selectionEnd
= CurrentPosition();
1011 SetSelection(selectionStart
, selectionEnd
);
1013 SelectionText selectedText
;
1014 CopySelectionRange(&selectedText
);
1016 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
1017 Point currentLocation
= LocationFromPosition(CurrentPosition());
1018 int currentLine
= LineFromLocation(currentLocation
);
1021 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
1024 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1025 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
1026 pdoc
->InsertString(pdoc
->Length(), eol
, istrlen(eol
));
1027 GoToLine(currentLine
+ lineDelta
);
1029 selectionLength
= pdoc
->InsertString(CurrentPosition(), selectedText
.Data(), selectionLength
);
1031 const int lengthInserted
= pdoc
->InsertString(CurrentPosition() + selectionLength
, eol
, istrlen(eol
));
1032 selectionLength
+= lengthInserted
;
1034 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
1037 void Editor::MoveSelectedLinesUp() {
1038 MoveSelectedLines(-1);
1041 void Editor::MoveSelectedLinesDown() {
1042 MoveSelectedLines(1);
1045 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1046 PRectangle rcClient
= GetTextRectangle();
1047 Point pt
= PointMainCaret();
1048 if (pt
.y
< rcClient
.top
) {
1049 MovePositionTo(SPositionFromLocation(
1050 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
)),
1051 false, false, UserVirtualSpace()),
1052 Selection::noSel
, ensureVisible
);
1053 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1054 int yOfLastLineFullyDisplayed
= static_cast<int>(rcClient
.top
) + (LinesOnScreen() - 1) * vs
.lineHeight
;
1055 MovePositionTo(SPositionFromLocation(
1056 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
) + yOfLastLineFullyDisplayed
),
1057 false, false, UserVirtualSpace()),
1058 Selection::noSel
, ensureVisible
);
1062 int Editor::DisplayFromPosition(int pos
) {
1063 AutoSurface
surface(this);
1064 return view
.DisplayFromPosition(surface
, *this, pos
, vs
);
1068 * Ensure the caret is reasonably visible in context.
1070 Caret policy in SciTE
1072 If slop is set, we can define a slop value.
1073 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1074 This zone is defined as a number of pixels near the vertical margins,
1075 and as a number of lines near the horizontal margins.
1076 By keeping the caret away from the edges, it is seen within its context,
1077 so it is likely that the identifier that the caret is on can be completely seen,
1078 and that the current line is seen with some of the lines following it which are
1079 often dependent on that line.
1081 If strict is set, the policy is enforced... strictly.
1082 The caret is centred on the display if slop is not set,
1083 and cannot go in the UZ if slop is set.
1085 If jumps is set, the display is moved more energetically
1086 so the caret can move in the same direction longer before the policy is applied again.
1087 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1089 If even is not set, instead of having symmetrical UZs,
1090 the left and bottom UZs are extended up to right and top UZs respectively.
1091 This way, we favour the displaying of useful information: the beginning of lines,
1092 where most code reside, and the lines after the caret, eg. the body of a function.
1095 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1096 | | | | | visibility or going into the UZ) display is...
1097 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1098 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1099 0 | 0 | 0 | 1 | Yes | moved by one position
1100 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1101 0 | 0 | 1 | 1 | Yes | centred on the caret
1102 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1103 0 | 1 | - | 1 | No, caret is always centred | -
1104 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1105 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1106 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1107 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1108 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1109 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1110 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1113 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const SelectionRange
&range
, const XYScrollOptions options
) {
1114 PRectangle rcClient
= GetTextRectangle();
1115 Point pt
= LocationFromPosition(range
.caret
);
1116 Point ptAnchor
= LocationFromPosition(range
.anchor
);
1117 const Point ptOrigin
= GetVisibleOriginInMain();
1120 ptAnchor
.x
+= ptOrigin
.x
;
1121 ptAnchor
.y
+= ptOrigin
.y
;
1122 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1124 XYScrollPosition
newXY(xOffset
, topLine
);
1125 if (rcClient
.Empty()) {
1129 // Vertical positioning
1130 if ((options
& xysVertical
) && (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1131 const int lineCaret
= DisplayFromPosition(range
.caret
.Position());
1132 const int linesOnScreen
= LinesOnScreen();
1133 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1134 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1135 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1136 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1137 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1139 // It should be possible to scroll the window to show the caret,
1140 // but this fails to remove the caret on GTK+
1141 if (bSlop
) { // A margin is defined
1144 int yMarginT
, yMarginB
;
1145 if (!(options
& xysUseMargin
)) {
1146 // In drag mode, avoid moves
1147 // otherwise, a double click will select several lines.
1148 yMarginT
= yMarginB
= 0;
1150 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1151 // a maximum of slightly less than half the heigth of the text area.
1152 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1154 yMarginB
= yMarginT
;
1156 yMarginB
= linesOnScreen
- yMarginT
- 1;
1162 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1166 yMoveB
= linesOnScreen
- yMoveT
- 1;
1168 if (lineCaret
< topLine
+ yMarginT
) {
1169 // Caret goes too high
1170 newXY
.topLine
= lineCaret
- yMoveT
;
1171 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1172 // Caret goes too low
1173 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1175 } else { // Not strict
1176 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1177 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1181 yMoveB
= linesOnScreen
- yMoveT
- 1;
1183 if (lineCaret
< topLine
) {
1184 // Caret goes too high
1185 newXY
.topLine
= lineCaret
- yMoveT
;
1186 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1187 // Caret goes too low
1188 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1192 if (!bStrict
&& !bJump
) {
1194 if (lineCaret
< topLine
) {
1195 // Caret goes too high
1196 newXY
.topLine
= lineCaret
;
1197 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1198 // Caret goes too low
1200 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1202 newXY
.topLine
= lineCaret
;
1205 } else { // Strict or going out of display
1207 // Always center caret
1208 newXY
.topLine
= lineCaret
- halfScreen
;
1210 // Always put caret on top of display
1211 newXY
.topLine
= lineCaret
;
1215 if (!(range
.caret
== range
.anchor
)) {
1216 const int lineAnchor
= DisplayFromPosition(range
.anchor
.Position());
1217 if (lineAnchor
< lineCaret
) {
1218 // Shift up to show anchor or as much of range as possible
1219 newXY
.topLine
= std::min(newXY
.topLine
, lineAnchor
);
1220 newXY
.topLine
= std::max(newXY
.topLine
, lineCaret
- LinesOnScreen());
1222 // Shift down to show anchor or as much of range as possible
1223 newXY
.topLine
= std::max(newXY
.topLine
, lineAnchor
- LinesOnScreen());
1224 newXY
.topLine
= std::min(newXY
.topLine
, lineCaret
);
1227 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1230 // Horizontal positioning
1231 if ((options
& xysHorizontal
) && !Wrapping()) {
1232 const int halfScreen
= Platform::Maximum(static_cast<int>(rcClient
.Width()) - 4, 4) / 2;
1233 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1234 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1235 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1236 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1238 if (bSlop
) { // A margin is defined
1241 int xMarginL
, xMarginR
;
1242 if (!(options
& xysUseMargin
)) {
1243 // In drag mode, avoid moves unless very near of the margin
1244 // otherwise, a simple click will select text.
1245 xMarginL
= xMarginR
= 2;
1247 // xMargin must equal to caretXSlop, with a minimum of 2 and
1248 // a maximum of slightly less than half the width of the text area.
1249 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1251 xMarginL
= xMarginR
;
1253 xMarginL
= static_cast<int>(rcClient
.Width()) - xMarginR
- 4;
1256 if (bJump
&& bEven
) {
1257 // Jump is used only in even mode
1258 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1260 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1262 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1263 // Caret is on the left of the display
1264 if (bJump
&& bEven
) {
1265 newXY
.xOffset
-= xMoveL
;
1267 // Move just enough to allow to display the caret
1268 newXY
.xOffset
-= static_cast<int>((rcClient
.left
+ xMarginL
) - pt
.x
);
1270 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1271 // Caret is on the right of the display
1272 if (bJump
&& bEven
) {
1273 newXY
.xOffset
+= xMoveR
;
1275 // Move just enough to allow to display the caret
1276 newXY
.xOffset
+= static_cast<int>(pt
.x
- (rcClient
.right
- xMarginR
) + 1);
1279 } else { // Not strict
1280 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1281 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1285 xMoveL
= static_cast<int>(rcClient
.Width()) - xMoveR
- 4;
1287 if (pt
.x
< rcClient
.left
) {
1288 // Caret is on the left of the display
1289 newXY
.xOffset
-= xMoveL
;
1290 } else if (pt
.x
>= rcClient
.right
) {
1291 // Caret is on the right of the display
1292 newXY
.xOffset
+= xMoveR
;
1297 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1298 // Strict or going out of display
1301 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.left
- halfScreen
);
1303 // Put caret on right
1304 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
+ 1);
1307 // Move just enough to allow to display the caret
1308 if (pt
.x
< rcClient
.left
) {
1309 // Caret is on the left of the display
1311 newXY
.xOffset
-= static_cast<int>(rcClient
.left
- pt
.x
);
1313 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1315 } else if (pt
.x
>= rcClient
.right
) {
1316 // Caret is on the right of the display
1317 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1321 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1322 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1323 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 2;
1324 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1325 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 2;
1326 if ((vs
.caretStyle
== CARETSTYLE_BLOCK
) || view
.imeCaretBlockOverride
) {
1327 // Ensure we can see a good portion of the block caret
1328 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1331 if (!(range
.caret
== range
.anchor
)) {
1332 if (ptAnchor
.x
< pt
.x
) {
1333 // Shift to left to show anchor or as much of range as possible
1334 int maxOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.left
) - 1;
1335 int minOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 1;
1336 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1337 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1339 // Shift to right to show anchor or as much of range as possible
1340 int minOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.right
) + 1;
1341 int maxOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 1;
1342 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1343 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1346 if (newXY
.xOffset
< 0) {
1354 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1355 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1356 if (newXY
.topLine
!= topLine
) {
1357 SetTopLine(newXY
.topLine
);
1358 SetVerticalScrollPos();
1360 if (newXY
.xOffset
!= xOffset
) {
1361 xOffset
= newXY
.xOffset
;
1362 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1363 if (newXY
.xOffset
> 0) {
1364 PRectangle rcText
= GetTextRectangle();
1365 if (horizontalScrollBarVisible
&&
1366 rcText
.Width() + xOffset
> scrollWidth
) {
1367 scrollWidth
= xOffset
+ static_cast<int>(rcText
.Width());
1371 SetHorizontalScrollPos();
1374 UpdateSystemCaret();
1378 void Editor::ScrollRange(SelectionRange range
) {
1379 SetXYScroll(XYScrollToMakeVisible(range
, xysDefault
));
1382 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1383 SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
),
1384 static_cast<XYScrollOptions
>((useMargin
?xysUseMargin
:0)|(vert
?xysVertical
:0)|(horiz
?xysHorizontal
:0))));
1387 void Editor::ShowCaretAtCurrentPosition() {
1389 caret
.active
= true;
1391 if (FineTickerAvailable()) {
1392 FineTickerCancel(tickCaret
);
1393 if (caret
.period
> 0)
1394 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1399 caret
.active
= false;
1401 if (FineTickerAvailable()) {
1402 FineTickerCancel(tickCaret
);
1408 void Editor::DropCaret() {
1409 caret
.active
= false;
1410 if (FineTickerAvailable()) {
1411 FineTickerCancel(tickCaret
);
1416 void Editor::CaretSetPeriod(int period
) {
1417 if (caret
.period
!= period
) {
1418 caret
.period
= period
;
1420 if (FineTickerAvailable()) {
1421 FineTickerCancel(tickCaret
);
1422 if ((caret
.active
) && (caret
.period
> 0))
1423 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1429 void Editor::InvalidateCaret() {
1430 if (posDrag
.IsValid()) {
1431 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1433 for (size_t r
=0; r
<sel
.Count(); r
++) {
1434 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1437 UpdateSystemCaret();
1440 void Editor::UpdateSystemCaret() {
1443 bool Editor::Wrapping() const {
1444 return vs
.wrapState
!= eWrapNone
;
1447 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1448 //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd);
1449 if (wrapPending
.AddRange(docLineStart
, docLineEnd
)) {
1450 view
.llc
.Invalidate(LineLayout::llPositions
);
1452 // Wrap lines during idle.
1453 if (Wrapping() && wrapPending
.NeedsWrap()) {
1458 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1459 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(lineToWrap
, *this));
1460 int linesWrapped
= 1;
1462 view
.LayoutLine(*this, lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1463 linesWrapped
= ll
->lines
;
1465 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1466 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1469 // Perform wrapping for a subset of the lines needing wrapping.
1470 // wsAll: wrap all lines which need wrapping in this single call
1471 // wsVisible: wrap currently visible lines
1472 // wsIdle: wrap one page + 100 lines
1473 // Return true if wrapping occurred.
1474 bool Editor::WrapLines(enum wrapScope ws
) {
1475 int goodTopLine
= topLine
;
1476 bool wrapOccurred
= false;
1478 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1479 wrapWidth
= LineLayout::wrapWidthInfinite
;
1480 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1481 cs
.SetHeight(lineDoc
, 1 +
1482 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1484 wrapOccurred
= true;
1486 wrapPending
.Reset();
1488 } else if (wrapPending
.NeedsWrap()) {
1489 wrapPending
.start
= std::min(wrapPending
.start
, pdoc
->LinesTotal());
1490 if (!SetIdle(true)) {
1491 // Idle processing not supported so full wrap required.
1494 // Decide where to start wrapping
1495 int lineToWrap
= wrapPending
.start
;
1496 int lineToWrapEnd
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1497 const int lineDocTop
= cs
.DocFromDisplay(topLine
);
1498 const int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1499 if (ws
== wsVisible
) {
1500 lineToWrap
= Platform::Clamp(lineDocTop
-5, wrapPending
.start
, pdoc
->LinesTotal());
1501 // Priority wrap to just after visible area.
1502 // Since wrapping could reduce display lines, treat each
1503 // as taking only one display line.
1504 lineToWrapEnd
= lineDocTop
;
1505 int lines
= LinesOnScreen() + 1;
1506 while ((lineToWrapEnd
< cs
.LinesInDoc()) && (lines
>0)) {
1507 if (cs
.GetVisible(lineToWrapEnd
))
1511 // .. and if the paint window is outside pending wraps
1512 if ((lineToWrap
> wrapPending
.end
) || (lineToWrapEnd
< wrapPending
.start
)) {
1513 // Currently visible text does not need wrapping
1516 } else if (ws
== wsIdle
) {
1517 lineToWrapEnd
= lineToWrap
+ LinesOnScreen() + 100;
1519 const int lineEndNeedWrap
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1520 lineToWrapEnd
= std::min(lineToWrapEnd
, lineEndNeedWrap
);
1522 // Ensure all lines being wrapped are styled.
1523 pdoc
->EnsureStyledTo(pdoc
->LineStart(lineToWrapEnd
));
1525 if (lineToWrap
< lineToWrapEnd
) {
1527 PRectangle rcTextArea
= GetClientRectangle();
1528 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1529 rcTextArea
.right
-= vs
.rightMarginWidth
;
1530 wrapWidth
= static_cast<int>(rcTextArea
.Width());
1532 AutoSurface
surface(this);
1534 //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd);
1536 while (lineToWrap
< lineToWrapEnd
) {
1537 if (WrapOneLine(surface
, lineToWrap
)) {
1538 wrapOccurred
= true;
1540 wrapPending
.Wrapped(lineToWrap
);
1544 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
) + std::min(subLineTop
, cs
.GetHeight(lineDocTop
)-1);
1548 // If wrapping is done, bring it to resting position
1549 if (wrapPending
.start
>= lineEndNeedWrap
) {
1550 wrapPending
.Reset();
1556 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1557 SetVerticalScrollPos();
1560 return wrapOccurred
;
1563 void Editor::LinesJoin() {
1564 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1566 bool prevNonWS
= true;
1567 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1568 if (pdoc
->IsPositionInLineEnd(pos
)) {
1569 targetEnd
-= pdoc
->LenChar(pos
);
1572 // Ensure at least one space separating previous lines
1573 const int lengthInserted
= pdoc
->InsertString(pos
, " ", 1);
1574 targetEnd
+= lengthInserted
;
1577 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1583 const char *Editor::StringFromEOLMode(int eolMode
) {
1584 if (eolMode
== SC_EOL_CRLF
) {
1586 } else if (eolMode
== SC_EOL_CR
) {
1593 void Editor::LinesSplit(int pixelWidth
) {
1594 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1595 if (pixelWidth
== 0) {
1596 PRectangle rcText
= GetTextRectangle();
1597 pixelWidth
= static_cast<int>(rcText
.Width());
1599 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1600 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1601 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1603 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1604 AutoSurface
surface(this);
1605 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
1606 if (surface
&& ll
) {
1607 unsigned int posLineStart
= pdoc
->LineStart(line
);
1608 view
.LayoutLine(*this, line
, surface
, vs
, ll
, pixelWidth
);
1609 int lengthInsertedTotal
= 0;
1610 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1611 const int lengthInserted
= pdoc
->InsertString(
1612 static_cast<int>(posLineStart
+ lengthInsertedTotal
+
1613 ll
->LineStart(subLine
)),
1615 targetEnd
+= lengthInserted
;
1616 lengthInsertedTotal
+= lengthInserted
;
1619 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1624 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1625 if (vs
.fixedColumnWidth
== 0)
1630 RefreshPixMaps(surfWindow
);
1632 // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished
1633 // at this point. The Initialised call checks for this case and sets the status
1634 // to be bad which avoids crashes in following calls.
1635 if (!surfWindow
->Initialised()) {
1639 PRectangle rcMargin
= GetClientRectangle();
1640 Point ptOrigin
= GetVisibleOriginInMain();
1641 rcMargin
.Move(0, -ptOrigin
.y
);
1643 rcMargin
.right
= static_cast<XYPOSITION
>(vs
.fixedColumnWidth
);
1645 if (!rc
.Intersects(rcMargin
))
1649 if (view
.bufferedDraw
) {
1650 surface
= marginView
.pixmapSelMargin
;
1652 surface
= surfWindow
;
1655 // Clip vertically to paint area to avoid drawing line numbers
1656 if (rcMargin
.bottom
> rc
.bottom
)
1657 rcMargin
.bottom
= rc
.bottom
;
1658 if (rcMargin
.top
< rc
.top
)
1659 rcMargin
.top
= rc
.top
;
1661 marginView
.PaintMargin(surface
, topLine
, rc
, rcMargin
, *this, vs
);
1663 if (view
.bufferedDraw
) {
1664 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *marginView
.pixmapSelMargin
);
1668 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
1669 view
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1670 marginView
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1671 if (view
.bufferedDraw
) {
1672 PRectangle rcClient
= GetClientRectangle();
1673 if (!view
.pixmapLine
->Initialised()) {
1675 view
.pixmapLine
->InitPixMap(static_cast<int>(rcClient
.Width()), vs
.lineHeight
,
1676 surfaceWindow
, wMain
.GetID());
1678 if (!marginView
.pixmapSelMargin
->Initialised()) {
1679 marginView
.pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1680 static_cast<int>(rcClient
.Height()), surfaceWindow
, wMain
.GetID());
1685 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1686 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1687 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1691 if (paintState
== paintAbandoned
)
1692 return; // Scroll bars may have changed so need redraw
1693 RefreshPixMaps(surfaceWindow
);
1695 paintAbandonedByStyling
= false;
1697 StyleAreaBounded(rcArea
, false);
1699 PRectangle rcClient
= GetClientRectangle();
1700 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1701 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1703 if (NotifyUpdateUI()) {
1705 RefreshPixMaps(surfaceWindow
);
1708 // Wrap the visible lines if needed.
1709 if (WrapLines(wsVisible
)) {
1710 // The wrapping process has changed the height of some lines so
1711 // abandon this paint for a complete repaint.
1712 if (AbandonPaint()) {
1715 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
1717 PLATFORM_ASSERT(marginView
.pixmapSelPattern
->Initialised());
1719 if (!view
.bufferedDraw
)
1720 surfaceWindow
->SetClip(rcArea
);
1722 if (paintState
!= paintAbandoned
) {
1723 if (vs
.marginInside
) {
1724 PaintSelMargin(surfaceWindow
, rcArea
);
1725 PRectangle rcRightMargin
= rcClient
;
1726 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1727 if (rcArea
.Intersects(rcRightMargin
)) {
1728 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1730 } else { // Else separate view so separate paint event but leftMargin included to allow overlap
1731 PRectangle rcLeftMargin
= rcArea
;
1732 rcLeftMargin
.left
= 0;
1733 rcLeftMargin
.right
= rcLeftMargin
.left
+ vs
.leftMarginWidth
;
1734 if (rcArea
.Intersects(rcLeftMargin
)) {
1735 surfaceWindow
->FillRectangle(rcLeftMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1740 if (paintState
== paintAbandoned
) {
1741 // Either styling or NotifyUpdateUI noticed that painting is needed
1742 // outside the current painting rectangle
1743 //Platform::DebugPrintf("Abandoning paint\n");
1745 if (paintAbandonedByStyling
) {
1746 // Styling has spilled over a line end, such as occurs by starting a multiline
1747 // comment. The width of subsequent text may have changed, so rewrap.
1748 NeedWrapping(cs
.DocFromDisplay(topLine
));
1754 view
.PaintText(surfaceWindow
, *this, rcArea
, rcClient
, vs
);
1756 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
1757 if (FineTickerAvailable()) {
1758 scrollWidth
= view
.lineWidthMaxSeen
;
1759 if (!FineTickerRunning(tickWiden
)) {
1760 FineTickerStart(tickWiden
, 50, 5);
1768 // This is mostly copied from the Paint method but with some things omitted
1769 // such as the margin markers, line numbers, selection and caret
1770 // Should be merged back into a combined Draw method.
1771 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
1775 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
1778 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
1779 if (!surfaceMeasure
) {
1782 return view
.FormatRange(draw
, pfr
, surface
, surfaceMeasure
, *this, vs
);
1785 int Editor::TextWidth(int style
, const char *text
) {
1787 AutoSurface
surface(this);
1789 return static_cast<int>(surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
)));
1795 // Empty method is overridden on GTK+ to show / hide scrollbars
1796 void Editor::ReconfigureScrollBars() {}
1798 void Editor::SetScrollBars() {
1801 int nMax
= MaxScrollPos();
1802 int nPage
= LinesOnScreen();
1803 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
1808 // TODO: ensure always showing as many lines as possible
1809 // May not be, if, for example, window made larger
1810 if (topLine
> MaxScrollPos()) {
1811 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1812 SetVerticalScrollPos();
1816 if (!AbandonPaint())
1819 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1822 void Editor::ChangeSize() {
1823 DropGraphics(false);
1826 PRectangle rcTextArea
= GetClientRectangle();
1827 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1828 rcTextArea
.right
-= vs
.rightMarginWidth
;
1829 if (wrapWidth
!= rcTextArea
.Width()) {
1836 int Editor::InsertSpace(int position
, unsigned int spaces
) {
1838 std::string
spaceText(spaces
, ' ');
1839 const int lengthInserted
= pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
1840 position
+= lengthInserted
;
1845 void Editor::AddChar(char ch
) {
1852 void Editor::FilterSelections() {
1853 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
1854 InvalidateWholeSelection();
1855 sel
.DropAdditionalRanges();
1859 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
1863 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
1864 void Editor::AddCharUTF(const char *s
, unsigned int len
, bool treatAsDBCS
) {
1867 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1869 // Vector elements point into selection in order to change selection.
1870 std::vector
<SelectionRange
*> selPtrs
;
1871 for (size_t r
= 0; r
< sel
.Count(); r
++) {
1872 selPtrs
.push_back(&sel
.Range(r
));
1874 // Order selections by position in document.
1875 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
1877 // Loop in reverse to avoid disturbing positions of selections yet to be processed.
1878 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
1879 rit
!= selPtrs
.rend(); ++rit
) {
1880 SelectionRange
*currentSel
= *rit
;
1881 if (!RangeContainsProtected(currentSel
->Start().Position(),
1882 currentSel
->End().Position())) {
1883 int positionInsert
= currentSel
->Start().Position();
1884 if (!currentSel
->Empty()) {
1885 if (currentSel
->Length()) {
1886 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
1887 currentSel
->ClearVirtualSpace();
1889 // Range is all virtual so collapse to start of virtual space
1890 currentSel
->MinimizeVirtualSpace();
1892 } else if (inOverstrike
) {
1893 if (positionInsert
< pdoc
->Length()) {
1894 if (!pdoc
->IsPositionInLineEnd(positionInsert
)) {
1895 pdoc
->DelChar(positionInsert
);
1896 currentSel
->ClearVirtualSpace();
1900 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
1901 const int lengthInserted
= pdoc
->InsertString(positionInsert
, s
, len
);
1902 if (lengthInserted
> 0) {
1903 currentSel
->caret
.SetPosition(positionInsert
+ lengthInserted
);
1904 currentSel
->anchor
.SetPosition(positionInsert
+ lengthInserted
);
1906 currentSel
->ClearVirtualSpace();
1907 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1909 AutoSurface
surface(this);
1911 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
1913 SetVerticalScrollPos();
1924 ThinRectangularRange();
1925 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1926 EnsureCaretVisible();
1927 // Avoid blinking during rapid typing:
1928 ShowCaretAtCurrentPosition();
1929 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
1930 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
1935 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
1936 static_cast<unsigned char>(s
[1]));
1937 } else if (len
> 0) {
1938 int byte
= static_cast<unsigned char>(s
[0]);
1939 if ((byte
< 0xC0) || (1 == len
)) {
1940 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1941 // characters when not in UTF-8 mode.
1942 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1943 // characters representing themselves.
1945 unsigned int utf32
[1] = { 0 };
1946 UTF32FromUTF8(s
, len
, utf32
, ELEMENTS(utf32
));
1952 if (recordingMacro
) {
1953 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
1957 void Editor::ClearBeforeTentativeStart() {
1958 // Make positions for the first composition string.
1960 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1961 for (size_t r
= 0; r
<sel
.Count(); r
++) {
1962 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1963 sel
.Range(r
).End().Position())) {
1964 int positionInsert
= sel
.Range(r
).Start().Position();
1965 if (!sel
.Range(r
).Empty()) {
1966 if (sel
.Range(r
).Length()) {
1967 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1968 sel
.Range(r
).ClearVirtualSpace();
1970 // Range is all virtual so collapse to start of virtual space
1971 sel
.Range(r
).MinimizeVirtualSpace();
1974 InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
1975 sel
.Range(r
).ClearVirtualSpace();
1980 void Editor::InsertPaste(const char *text
, int len
) {
1981 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
1982 SelectionPosition selStart
= sel
.Start();
1983 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
1984 const int lengthInserted
= pdoc
->InsertString(selStart
.Position(), text
, len
);
1985 if (lengthInserted
> 0) {
1986 SetEmptySelection(selStart
.Position() + lengthInserted
);
1989 // SC_MULTIPASTE_EACH
1990 for (size_t r
=0; r
<sel
.Count(); r
++) {
1991 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1992 sel
.Range(r
).End().Position())) {
1993 int positionInsert
= sel
.Range(r
).Start().Position();
1994 if (!sel
.Range(r
).Empty()) {
1995 if (sel
.Range(r
).Length()) {
1996 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1997 sel
.Range(r
).ClearVirtualSpace();
1999 // Range is all virtual so collapse to start of virtual space
2000 sel
.Range(r
).MinimizeVirtualSpace();
2003 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
2004 const int lengthInserted
= pdoc
->InsertString(positionInsert
, text
, len
);
2005 if (lengthInserted
> 0) {
2006 sel
.Range(r
).caret
.SetPosition(positionInsert
+ lengthInserted
);
2007 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ lengthInserted
);
2009 sel
.Range(r
).ClearVirtualSpace();
2015 void Editor::InsertPasteShape(const char *text
, int len
, PasteShape shape
) {
2016 std::string convertedText
;
2017 if (convertPastes
) {
2018 // Convert line endings of the paste into our local line-endings mode
2019 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
2020 len
= static_cast<int>(convertedText
.length());
2021 text
= convertedText
.c_str();
2023 if (shape
== pasteRectangular
) {
2024 PasteRectangular(sel
.Start(), text
, len
);
2026 if (shape
== pasteLine
) {
2027 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
2028 int lengthInserted
= pdoc
->InsertString(insertPos
, text
, len
);
2029 // add the newline if necessary
2030 if ((len
> 0) && (text
[len
- 1] != '\n' && text
[len
- 1] != '\r')) {
2031 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
2032 int length
= static_cast<int>(strlen(endline
));
2033 lengthInserted
+= pdoc
->InsertString(insertPos
+ lengthInserted
, endline
, length
);
2035 if (sel
.MainCaret() == insertPos
) {
2036 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
2039 InsertPaste(text
, len
);
2044 void Editor::ClearSelection(bool retainMultipleSelections
) {
2045 if (!sel
.IsRectangular() && !retainMultipleSelections
)
2048 for (size_t r
=0; r
<sel
.Count(); r
++) {
2049 if (!sel
.Range(r
).Empty()) {
2050 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
2051 sel
.Range(r
).End().Position())) {
2052 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
2053 sel
.Range(r
).Length());
2054 sel
.Range(r
) = SelectionRange(sel
.Range(r
).Start());
2058 ThinRectangularRange();
2059 sel
.RemoveDuplicates();
2061 SetHoverIndicatorPosition(sel
.MainCaret());
2064 void Editor::ClearAll() {
2067 if (0 != pdoc
->Length()) {
2068 pdoc
->DeleteChars(0, pdoc
->Length());
2070 if (!pdoc
->IsReadOnly()) {
2072 pdoc
->AnnotationClearAll();
2073 pdoc
->MarginClearAll();
2077 view
.ClearAllTabstops();
2081 SetVerticalScrollPos();
2082 InvalidateStyleRedraw();
2085 void Editor::ClearDocumentStyle() {
2086 Decoration
*deco
= pdoc
->decorations
.root
;
2088 // Save next in case deco deleted
2089 Decoration
*decoNext
= deco
->next
;
2090 if (deco
->indicator
< INDIC_CONTAINER
) {
2091 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
2092 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
2096 pdoc
->StartStyling(0, '\377');
2097 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2099 SetAnnotationHeights(0, pdoc
->LinesTotal());
2100 pdoc
->ClearLevels();
2103 void Editor::CopyAllowLine() {
2104 SelectionText selectedText
;
2105 CopySelectionRange(&selectedText
, true);
2106 CopyToClipboard(selectedText
);
2109 void Editor::Cut() {
2110 pdoc
->CheckReadOnly();
2111 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2117 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
2118 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2122 sel
.RangeMain() = SelectionRange(pos
);
2123 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2125 sel
.RangeMain().caret
= SelectionPosition(
2126 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
2127 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
2128 bool prevCr
= false;
2129 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
2131 for (int i
= 0; i
< len
; i
++) {
2132 if (IsEOLChar(ptr
[i
])) {
2133 if ((ptr
[i
] == '\r') || (!prevCr
))
2135 if (line
>= pdoc
->LinesTotal()) {
2136 if (pdoc
->eolMode
!= SC_EOL_LF
)
2137 pdoc
->InsertString(pdoc
->Length(), "\r", 1);
2138 if (pdoc
->eolMode
!= SC_EOL_CR
)
2139 pdoc
->InsertString(pdoc
->Length(), "\n", 1);
2141 // Pad the end of lines with spaces if required
2142 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
2143 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
2144 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
2146 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), " ", 1);
2147 sel
.RangeMain().caret
.Add(lengthInserted
);
2150 prevCr
= ptr
[i
] == '\r';
2152 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
2153 sel
.RangeMain().caret
.Add(lengthInserted
);
2157 SetEmptySelection(pos
);
2160 bool Editor::CanPaste() {
2161 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
2164 void Editor::Clear() {
2165 // If multiple selections, don't delete EOLS
2167 bool singleVirtual
= false;
2168 if ((sel
.Count() == 1) &&
2169 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
2170 sel
.RangeMain().Start().VirtualSpace()) {
2171 singleVirtual
= true;
2173 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
2174 for (size_t r
=0; r
<sel
.Count(); r
++) {
2175 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
2176 if (sel
.Range(r
).Start().VirtualSpace()) {
2177 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
2178 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
2180 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
2182 if ((sel
.Count() == 1) || !pdoc
->IsPositionInLineEnd(sel
.Range(r
).caret
.Position())) {
2183 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
2184 sel
.Range(r
).ClearVirtualSpace();
2185 } // else multiple selection so don't eat line ends
2187 sel
.Range(r
).ClearVirtualSpace();
2193 sel
.RemoveDuplicates();
2194 ShowCaretAtCurrentPosition(); // Avoid blinking
2197 void Editor::SelectAll() {
2199 SetSelection(0, pdoc
->Length());
2203 void Editor::Undo() {
2204 if (pdoc
->CanUndo()) {
2206 int newPos
= pdoc
->Undo();
2208 SetEmptySelection(newPos
);
2209 EnsureCaretVisible();
2213 void Editor::Redo() {
2214 if (pdoc
->CanRedo()) {
2215 int newPos
= pdoc
->Redo();
2217 SetEmptySelection(newPos
);
2218 EnsureCaretVisible();
2222 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2224 if (!sel
.IsRectangular())
2226 if (sel
.IsRectangular())
2227 allowLineStartDeletion
= false;
2228 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
2230 for (size_t r
=0; r
<sel
.Count(); r
++) {
2231 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
2232 if (sel
.Range(r
).caret
.VirtualSpace()) {
2233 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
2234 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
2236 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2237 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
2238 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2239 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
2240 UndoGroup
ugInner(pdoc
, !ug
.Needed());
2241 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2242 int indentationStep
= pdoc
->IndentSize();
2243 int indentationChange
= indentation
% indentationStep
;
2244 if (indentationChange
== 0)
2245 indentationChange
= indentationStep
;
2246 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationChange
);
2247 // SetEmptySelection
2248 sel
.Range(r
) = SelectionRange(posSelect
);
2250 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
2255 sel
.Range(r
).ClearVirtualSpace();
2258 ThinRectangularRange();
2262 sel
.RemoveDuplicates();
2263 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
2264 // Avoid blinking during rapid typing:
2265 ShowCaretAtCurrentPosition();
2268 int Editor::ModifierFlags(bool shift
, bool ctrl
, bool alt
, bool meta
) {
2270 (shift
? SCI_SHIFT
: 0) |
2271 (ctrl
? SCI_CTRL
: 0) |
2272 (alt
? SCI_ALT
: 0) |
2273 (meta
? SCI_META
: 0);
2276 void Editor::NotifyFocus(bool focus
) {
2277 SCNotification scn
= {};
2278 scn
.nmhdr
.code
= focus
? SCN_FOCUSIN
: SCN_FOCUSOUT
;
2282 void Editor::SetCtrlID(int identifier
) {
2283 ctrlID
= identifier
;
2286 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2287 SCNotification scn
= {};
2288 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2289 scn
.position
= endStyleNeeded
;
2293 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2294 NotifyStyleToNeeded(endStyleNeeded
);
2297 void Editor::NotifyLexerChanged(Document
*, void *) {
2300 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
2301 errorStatus
= status
;
2304 void Editor::NotifyChar(int ch
) {
2305 SCNotification scn
= {};
2306 scn
.nmhdr
.code
= SCN_CHARADDED
;
2311 void Editor::NotifySavePoint(bool isSavePoint
) {
2312 SCNotification scn
= {};
2314 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2316 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2321 void Editor::NotifyModifyAttempt() {
2322 SCNotification scn
= {};
2323 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2327 void Editor::NotifyDoubleClick(Point pt
, int modifiers
) {
2328 SCNotification scn
= {};
2329 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2330 scn
.line
= LineFromLocation(pt
);
2331 scn
.position
= PositionFromLocation(pt
, true);
2332 scn
.modifiers
= modifiers
;
2336 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2337 NotifyDoubleClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2340 void Editor::NotifyHotSpotDoubleClicked(int position
, int modifiers
) {
2341 SCNotification scn
= {};
2342 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
2343 scn
.position
= position
;
2344 scn
.modifiers
= modifiers
;
2348 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2349 NotifyHotSpotDoubleClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2352 void Editor::NotifyHotSpotClicked(int position
, int modifiers
) {
2353 SCNotification scn
= {};
2354 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
2355 scn
.position
= position
;
2356 scn
.modifiers
= modifiers
;
2360 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2361 NotifyHotSpotClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2364 void Editor::NotifyHotSpotReleaseClick(int position
, int modifiers
) {
2365 SCNotification scn
= {};
2366 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
2367 scn
.position
= position
;
2368 scn
.modifiers
= modifiers
;
2372 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
2373 NotifyHotSpotReleaseClick(position
, ModifierFlags(shift
, ctrl
, alt
));
2376 bool Editor::NotifyUpdateUI() {
2378 SCNotification scn
= {};
2379 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2380 scn
.updated
= needUpdateUI
;
2388 void Editor::NotifyPainted() {
2389 SCNotification scn
= {};
2390 scn
.nmhdr
.code
= SCN_PAINTED
;
2394 void Editor::NotifyIndicatorClick(bool click
, int position
, int modifiers
) {
2395 int mask
= pdoc
->decorations
.AllOnFor(position
);
2396 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
2397 SCNotification scn
= {};
2398 pdoc
->decorations
.clickNotified
= click
;
2399 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
2400 scn
.modifiers
= modifiers
;
2401 scn
.position
= position
;
2406 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
2407 NotifyIndicatorClick(click
, position
, ModifierFlags(shift
, ctrl
, alt
));
2410 bool Editor::NotifyMarginClick(Point pt
, int modifiers
) {
2411 int marginClicked
= -1;
2412 int x
= vs
.textStart
- vs
.fixedColumnWidth
;
2413 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
2414 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2415 marginClicked
= margin
;
2416 x
+= vs
.ms
[margin
].width
;
2418 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2419 int position
= pdoc
->LineStart(LineFromLocation(pt
));
2420 if ((vs
.ms
[marginClicked
].mask
& SC_MASK_FOLDERS
) && (foldAutomatic
& SC_AUTOMATICFOLD_CLICK
)) {
2421 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
2422 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
2423 int lineClick
= pdoc
->LineFromPosition(position
);
2424 if (shift
&& ctrl
) {
2425 FoldAll(SC_FOLDACTION_TOGGLE
);
2427 int levelClick
= pdoc
->GetLevel(lineClick
);
2428 if (levelClick
& SC_FOLDLEVELHEADERFLAG
) {
2430 // Ensure all children visible
2431 FoldExpand(lineClick
, SC_FOLDACTION_EXPAND
, levelClick
);
2433 FoldExpand(lineClick
, SC_FOLDACTION_TOGGLE
, levelClick
);
2436 FoldLine(lineClick
, SC_FOLDACTION_TOGGLE
);
2442 SCNotification scn
= {};
2443 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2444 scn
.modifiers
= modifiers
;
2445 scn
.position
= position
;
2446 scn
.margin
= marginClicked
;
2454 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2455 return NotifyMarginClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2458 void Editor::NotifyNeedShown(int pos
, int len
) {
2459 SCNotification scn
= {};
2460 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2466 void Editor::NotifyDwelling(Point pt
, bool state
) {
2467 SCNotification scn
= {};
2468 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2469 scn
.position
= PositionFromLocation(pt
, true);
2470 scn
.x
= static_cast<int>(pt
.x
+ vs
.ExternalMarginWidth());
2471 scn
.y
= static_cast<int>(pt
.y
);
2475 void Editor::NotifyZoom() {
2476 SCNotification scn
= {};
2477 scn
.nmhdr
.code
= SCN_ZOOM
;
2481 // Notifications from document
2482 void Editor::NotifyModifyAttempt(Document
*, void *) {
2483 //Platform::DebugPrintf("** Modify Attempt\n");
2484 NotifyModifyAttempt();
2487 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2488 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2489 NotifySavePoint(atSavePoint
);
2492 void Editor::CheckModificationForWrap(DocModification mh
) {
2493 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
2494 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2495 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2496 int lines
= Platform::Maximum(0, mh
.linesAdded
);
2498 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
2501 // Fix up annotation heights
2502 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
2506 // Move a position so it is still after the same character as before the insertion.
2507 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2508 if (position
> startInsertion
) {
2509 return position
+ length
;
2514 // Move a position so it is still after the same character as before the deletion if that
2515 // character is still present else after the previous surviving character.
2516 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2517 if (position
> startDeletion
) {
2518 int endDeletion
= startDeletion
+ length
;
2519 if (position
> endDeletion
) {
2520 return position
- length
;
2522 return startDeletion
;
2529 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2530 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
2531 if (paintState
== painting
) {
2532 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2534 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
2535 if (paintState
== painting
) {
2536 CheckForChangeOutsidePaint(
2537 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
2539 // Could check that change is before last visible line.
2543 if (mh
.modificationType
& SC_MOD_CHANGETABSTOPS
) {
2546 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
2547 if (paintState
== painting
) {
2548 CheckForChangeOutsidePaint(
2549 Range(mh
.position
, mh
.position
+ mh
.length
));
2554 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
2555 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2556 pdoc
->IncrementStyleClock();
2558 if (paintState
== notPainting
) {
2559 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2560 // Styling performed before this view
2563 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2566 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2567 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2570 // Move selection and brace highlights
2571 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2572 sel
.MovePositions(true, mh
.position
, mh
.length
);
2573 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2574 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2575 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2576 sel
.MovePositions(false, mh
.position
, mh
.length
);
2577 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2578 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2580 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
2581 // Some lines are hidden so may need shown.
2582 const int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2583 int endNeedShown
= mh
.position
;
2584 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2585 if (pdoc
->ContainsLineEnd(mh
.text
, mh
.length
) && (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
2586 endNeedShown
= pdoc
->LineStart(lineOfPos
+1);
2587 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2588 // Extend the need shown area over any folded lines
2589 endNeedShown
= mh
.position
+ mh
.length
;
2590 int lineLast
= pdoc
->LineFromPosition(mh
.position
+mh
.length
);
2591 for (int line
= lineOfPos
; line
<= lineLast
; line
++) {
2592 const int lineMaxSubord
= pdoc
->GetLastChild(line
, -1, -1);
2593 if (lineLast
< lineMaxSubord
) {
2594 lineLast
= lineMaxSubord
;
2595 endNeedShown
= pdoc
->LineEnd(lineLast
);
2599 NeedShown(mh
.position
, endNeedShown
- mh
.position
);
2601 if (mh
.linesAdded
!= 0) {
2602 // Update contraction state for inserted and removed lines
2603 // lineOfPos should be calculated in context of state before modification, shouldn't it
2604 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2605 if (mh
.position
> pdoc
->LineStart(lineOfPos
))
2606 lineOfPos
++; // Affecting subsequent lines
2607 if (mh
.linesAdded
> 0) {
2608 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2610 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2612 view
.LinesAddedOrRemoved(lineOfPos
, mh
.linesAdded
);
2614 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
2615 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2616 if (vs
.annotationVisible
) {
2617 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
2621 CheckModificationForWrap(mh
);
2622 if (mh
.linesAdded
!= 0) {
2623 // Avoid scrolling of display if change before current display
2624 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
2625 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2626 if (newTop
!= topLine
) {
2628 SetVerticalScrollPos();
2632 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
2633 QueueIdleWork(WorkNeeded::workStyle
, pdoc
->Length());
2637 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
2638 QueueIdleWork(WorkNeeded::workStyle
, mh
.position
+ mh
.length
);
2639 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2644 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
2648 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
2649 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
2650 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
2651 // Fold changes can affect the drawing of following lines so redraw whole margin
2652 RedrawSelMargin(marginView
.highlightDelimiter
.isEnabled
? -1 : mh
.line
- 1, true);
2654 RedrawSelMargin(mh
.line
);
2658 if ((mh
.modificationType
& SC_MOD_CHANGEFOLD
) && (foldAutomatic
& SC_AUTOMATICFOLD_CHANGE
)) {
2659 FoldChanged(mh
.line
, mh
.foldLevelNow
, mh
.foldLevelPrev
);
2662 // NOW pay the piper WRT "deferred" visual updates
2663 if (IsLastStep(mh
)) {
2668 // If client wants to see this modification
2669 if (mh
.modificationType
& modEventMask
) {
2670 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
2671 // Real modification made to text of document.
2672 NotifyChange(); // Send EN_CHANGE
2675 SCNotification scn
= {};
2676 scn
.nmhdr
.code
= SCN_MODIFIED
;
2677 scn
.position
= mh
.position
;
2678 scn
.modificationType
= mh
.modificationType
;
2680 scn
.length
= mh
.length
;
2681 scn
.linesAdded
= mh
.linesAdded
;
2683 scn
.foldLevelNow
= mh
.foldLevelNow
;
2684 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2685 scn
.token
= mh
.token
;
2686 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
2691 void Editor::NotifyDeleted(Document
*, void *) {
2695 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2697 // Enumerates all macroable messages
2703 case SCI_REPLACESEL
:
2705 case SCI_INSERTTEXT
:
2706 case SCI_APPENDTEXT
:
2711 case SCI_SEARCHANCHOR
:
2712 case SCI_SEARCHNEXT
:
2713 case SCI_SEARCHPREV
:
2715 case SCI_LINEDOWNEXTEND
:
2717 case SCI_PARADOWNEXTEND
:
2719 case SCI_LINEUPEXTEND
:
2721 case SCI_PARAUPEXTEND
:
2723 case SCI_CHARLEFTEXTEND
:
2725 case SCI_CHARRIGHTEXTEND
:
2727 case SCI_WORDLEFTEXTEND
:
2729 case SCI_WORDRIGHTEXTEND
:
2730 case SCI_WORDPARTLEFT
:
2731 case SCI_WORDPARTLEFTEXTEND
:
2732 case SCI_WORDPARTRIGHT
:
2733 case SCI_WORDPARTRIGHTEXTEND
:
2734 case SCI_WORDLEFTEND
:
2735 case SCI_WORDLEFTENDEXTEND
:
2736 case SCI_WORDRIGHTEND
:
2737 case SCI_WORDRIGHTENDEXTEND
:
2739 case SCI_HOMEEXTEND
:
2741 case SCI_LINEENDEXTEND
:
2743 case SCI_HOMEWRAPEXTEND
:
2744 case SCI_LINEENDWRAP
:
2745 case SCI_LINEENDWRAPEXTEND
:
2746 case SCI_DOCUMENTSTART
:
2747 case SCI_DOCUMENTSTARTEXTEND
:
2748 case SCI_DOCUMENTEND
:
2749 case SCI_DOCUMENTENDEXTEND
:
2750 case SCI_STUTTEREDPAGEUP
:
2751 case SCI_STUTTEREDPAGEUPEXTEND
:
2752 case SCI_STUTTEREDPAGEDOWN
:
2753 case SCI_STUTTEREDPAGEDOWNEXTEND
:
2755 case SCI_PAGEUPEXTEND
:
2757 case SCI_PAGEDOWNEXTEND
:
2758 case SCI_EDITTOGGLEOVERTYPE
:
2760 case SCI_DELETEBACK
:
2765 case SCI_VCHOMEEXTEND
:
2766 case SCI_VCHOMEWRAP
:
2767 case SCI_VCHOMEWRAPEXTEND
:
2768 case SCI_VCHOMEDISPLAY
:
2769 case SCI_VCHOMEDISPLAYEXTEND
:
2770 case SCI_DELWORDLEFT
:
2771 case SCI_DELWORDRIGHT
:
2772 case SCI_DELWORDRIGHTEND
:
2773 case SCI_DELLINELEFT
:
2774 case SCI_DELLINERIGHT
:
2777 case SCI_LINEDELETE
:
2778 case SCI_LINETRANSPOSE
:
2779 case SCI_LINEDUPLICATE
:
2782 case SCI_LINESCROLLDOWN
:
2783 case SCI_LINESCROLLUP
:
2784 case SCI_DELETEBACKNOTLINE
:
2785 case SCI_HOMEDISPLAY
:
2786 case SCI_HOMEDISPLAYEXTEND
:
2787 case SCI_LINEENDDISPLAY
:
2788 case SCI_LINEENDDISPLAYEXTEND
:
2789 case SCI_SETSELECTIONMODE
:
2790 case SCI_LINEDOWNRECTEXTEND
:
2791 case SCI_LINEUPRECTEXTEND
:
2792 case SCI_CHARLEFTRECTEXTEND
:
2793 case SCI_CHARRIGHTRECTEXTEND
:
2794 case SCI_HOMERECTEXTEND
:
2795 case SCI_VCHOMERECTEXTEND
:
2796 case SCI_LINEENDRECTEXTEND
:
2797 case SCI_PAGEUPRECTEXTEND
:
2798 case SCI_PAGEDOWNRECTEXTEND
:
2799 case SCI_SELECTIONDUPLICATE
:
2800 case SCI_COPYALLOWLINE
:
2801 case SCI_VERTICALCENTRECARET
:
2802 case SCI_MOVESELECTEDLINESUP
:
2803 case SCI_MOVESELECTEDLINESDOWN
:
2804 case SCI_SCROLLTOSTART
:
2805 case SCI_SCROLLTOEND
:
2808 // Filter out all others like display changes. Also, newlines are redundant
2809 // with char insert messages.
2812 // printf("Filtered out %ld of macro recording\n", iMessage);
2816 // Send notification
2817 SCNotification scn
= {};
2818 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2819 scn
.message
= iMessage
;
2820 scn
.wParam
= wParam
;
2821 scn
.lParam
= lParam
;
2825 // Something has changed that the container should know about
2826 void Editor::ContainerNeedsUpdate(int flags
) {
2827 needUpdateUI
|= flags
;
2831 * Force scroll and keep position relative to top of window.
2833 * If stuttered = true and not already at first/last row, move to first/last row of window.
2834 * If stuttered = true and already at first/last row, scroll as normal.
2836 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
2838 SelectionPosition newPos
;
2840 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
2841 int topStutterLine
= topLine
+ caretYSlop
;
2842 int bottomStutterLine
=
2843 pdoc
->LineFromPosition(PositionFromLocation(
2844 Point::FromInts(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
2847 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
2848 topLineNew
= topLine
;
2849 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
2850 false, false, UserVirtualSpace());
2852 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
2853 topLineNew
= topLine
;
2854 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
2855 false, false, UserVirtualSpace());
2858 Point pt
= LocationFromPosition(sel
.MainCaret());
2860 topLineNew
= Platform::Clamp(
2861 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2862 newPos
= SPositionFromLocation(
2863 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(pt
.y
) + direction
* (vs
.lineHeight
* LinesToScroll())),
2864 false, false, UserVirtualSpace());
2867 if (topLineNew
!= topLine
) {
2868 SetTopLine(topLineNew
);
2869 MovePositionTo(newPos
, selt
);
2871 SetVerticalScrollPos();
2873 MovePositionTo(newPos
, selt
);
2877 void Editor::ChangeCaseOfSelection(int caseMapping
) {
2879 for (size_t r
=0; r
<sel
.Count(); r
++) {
2880 SelectionRange current
= sel
.Range(r
);
2881 SelectionRange currentNoVS
= current
;
2882 currentNoVS
.ClearVirtualSpace();
2883 size_t rangeBytes
= currentNoVS
.Length();
2884 if (rangeBytes
> 0) {
2885 std::string sText
= RangeText(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
2887 std::string sMapped
= CaseMapString(sText
, caseMapping
);
2889 if (sMapped
!= sText
) {
2890 size_t firstDifference
= 0;
2891 while (sMapped
[firstDifference
] == sText
[firstDifference
])
2893 size_t lastDifferenceText
= sText
.size() - 1;
2894 size_t lastDifferenceMapped
= sMapped
.size() - 1;
2895 while (sMapped
[lastDifferenceMapped
] == sText
[lastDifferenceText
]) {
2896 lastDifferenceText
--;
2897 lastDifferenceMapped
--;
2899 size_t endDifferenceText
= sText
.size() - 1 - lastDifferenceText
;
2901 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2902 static_cast<int>(rangeBytes
- firstDifference
- endDifferenceText
));
2903 const int lengthChange
= static_cast<int>(lastDifferenceMapped
- firstDifference
+ 1);
2904 const int lengthInserted
= pdoc
->InsertString(
2905 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2906 sMapped
.c_str() + firstDifference
,
2908 // Automatic movement changes selection so reset to exactly the same as it was.
2909 int diffSizes
= static_cast<int>(sMapped
.size() - sText
.size()) + lengthInserted
- lengthChange
;
2910 if (diffSizes
!= 0) {
2911 if (current
.anchor
> current
.caret
)
2912 current
.anchor
.Add(diffSizes
);
2914 current
.caret
.Add(diffSizes
);
2916 sel
.Range(r
) = current
;
2922 void Editor::LineTranspose() {
2923 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2927 const int startPrevious
= pdoc
->LineStart(line
- 1);
2928 const std::string linePrevious
= RangeText(startPrevious
, pdoc
->LineEnd(line
- 1));
2930 int startCurrent
= pdoc
->LineStart(line
);
2931 const std::string lineCurrent
= RangeText(startCurrent
, pdoc
->LineEnd(line
));
2933 pdoc
->DeleteChars(startCurrent
, static_cast<int>(lineCurrent
.length()));
2934 pdoc
->DeleteChars(startPrevious
, static_cast<int>(linePrevious
.length()));
2935 startCurrent
-= static_cast<int>(linePrevious
.length());
2937 startCurrent
+= pdoc
->InsertString(startPrevious
, lineCurrent
.c_str(),
2938 static_cast<int>(lineCurrent
.length()));
2939 pdoc
->InsertString(startCurrent
, linePrevious
.c_str(),
2940 static_cast<int>(linePrevious
.length()));
2941 // Move caret to start of current line
2942 MovePositionTo(SelectionPosition(startCurrent
));
2946 void Editor::Duplicate(bool forLine
) {
2951 const char *eol
= "";
2954 eol
= StringFromEOLMode(pdoc
->eolMode
);
2955 eolLen
= istrlen(eol
);
2957 for (size_t r
=0; r
<sel
.Count(); r
++) {
2958 SelectionPosition start
= sel
.Range(r
).Start();
2959 SelectionPosition end
= sel
.Range(r
).End();
2961 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2962 start
= SelectionPosition(pdoc
->LineStart(line
));
2963 end
= SelectionPosition(pdoc
->LineEnd(line
));
2965 std::string text
= RangeText(start
.Position(), end
.Position());
2966 int lengthInserted
= eolLen
;
2968 lengthInserted
= pdoc
->InsertString(end
.Position(), eol
, eolLen
);
2969 pdoc
->InsertString(end
.Position() + lengthInserted
, text
.c_str(), static_cast<int>(text
.length()));
2971 if (sel
.Count() && sel
.IsRectangular()) {
2972 SelectionPosition last
= sel
.Last();
2974 int line
= pdoc
->LineFromPosition(last
.Position());
2975 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
2977 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
2978 sel
.Rectangular().anchor
= last
;
2980 sel
.Rectangular().caret
= last
;
2981 SetRectangularRange();
2985 void Editor::CancelModes() {
2986 sel
.SetMoveExtends(false);
2989 void Editor::NewLine() {
2990 InvalidateWholeSelection();
2991 if (sel
.IsRectangular() || !additionalSelectionTyping
) {
2992 // Remove non-main ranges
2993 sel
.DropAdditionalRanges();
2996 UndoGroup
ug(pdoc
, !sel
.Empty() || (sel
.Count() > 1));
3003 // Insert each line end
3004 size_t countInsertions
= 0;
3005 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3006 sel
.Range(r
).ClearVirtualSpace();
3007 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3008 const int positionInsert
= sel
.Range(r
).caret
.Position();
3009 const int insertLength
= pdoc
->InsertString(positionInsert
, eol
, istrlen(eol
));
3010 if (insertLength
> 0) {
3011 sel
.Range(r
) = SelectionRange(positionInsert
+ insertLength
);
3016 // Perform notifications after all the changes as the application may change the
3017 // selections in response to the characters.
3018 for (size_t i
= 0; i
< countInsertions
; i
++) {
3019 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3022 if (recordingMacro
) {
3026 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3034 EnsureCaretVisible();
3035 // Avoid blinking during rapid typing:
3036 ShowCaretAtCurrentPosition();
3039 SelectionPosition
Editor::PositionUpOrDown(SelectionPosition spStart
, int direction
, int lastX
) {
3040 const Point pt
= LocationFromPosition(spStart
);
3043 if (vs
.annotationVisible
) {
3044 const int lineDoc
= pdoc
->LineFromPosition(spStart
.Position());
3045 const Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
3046 const int subLine
= static_cast<int>(pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
3048 if (direction
< 0 && subLine
== 0) {
3049 const int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
3050 if (lineDisplay
> 0) {
3051 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
3053 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
3054 skipLines
= pdoc
->AnnotationLines(lineDoc
);
3058 const int newY
= static_cast<int>(pt
.y
) + (1 + skipLines
) * direction
* vs
.lineHeight
;
3060 lastX
= static_cast<int>(pt
.x
) + xOffset
;
3062 SelectionPosition posNew
= SPositionFromLocation(
3063 Point::FromInts(lastX
- xOffset
, newY
), false, false, UserVirtualSpace());
3065 if (direction
< 0) {
3066 // Line wrapping may lead to a location on the same line, so
3067 // seek back if that is the case.
3068 Point ptNew
= LocationFromPosition(posNew
.Position());
3069 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
3071 posNew
.SetVirtualSpace(0);
3072 ptNew
= LocationFromPosition(posNew
.Position());
3074 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
3075 // There is an equivalent case when moving down which skips
3077 Point ptNew
= LocationFromPosition(posNew
.Position());
3078 while ((posNew
.Position() > spStart
.Position()) && (ptNew
.y
> newY
)) {
3080 posNew
.SetVirtualSpace(0);
3081 ptNew
= LocationFromPosition(posNew
.Position());
3087 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
3088 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
3089 if (sel
.IsRectangular()) {
3090 if (selt
== Selection::noSel
) {
3091 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
3093 caretToUse
= sel
.Rectangular().caret
;
3096 if (selt
== Selection::selRectangle
) {
3097 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3098 if (!sel
.IsRectangular()) {
3099 InvalidateWholeSelection();
3100 sel
.DropAdditionalRanges();
3102 const SelectionPosition posNew
= MovePositionSoVisible(
3103 PositionUpOrDown(caretToUse
, direction
, lastXChosen
), direction
);
3104 sel
.selType
= Selection::selRectangle
;
3105 sel
.Rectangular() = SelectionRange(posNew
, rangeBase
.anchor
);
3106 SetRectangularRange();
3107 MovedCaret(posNew
, caretToUse
, true);
3109 InvalidateWholeSelection();
3110 if (!additionalSelectionTyping
|| (sel
.IsRectangular())) {
3111 sel
.DropAdditionalRanges();
3113 sel
.selType
= Selection::selStream
;
3114 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3115 const int lastX
= (r
== sel
.Main()) ? lastXChosen
: -1;
3116 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3117 const SelectionPosition posNew
= MovePositionSoVisible(
3118 PositionUpOrDown(spCaretNow
, direction
, lastX
), direction
);
3119 sel
.Range(r
) = selt
== Selection::selStream
?
3120 SelectionRange(posNew
, sel
.Range(r
).anchor
) : SelectionRange(posNew
);
3122 sel
.RemoveDuplicates();
3123 MovedCaret(sel
.RangeMain().caret
, caretToUse
, true);
3127 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
3128 int lineDoc
, savedPos
= sel
.MainCaret();
3130 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
3131 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
3132 if (direction
> 0) {
3133 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
3134 if (selt
== Selection::noSel
) {
3135 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
3140 } while (!cs
.GetVisible(lineDoc
));
3143 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3145 AutoSurface
surface(this);
3146 int posRet
= view
.StartEndDisplayLine(surface
, *this, pos
, start
, vs
);
3147 if (posRet
== INVALID_POSITION
) {
3156 unsigned int WithExtends(unsigned int iMessage
) {
3158 case SCI_CHARLEFT
: return SCI_CHARLEFTEXTEND
;
3159 case SCI_CHARRIGHT
: return SCI_CHARRIGHTEXTEND
;
3161 case SCI_WORDLEFT
: return SCI_WORDLEFTEXTEND
;
3162 case SCI_WORDRIGHT
: return SCI_WORDRIGHTEXTEND
;
3163 case SCI_WORDLEFTEND
: return SCI_WORDLEFTENDEXTEND
;
3164 case SCI_WORDRIGHTEND
: return SCI_WORDRIGHTENDEXTEND
;
3165 case SCI_WORDPARTLEFT
: return SCI_WORDPARTLEFTEXTEND
;
3166 case SCI_WORDPARTRIGHT
: return SCI_WORDPARTRIGHTEXTEND
;
3168 case SCI_HOME
: return SCI_HOMEEXTEND
;
3169 case SCI_HOMEDISPLAY
: return SCI_HOMEDISPLAYEXTEND
;
3170 case SCI_HOMEWRAP
: return SCI_HOMEWRAPEXTEND
;
3171 case SCI_VCHOME
: return SCI_VCHOMEEXTEND
;
3172 case SCI_VCHOMEDISPLAY
: return SCI_VCHOMEDISPLAYEXTEND
;
3173 case SCI_VCHOMEWRAP
: return SCI_VCHOMEWRAPEXTEND
;
3175 case SCI_LINEEND
: return SCI_LINEENDEXTEND
;
3176 case SCI_LINEENDDISPLAY
: return SCI_LINEENDDISPLAYEXTEND
;
3177 case SCI_LINEENDWRAP
: return SCI_LINEENDWRAPEXTEND
;
3179 default: return iMessage
;
3183 int NaturalDirection(unsigned int iMessage
) {
3186 case SCI_CHARLEFTEXTEND
:
3187 case SCI_CHARLEFTRECTEXTEND
:
3189 case SCI_WORDLEFTEXTEND
:
3190 case SCI_WORDLEFTEND
:
3191 case SCI_WORDLEFTENDEXTEND
:
3192 case SCI_WORDPARTLEFT
:
3193 case SCI_WORDPARTLEFTEXTEND
:
3195 case SCI_HOMEEXTEND
:
3196 case SCI_HOMEDISPLAY
:
3197 case SCI_HOMEDISPLAYEXTEND
:
3199 case SCI_HOMEWRAPEXTEND
:
3200 // VC_HOME* mostly goes back
3202 case SCI_VCHOMEEXTEND
:
3203 case SCI_VCHOMEDISPLAY
:
3204 case SCI_VCHOMEDISPLAYEXTEND
:
3205 case SCI_VCHOMEWRAP
:
3206 case SCI_VCHOMEWRAPEXTEND
:
3214 bool IsRectExtend(unsigned int iMessage
) {
3216 case SCI_CHARLEFTRECTEXTEND
:
3217 case SCI_CHARRIGHTRECTEXTEND
:
3218 case SCI_HOMERECTEXTEND
:
3219 case SCI_VCHOMERECTEXTEND
:
3220 case SCI_LINEENDRECTEXTEND
:
3229 int Editor::VCHomeDisplayPosition(int position
) {
3230 const int homePos
= pdoc
->VCHomePosition(position
);
3231 const int viewLineStart
= StartEndDisplayLine(position
, true);
3232 if (viewLineStart
> homePos
)
3233 return viewLineStart
;
3238 int Editor::VCHomeWrapPosition(int position
) {
3239 const int homePos
= pdoc
->VCHomePosition(position
);
3240 const int viewLineStart
= StartEndDisplayLine(position
, true);
3241 if ((viewLineStart
< position
) && (viewLineStart
> homePos
))
3242 return viewLineStart
;
3247 int Editor::LineEndWrapPosition(int position
) {
3248 const int endPos
= StartEndDisplayLine(position
, false);
3249 const int realEndPos
= pdoc
->LineEndPosition(position
);
3250 if (endPos
> realEndPos
// if moved past visible EOLs
3251 || position
>= endPos
) // if at end of display line already
3257 int Editor::HorizontalMove(unsigned int iMessage
) {
3258 if (sel
.MoveExtends()) {
3259 iMessage
= WithExtends(iMessage
);
3262 if (!multipleSelection
&& !sel
.IsRectangular()) {
3263 // Simplify selection down to 1
3264 sel
.SetSelection(sel
.RangeMain());
3267 // Invalidate each of the current selections
3268 InvalidateWholeSelection();
3270 if (IsRectExtend(iMessage
)) {
3271 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3272 if (!sel
.IsRectangular()) {
3273 sel
.DropAdditionalRanges();
3275 // Will change to rectangular if not currently rectangular
3276 SelectionPosition spCaret
= rangeBase
.caret
;
3278 case SCI_CHARLEFTRECTEXTEND
:
3279 if (pdoc
->IsLineEndPosition(spCaret
.Position()) && spCaret
.VirtualSpace()) {
3280 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3282 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3285 case SCI_CHARRIGHTRECTEXTEND
:
3286 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3287 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3289 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3292 case SCI_HOMERECTEXTEND
:
3293 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3295 case SCI_VCHOMERECTEXTEND
:
3296 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3298 case SCI_LINEENDRECTEXTEND
:
3299 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3302 const int directionMove
= (spCaret
< rangeBase
.caret
) ? -1 : 1;
3303 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3304 sel
.selType
= Selection::selRectangle
;
3305 sel
.Rectangular() = SelectionRange(spCaret
, rangeBase
.anchor
);
3306 SetRectangularRange();
3308 if (sel
.IsRectangular()) {
3309 // Not a rectangular extension so switch to stream.
3310 SelectionPosition selAtLimit
= (NaturalDirection(iMessage
) > 0) ? sel
.Limits().end
: sel
.Limits().start
;
3311 sel
.selType
= Selection::selStream
;
3312 sel
.SetSelection(SelectionRange(selAtLimit
));
3314 if (!additionalSelectionTyping
) {
3315 InvalidateWholeSelection();
3316 sel
.DropAdditionalRanges();
3318 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3319 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3320 SelectionPosition spCaret
= spCaretNow
;
3323 case SCI_CHARLEFTEXTEND
:
3324 if (spCaret
.VirtualSpace()) {
3325 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3327 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3331 case SCI_CHARRIGHTEXTEND
:
3332 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(spCaret
.Position())) {
3333 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3335 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3339 case SCI_WORDLEFTEXTEND
:
3340 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), -1));
3343 case SCI_WORDRIGHTEXTEND
:
3344 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), 1));
3346 case SCI_WORDLEFTEND
:
3347 case SCI_WORDLEFTENDEXTEND
:
3348 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), -1));
3350 case SCI_WORDRIGHTEND
:
3351 case SCI_WORDRIGHTENDEXTEND
:
3352 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), 1));
3354 case SCI_WORDPARTLEFT
:
3355 case SCI_WORDPARTLEFTEXTEND
:
3356 spCaret
= SelectionPosition(pdoc
->WordPartLeft(spCaret
.Position()));
3358 case SCI_WORDPARTRIGHT
:
3359 case SCI_WORDPARTRIGHTEXTEND
:
3360 spCaret
= SelectionPosition(pdoc
->WordPartRight(spCaret
.Position()));
3363 case SCI_HOMEEXTEND
:
3364 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3366 case SCI_HOMEDISPLAY
:
3367 case SCI_HOMEDISPLAYEXTEND
:
3368 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), true));
3371 case SCI_HOMEWRAPEXTEND
:
3372 spCaret
= MovePositionSoVisible(StartEndDisplayLine(spCaret
.Position(), true), -1);
3373 if (spCaretNow
<= spCaret
)
3374 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3377 case SCI_VCHOMEEXTEND
:
3378 // VCHome alternates between beginning of line and beginning of text so may move back or forwards
3379 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3381 case SCI_VCHOMEDISPLAY
:
3382 case SCI_VCHOMEDISPLAYEXTEND
:
3383 spCaret
= SelectionPosition(VCHomeDisplayPosition(spCaret
.Position()));
3385 case SCI_VCHOMEWRAP
:
3386 case SCI_VCHOMEWRAPEXTEND
:
3387 spCaret
= SelectionPosition(VCHomeWrapPosition(spCaret
.Position()));
3390 case SCI_LINEENDEXTEND
:
3391 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3393 case SCI_LINEENDDISPLAY
:
3394 case SCI_LINEENDDISPLAYEXTEND
:
3395 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), false));
3397 case SCI_LINEENDWRAP
:
3398 case SCI_LINEENDWRAPEXTEND
:
3399 spCaret
= SelectionPosition(LineEndWrapPosition(spCaret
.Position()));
3403 PLATFORM_ASSERT(false);
3406 const int directionMove
= (spCaret
< spCaretNow
) ? -1 : 1;
3407 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3409 // Handle move versus extend, and special behaviour for non-emoty left/right
3413 if (sel
.Range(r
).Empty()) {
3414 sel
.Range(r
) = SelectionRange(spCaret
);
3416 sel
.Range(r
) = SelectionRange(
3417 (iMessage
== SCI_CHARLEFT
) ? sel
.Range(r
).Start() : sel
.Range(r
).End());
3423 case SCI_WORDLEFTEND
:
3424 case SCI_WORDRIGHTEND
:
3425 case SCI_WORDPARTLEFT
:
3426 case SCI_WORDPARTRIGHT
:
3428 case SCI_HOMEDISPLAY
:
3431 case SCI_VCHOMEDISPLAY
:
3432 case SCI_VCHOMEWRAP
:
3434 case SCI_LINEENDDISPLAY
:
3435 case SCI_LINEENDWRAP
:
3436 sel
.Range(r
) = SelectionRange(spCaret
);
3439 case SCI_CHARLEFTEXTEND
:
3440 case SCI_CHARRIGHTEXTEND
:
3441 case SCI_WORDLEFTEXTEND
:
3442 case SCI_WORDRIGHTEXTEND
:
3443 case SCI_WORDLEFTENDEXTEND
:
3444 case SCI_WORDRIGHTENDEXTEND
:
3445 case SCI_WORDPARTLEFTEXTEND
:
3446 case SCI_WORDPARTRIGHTEXTEND
:
3447 case SCI_HOMEEXTEND
:
3448 case SCI_HOMEDISPLAYEXTEND
:
3449 case SCI_HOMEWRAPEXTEND
:
3450 case SCI_VCHOMEEXTEND
:
3451 case SCI_VCHOMEDISPLAYEXTEND
:
3452 case SCI_VCHOMEWRAPEXTEND
:
3453 case SCI_LINEENDEXTEND
:
3454 case SCI_LINEENDDISPLAYEXTEND
:
3455 case SCI_LINEENDWRAPEXTEND
: {
3456 SelectionRange rangeNew
= SelectionRange(spCaret
, sel
.Range(r
).anchor
);
3457 sel
.TrimOtherSelections(r
, SelectionRange(rangeNew
));
3458 sel
.Range(r
) = rangeNew
;
3463 PLATFORM_ASSERT(false);
3468 sel
.RemoveDuplicates();
3470 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3472 // Invalidate the new state of the selection
3473 InvalidateWholeSelection();
3476 // Need the line moving and so forth from MovePositionTo
3480 int Editor::DelWordOrLine(unsigned int iMessage
) {
3481 // Virtual space may be realised for SCI_DELWORDRIGHT or SCI_DELWORDRIGHTEND
3482 // which means 2 actions so wrap in an undo group.
3484 // Rightwards and leftwards deletions differ in treatment of virtual space.
3485 // Clear virtual space for leftwards, realise for rightwards.
3486 const bool leftwards
= (iMessage
== SCI_DELWORDLEFT
) || (iMessage
== SCI_DELLINELEFT
);
3488 if (!additionalSelectionTyping
) {
3489 InvalidateWholeSelection();
3490 sel
.DropAdditionalRanges();
3493 UndoGroup
ug0(pdoc
, (sel
.Count() > 1) || !leftwards
);
3495 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3497 // Delete to the left so first clear the virtual space.
3498 sel
.Range(r
).ClearVirtualSpace();
3500 // Delete to the right so first realise the virtual space.
3501 sel
.Range(r
) = SelectionRange(
3502 InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
3507 case SCI_DELWORDLEFT
:
3508 rangeDelete
= Range(
3509 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), -1),
3510 sel
.Range(r
).caret
.Position());
3512 case SCI_DELWORDRIGHT
:
3513 rangeDelete
= Range(
3514 sel
.Range(r
).caret
.Position(),
3515 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), 1));
3517 case SCI_DELWORDRIGHTEND
:
3518 rangeDelete
= Range(
3519 sel
.Range(r
).caret
.Position(),
3520 pdoc
->NextWordEnd(sel
.Range(r
).caret
.Position(), 1));
3522 case SCI_DELLINELEFT
:
3523 rangeDelete
= Range(
3524 pdoc
->LineStart(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())),
3525 sel
.Range(r
).caret
.Position());
3527 case SCI_DELLINERIGHT
:
3528 rangeDelete
= Range(
3529 sel
.Range(r
).caret
.Position(),
3530 pdoc
->LineEnd(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())));
3533 if (!RangeContainsProtected(rangeDelete
.start
, rangeDelete
.end
)) {
3534 pdoc
->DeleteChars(rangeDelete
.start
, rangeDelete
.end
- rangeDelete
.start
);
3538 // May need something stronger here: can selections overlap at this point?
3539 sel
.RemoveDuplicates();
3541 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3543 // Invalidate the new state of the selection
3544 InvalidateWholeSelection();
3550 int Editor::KeyCommand(unsigned int iMessage
) {
3553 CursorUpOrDown(1, Selection::noSel
);
3555 case SCI_LINEDOWNEXTEND
:
3556 CursorUpOrDown(1, Selection::selStream
);
3558 case SCI_LINEDOWNRECTEXTEND
:
3559 CursorUpOrDown(1, Selection::selRectangle
);
3562 ParaUpOrDown(1, Selection::noSel
);
3564 case SCI_PARADOWNEXTEND
:
3565 ParaUpOrDown(1, Selection::selStream
);
3567 case SCI_LINESCROLLDOWN
:
3568 ScrollTo(topLine
+ 1);
3569 MoveCaretInsideView(false);
3572 CursorUpOrDown(-1, Selection::noSel
);
3574 case SCI_LINEUPEXTEND
:
3575 CursorUpOrDown(-1, Selection::selStream
);
3577 case SCI_LINEUPRECTEXTEND
:
3578 CursorUpOrDown(-1, Selection::selRectangle
);
3581 ParaUpOrDown(-1, Selection::noSel
);
3583 case SCI_PARAUPEXTEND
:
3584 ParaUpOrDown(-1, Selection::selStream
);
3586 case SCI_LINESCROLLUP
:
3587 ScrollTo(topLine
- 1);
3588 MoveCaretInsideView(false);
3592 case SCI_CHARLEFTEXTEND
:
3593 case SCI_CHARLEFTRECTEXTEND
:
3595 case SCI_CHARRIGHTEXTEND
:
3596 case SCI_CHARRIGHTRECTEXTEND
:
3598 case SCI_WORDLEFTEXTEND
:
3600 case SCI_WORDRIGHTEXTEND
:
3601 case SCI_WORDLEFTEND
:
3602 case SCI_WORDLEFTENDEXTEND
:
3603 case SCI_WORDRIGHTEND
:
3604 case SCI_WORDRIGHTENDEXTEND
:
3605 case SCI_WORDPARTLEFT
:
3606 case SCI_WORDPARTLEFTEXTEND
:
3607 case SCI_WORDPARTRIGHT
:
3608 case SCI_WORDPARTRIGHTEXTEND
:
3610 case SCI_HOMEEXTEND
:
3611 case SCI_HOMERECTEXTEND
:
3612 case SCI_HOMEDISPLAY
:
3613 case SCI_HOMEDISPLAYEXTEND
:
3615 case SCI_HOMEWRAPEXTEND
:
3617 case SCI_VCHOMEEXTEND
:
3618 case SCI_VCHOMERECTEXTEND
:
3619 case SCI_VCHOMEDISPLAY
:
3620 case SCI_VCHOMEDISPLAYEXTEND
:
3621 case SCI_VCHOMEWRAP
:
3622 case SCI_VCHOMEWRAPEXTEND
:
3624 case SCI_LINEENDEXTEND
:
3625 case SCI_LINEENDRECTEXTEND
:
3626 case SCI_LINEENDDISPLAY
:
3627 case SCI_LINEENDDISPLAYEXTEND
:
3628 case SCI_LINEENDWRAP
:
3629 case SCI_LINEENDWRAPEXTEND
:
3630 return HorizontalMove(iMessage
);
3632 case SCI_DOCUMENTSTART
:
3636 case SCI_DOCUMENTSTARTEXTEND
:
3637 MovePositionTo(0, Selection::selStream
);
3640 case SCI_DOCUMENTEND
:
3641 MovePositionTo(pdoc
->Length());
3644 case SCI_DOCUMENTENDEXTEND
:
3645 MovePositionTo(pdoc
->Length(), Selection::selStream
);
3648 case SCI_STUTTEREDPAGEUP
:
3649 PageMove(-1, Selection::noSel
, true);
3651 case SCI_STUTTEREDPAGEUPEXTEND
:
3652 PageMove(-1, Selection::selStream
, true);
3654 case SCI_STUTTEREDPAGEDOWN
:
3655 PageMove(1, Selection::noSel
, true);
3657 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3658 PageMove(1, Selection::selStream
, true);
3663 case SCI_PAGEUPEXTEND
:
3664 PageMove(-1, Selection::selStream
);
3666 case SCI_PAGEUPRECTEXTEND
:
3667 PageMove(-1, Selection::selRectangle
);
3672 case SCI_PAGEDOWNEXTEND
:
3673 PageMove(1, Selection::selStream
);
3675 case SCI_PAGEDOWNRECTEXTEND
:
3676 PageMove(1, Selection::selRectangle
);
3678 case SCI_EDITTOGGLEOVERTYPE
:
3679 inOverstrike
= !inOverstrike
;
3680 ShowCaretAtCurrentPosition();
3681 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
3684 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3685 // Also unselect text
3687 if (sel
.Count() > 1) {
3688 // Drop additional selections
3689 InvalidateWholeSelection();
3690 sel
.DropAdditionalRanges();
3693 case SCI_DELETEBACK
:
3695 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3698 EnsureCaretVisible();
3700 case SCI_DELETEBACKNOTLINE
:
3702 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3705 EnsureCaretVisible();
3709 if (caretSticky
== SC_CARETSTICKY_OFF
) {
3712 EnsureCaretVisible();
3713 ShowCaretAtCurrentPosition(); // Avoid blinking
3717 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3720 EnsureCaretVisible();
3721 ShowCaretAtCurrentPosition(); // Avoid blinking
3730 if (vs
.zoomLevel
< 20) {
3732 InvalidateStyleRedraw();
3737 if (vs
.zoomLevel
> -10) {
3739 InvalidateStyleRedraw();
3744 case SCI_DELWORDLEFT
:
3745 case SCI_DELWORDRIGHT
:
3746 case SCI_DELWORDRIGHTEND
:
3747 case SCI_DELLINELEFT
:
3748 case SCI_DELLINERIGHT
:
3749 return DelWordOrLine(iMessage
);
3751 case SCI_LINECOPY
: {
3752 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3753 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3754 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3755 pdoc
->LineStart(lineEnd
+ 1));
3759 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3760 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3761 int start
= pdoc
->LineStart(lineStart
);
3762 int end
= pdoc
->LineStart(lineEnd
+ 1);
3763 SetSelection(start
, end
);
3768 case SCI_LINEDELETE
: {
3769 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3770 int start
= pdoc
->LineStart(line
);
3771 int end
= pdoc
->LineStart(line
+ 1);
3772 pdoc
->DeleteChars(start
, end
- start
);
3775 case SCI_LINETRANSPOSE
:
3778 case SCI_LINEDUPLICATE
:
3781 case SCI_SELECTIONDUPLICATE
:
3785 ChangeCaseOfSelection(cmLower
);
3788 ChangeCaseOfSelection(cmUpper
);
3790 case SCI_SCROLLTOSTART
:
3793 case SCI_SCROLLTOEND
:
3794 ScrollTo(MaxScrollPos());
3800 int Editor::KeyDefault(int, int) {
3804 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
3806 int msg
= kmap
.Find(key
, modifiers
);
3810 return static_cast<int>(WndProc(msg
, 0, 0));
3814 return KeyDefault(key
, modifiers
);
3818 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3819 return KeyDownWithModifiers(key
, ModifierFlags(shift
, ctrl
, alt
), consumed
);
3822 void Editor::Indent(bool forwards
) {
3824 for (size_t r
=0; r
<sel
.Count(); r
++) {
3825 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
3826 int caretPosition
= sel
.Range(r
).caret
.Position();
3827 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
3828 if (lineOfAnchor
== lineCurrentPos
) {
3830 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
3831 caretPosition
= sel
.Range(r
).caret
.Position();
3832 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3834 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3835 int indentationStep
= pdoc
->IndentSize();
3836 const int posSelect
= pdoc
->SetLineIndentation(
3837 lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
3838 sel
.Range(r
) = SelectionRange(posSelect
);
3840 if (pdoc
->useTabs
) {
3841 const int lengthInserted
= pdoc
->InsertString(caretPosition
, "\t", 1);
3842 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3844 int numSpaces
= (pdoc
->tabInChars
) -
3845 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
3847 numSpaces
= pdoc
->tabInChars
;
3848 const std::string
spaceText(numSpaces
, ' ');
3849 const int lengthInserted
= pdoc
->InsertString(caretPosition
, spaceText
.c_str(),
3850 static_cast<int>(spaceText
.length()));
3851 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3855 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3857 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3858 int indentationStep
= pdoc
->IndentSize();
3859 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3860 sel
.Range(r
) = SelectionRange(posSelect
);
3862 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
3866 int newPos
= caretPosition
;
3867 while (pdoc
->GetColumn(newPos
) > newColumn
)
3869 sel
.Range(r
) = SelectionRange(newPos
);
3872 } else { // Multiline
3873 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
3874 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
3875 // Multiple lines selected so indent / dedent
3876 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3877 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3878 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
3879 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3880 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3881 if (lineOfAnchor
< lineCurrentPos
) {
3882 if (currentPosPosOnLine
== 0)
3883 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3885 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3887 if (anchorPosOnLine
== 0)
3888 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3890 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3894 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
3897 class CaseFolderASCII
: public CaseFolderTable
{
3902 ~CaseFolderASCII() {
3907 CaseFolder
*Editor::CaseFolderForEncoding() {
3908 // Simple default that only maps ASCII upper case to lower case.
3909 return new CaseFolderASCII();
3913 * Search of a text in the document, in the given range.
3914 * @return The position of the found text, -1 if not found.
3916 long Editor::FindText(
3917 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3918 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3919 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3921 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
3922 int lengthFound
= istrlen(ft
->lpstrText
);
3923 if (!pdoc
->HasCaseFolder())
3924 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3926 long pos
= pdoc
->FindText(
3927 static_cast<int>(ft
->chrg
.cpMin
),
3928 static_cast<int>(ft
->chrg
.cpMax
),
3930 static_cast<int>(wParam
),
3933 ft
->chrgText
.cpMin
= pos
;
3934 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3936 return static_cast<int>(pos
);
3937 } catch (RegexError
&) {
3938 errorStatus
= SC_STATUS_WARN_REGEX
;
3944 * Relocatable search support : Searches relative to current selection
3945 * point and sets the selection to the found text range with
3949 * Anchor following searches at current selection start: This allows
3950 * multiple incremental interactive searches to be macro recorded
3951 * while still setting the selection to found text so the find/select
3952 * operation is self-contained.
3954 void Editor::SearchAnchor() {
3955 searchAnchor
= SelectionStart().Position();
3959 * Find text from current search anchor: Must call @c SearchAnchor first.
3960 * Used for next text and previous text requests.
3961 * @return The position of the found text, -1 if not found.
3963 long Editor::SearchText(
3964 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3965 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3966 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3967 sptr_t lParam
) { ///< The text to search for.
3969 const char *txt
= reinterpret_cast<char *>(lParam
);
3971 int lengthFound
= istrlen(txt
);
3972 if (!pdoc
->HasCaseFolder())
3973 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3975 if (iMessage
== SCI_SEARCHNEXT
) {
3976 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3977 static_cast<int>(wParam
),
3980 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3981 static_cast<int>(wParam
),
3984 } catch (RegexError
&) {
3985 errorStatus
= SC_STATUS_WARN_REGEX
;
3989 SetSelection(static_cast<int>(pos
), static_cast<int>(pos
+ lengthFound
));
3995 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
3997 for (size_t i
=0; i
<ret
.size(); i
++) {
3998 switch (caseMapping
) {
4000 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
4001 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
4004 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
4005 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
4013 * Search for text in the target range of the document.
4014 * @return The position of the found text, -1 if not found.
4016 long Editor::SearchInTarget(const char *text
, int length
) {
4017 int lengthFound
= length
;
4019 if (!pdoc
->HasCaseFolder())
4020 pdoc
->SetCaseFolder(CaseFolderForEncoding());
4022 long pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4026 targetStart
= static_cast<int>(pos
);
4027 targetEnd
= static_cast<int>(pos
+ lengthFound
);
4030 } catch (RegexError
&) {
4031 errorStatus
= SC_STATUS_WARN_REGEX
;
4036 void Editor::GoToLine(int lineNo
) {
4037 if (lineNo
> pdoc
->LinesTotal())
4038 lineNo
= pdoc
->LinesTotal();
4041 SetEmptySelection(pdoc
->LineStart(lineNo
));
4042 ShowCaretAtCurrentPosition();
4043 EnsureCaretVisible();
4046 static bool Close(Point pt1
, Point pt2
, Point threshold
) {
4047 if (std::abs(pt1
.x
- pt2
.x
) > threshold
.x
)
4049 if (std::abs(pt1
.y
- pt2
.y
) > threshold
.y
)
4054 std::string
Editor::RangeText(int start
, int end
) const {
4056 int len
= end
- start
;
4057 std::string
ret(len
, '\0');
4058 for (int i
= 0; i
< len
; i
++) {
4059 ret
[i
] = pdoc
->CharAt(start
+ i
);
4063 return std::string();
4066 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
4068 if (allowLineCopy
) {
4069 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4070 int start
= pdoc
->LineStart(currentLine
);
4071 int end
= pdoc
->LineEnd(currentLine
);
4073 std::string text
= RangeText(start
, end
);
4074 if (pdoc
->eolMode
!= SC_EOL_LF
)
4075 text
.push_back('\r');
4076 if (pdoc
->eolMode
!= SC_EOL_CR
)
4077 text
.push_back('\n');
4078 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4079 vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
4083 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
4084 if (sel
.selType
== Selection::selRectangle
)
4085 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
4086 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
4087 SelectionRange current
= rangesInOrder
[r
];
4088 text
.append(RangeText(current
.Start().Position(), current
.End().Position()));
4089 if (sel
.selType
== Selection::selRectangle
) {
4090 if (pdoc
->eolMode
!= SC_EOL_LF
)
4091 text
.push_back('\r');
4092 if (pdoc
->eolMode
!= SC_EOL_CR
)
4093 text
.push_back('\n');
4096 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4097 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
4101 void Editor::CopyRangeToClipboard(int start
, int end
) {
4102 start
= pdoc
->ClampPositionIntoDocument(start
);
4103 end
= pdoc
->ClampPositionIntoDocument(end
);
4104 SelectionText selectedText
;
4105 std::string text
= RangeText(start
, end
);
4106 selectedText
.Copy(text
,
4107 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4108 CopyToClipboard(selectedText
);
4111 void Editor::CopyText(int length
, const char *text
) {
4112 SelectionText selectedText
;
4113 selectedText
.Copy(std::string(text
, length
),
4114 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4115 CopyToClipboard(selectedText
);
4118 void Editor::SetDragPosition(SelectionPosition newPos
) {
4119 if (newPos
.Position() >= 0) {
4120 newPos
= MovePositionOutsideChar(newPos
, 1);
4123 if (!(posDrag
== newPos
)) {
4125 if (FineTickerAvailable()) {
4126 FineTickerCancel(tickCaret
);
4127 if ((caret
.active
) && (caret
.period
> 0) && (newPos
.Position() < 0))
4128 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
4138 void Editor::DisplayCursor(Window::Cursor c
) {
4139 if (cursorMode
== SC_CURSORNORMAL
)
4142 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4145 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
4146 int xMove
= static_cast<int>(ptStart
.x
- ptNow
.x
);
4147 int yMove
= static_cast<int>(ptStart
.y
- ptNow
.y
);
4148 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
4149 return distanceSquared
> 16;
4152 void Editor::StartDrag() {
4153 // Always handled by subclasses
4154 //SetMouseCapture(true);
4155 //DisplayCursor(Window::cursorArrow);
4158 void Editor::DropAt(SelectionPosition position
, const char *value
, size_t lengthValue
, bool moving
, bool rectangular
) {
4159 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
4160 if (inDragDrop
== ddDragging
)
4161 dropWentOutside
= false;
4163 bool positionWasInSelection
= PositionInSelection(position
.Position());
4165 bool positionOnEdgeOfSelection
=
4166 (position
== SelectionStart()) || (position
== SelectionEnd());
4168 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
4169 (positionOnEdgeOfSelection
&& !moving
)) {
4171 SelectionPosition selStart
= SelectionStart();
4172 SelectionPosition selEnd
= SelectionEnd();
4176 SelectionPosition positionAfterDeletion
= position
;
4177 if ((inDragDrop
== ddDragging
) && moving
) {
4178 // Remove dragged out text
4179 if (rectangular
|| sel
.selType
== Selection::selLines
) {
4180 for (size_t r
=0; r
<sel
.Count(); r
++) {
4181 if (position
>= sel
.Range(r
).Start()) {
4182 if (position
> sel
.Range(r
).End()) {
4183 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
4185 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
4190 if (position
> selStart
) {
4191 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
4196 position
= positionAfterDeletion
;
4198 std::string convertedText
= Document::TransformLineEnds(value
, lengthValue
, pdoc
->eolMode
);
4201 PasteRectangular(position
, convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4202 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4203 SetEmptySelection(position
);
4205 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
4206 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
4207 const int lengthInserted
= pdoc
->InsertString(
4208 position
.Position(), convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4209 if (lengthInserted
> 0) {
4210 SelectionPosition posAfterInsertion
= position
;
4211 posAfterInsertion
.Add(lengthInserted
);
4212 SetSelection(posAfterInsertion
, position
);
4215 } else if (inDragDrop
== ddDragging
) {
4216 SetEmptySelection(position
);
4220 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
4221 DropAt(position
, value
, strlen(value
), moving
, rectangular
);
4225 * @return true if given position is inside the selection,
4227 bool Editor::PositionInSelection(int pos
) {
4228 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
4229 for (size_t r
=0; r
<sel
.Count(); r
++) {
4230 if (sel
.Range(r
).Contains(pos
))
4236 bool Editor::PointInSelection(Point pt
) {
4237 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
4238 Point ptPos
= LocationFromPosition(pos
);
4239 for (size_t r
=0; r
<sel
.Count(); r
++) {
4240 SelectionRange range
= sel
.Range(r
);
4241 if (range
.Contains(pos
)) {
4243 if (pos
== range
.Start()) {
4244 // see if just before selection
4245 if (pt
.x
< ptPos
.x
) {
4249 if (pos
== range
.End()) {
4250 // see if just after selection
4251 if (pt
.x
> ptPos
.x
) {
4262 bool Editor::PointInSelMargin(Point pt
) const {
4263 // Really means: "Point in a margin"
4264 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4265 PRectangle rcSelMargin
= GetClientRectangle();
4266 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.leftMarginWidth
);
4267 rcSelMargin
.left
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.fixedColumnWidth
);
4268 return rcSelMargin
.ContainsWholePixel(pt
);
4274 Window::Cursor
Editor::GetMarginCursor(Point pt
) const {
4276 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
4277 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4278 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
4279 x
+= vs
.ms
[margin
].width
;
4281 return Window::cursorReverseArrow
;
4284 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
4285 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
4286 SetSelection(currentPos_
, anchor_
);
4289 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
4290 int selCurrentPos
, selAnchorPos
;
4292 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
4293 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
4294 if (lineAnchorPos_
< lineCurrentPos_
) {
4295 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
4296 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4297 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4298 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
4299 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4300 } else { // Same line, select it
4301 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4302 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4305 if (lineAnchorPos_
< lineCurrentPos_
) {
4306 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
4307 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4308 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4309 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4310 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
4311 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4312 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
4313 } else { // Same line, select it
4314 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4315 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4316 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4319 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
4322 void Editor::WordSelection(int pos
) {
4323 if (pos
< wordSelectAnchorStartPos
) {
4324 // Extend backward to the word containing pos.
4325 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
4326 // This ensures that a series of empty lines isn't counted as a single "word".
4327 if (!pdoc
->IsLineEndPosition(pos
))
4328 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
4329 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
4330 } else if (pos
> wordSelectAnchorEndPos
) {
4331 // Extend forward to the word containing the character to the left of pos.
4332 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
4333 // This ensures that a series of empty lines isn't counted as a single "word".
4334 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
4335 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
4336 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
4338 // Select only the anchored word
4339 if (pos
>= originalAnchorPos
)
4340 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
4342 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
4346 void Editor::DwellEnd(bool mouseMoved
) {
4348 ticksToDwell
= dwellDelay
;
4350 ticksToDwell
= SC_TIME_FOREVER
;
4351 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4353 NotifyDwelling(ptMouseLast
, dwelling
);
4355 if (FineTickerAvailable()) {
4356 FineTickerCancel(tickDwell
);
4357 if (mouseMoved
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4358 //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
4363 void Editor::MouseLeave() {
4364 SetHotSpotRange(NULL
);
4365 if (!HaveMouseCapture()) {
4366 ptMouseLast
= Point(-1,-1);
4371 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
4372 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
4373 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
4376 void Editor::ButtonDownWithModifiers(Point pt
, unsigned int curTime
, int modifiers
) {
4377 SetHoverIndicatorPoint(pt
);
4378 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
4380 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
4381 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
4382 const bool alt
= (modifiers
& SCI_ALT
) != 0;
4383 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
4384 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4385 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4386 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4387 inDragDrop
= ddNone
;
4388 sel
.SetMoveExtends(false);
4390 if (NotifyMarginClick(pt
, modifiers
))
4393 NotifyIndicatorClick(true, newPos
.Position(), modifiers
);
4395 bool inSelMargin
= PointInSelMargin(pt
);
4396 // In margin ctrl+(double)click should always select everything
4397 if (ctrl
&& inSelMargin
) {
4399 lastClickTime
= curTime
;
4403 if (shift
&& !inSelMargin
) {
4404 SetSelection(newPos
);
4406 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
, doubleClickCloseThreshold
)) {
4407 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4408 SetMouseCapture(true);
4409 if (FineTickerAvailable()) {
4410 FineTickerStart(tickScroll
, 100, 10);
4412 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
4413 SetEmptySelection(newPos
.Position());
4414 bool doubleClick
= false;
4415 // Stop mouse button bounce changing selection type
4416 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4418 // Inside margin selection type should be either selSubLine or selWholeLine.
4419 if (selectionType
== selSubLine
) {
4420 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
4421 // so we switch to selWholeLine in order to select whole line.
4422 selectionType
= selWholeLine
;
4423 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
4424 // If it is neither, reset selection type to line selection.
4425 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4428 if (selectionType
== selChar
) {
4429 selectionType
= selWord
;
4431 } else if (selectionType
== selWord
) {
4432 // Since we ended up here, we're inside a *triple* click, which should always select
4433 // whole line regardless of word wrap being enabled or not.
4434 selectionType
= selWholeLine
;
4436 selectionType
= selChar
;
4437 originalAnchorPos
= sel
.MainCaret();
4442 if (selectionType
== selWord
) {
4443 int charPos
= originalAnchorPos
;
4444 if (sel
.MainCaret() == originalAnchorPos
) {
4445 charPos
= PositionFromLocation(pt
, false, true);
4446 charPos
= MovePositionOutsideChar(charPos
, -1);
4449 int startWord
, endWord
;
4450 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
4451 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
4452 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
4454 // Selecting backwards, or anchor beyond last character on line. In these cases,
4455 // we select the word containing the character to the *left* of the anchor.
4456 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
4457 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
4458 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
4460 // Anchor at start of line; select nothing to begin with.
4461 startWord
= charPos
;
4466 wordSelectAnchorStartPos
= startWord
;
4467 wordSelectAnchorEndPos
= endWord
;
4468 wordSelectInitialCaretPos
= sel
.MainCaret();
4469 WordSelection(wordSelectInitialCaretPos
);
4470 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
4471 lineAnchorPos
= newPos
.Position();
4472 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4473 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4475 SetEmptySelection(sel
.MainCaret());
4477 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4479 NotifyDoubleClick(pt
, modifiers
);
4480 if (PositionIsHotspot(newCharPos
.Position()))
4481 NotifyHotSpotDoubleClicked(newCharPos
.Position(), modifiers
);
4483 } else { // Single click
4485 sel
.selType
= Selection::selStream
;
4487 // Single click in margin: select whole line or only subline if word wrap is enabled
4488 lineAnchorPos
= newPos
.Position();
4489 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4490 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4492 // Single shift+click in margin: select from line anchor to clicked line
4493 if (sel
.MainAnchor() > sel
.MainCaret())
4494 lineAnchorPos
= sel
.MainAnchor() - 1;
4496 lineAnchorPos
= sel
.MainAnchor();
4497 // Reset selection type if there is an empty selection.
4498 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
4499 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
4500 // This ensures that we continue selecting in the same selection mode.
4501 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
4502 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4503 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4506 SetDragPosition(SelectionPosition(invalidPosition
));
4507 SetMouseCapture(true);
4508 if (FineTickerAvailable()) {
4509 FineTickerStart(tickScroll
, 100, 10);
4512 if (PointIsHotspot(pt
)) {
4513 NotifyHotSpotClicked(newCharPos
.Position(), modifiers
);
4514 hotSpotClickPos
= newCharPos
.Position();
4517 if (PointInSelection(pt
) && !SelectionEmpty())
4518 inDragDrop
= ddInitial
;
4520 inDragDrop
= ddNone
;
4522 SetMouseCapture(true);
4523 if (FineTickerAvailable()) {
4524 FineTickerStart(tickScroll
, 100, 10);
4526 if (inDragDrop
!= ddInitial
) {
4527 SetDragPosition(SelectionPosition(invalidPosition
));
4529 if (ctrl
&& multipleSelection
) {
4530 SelectionRange
range(newPos
);
4531 sel
.TentativeSelection(range
);
4532 InvalidateSelection(range
, true);
4534 InvalidateSelection(SelectionRange(newPos
), true);
4535 if (sel
.Count() > 1)
4537 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
4539 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4540 SetSelection(newPos
, newPos
);
4543 SelectionPosition anchorCurrent
= newPos
;
4545 anchorCurrent
= sel
.IsRectangular() ?
4546 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
4547 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4548 selectionType
= selChar
;
4549 originalAnchorPos
= sel
.MainCaret();
4550 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
4551 SetRectangularRange();
4555 lastClickTime
= curTime
;
4557 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4558 ShowCaretAtCurrentPosition();
4561 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4562 return ButtonDownWithModifiers(pt
, curTime
, ModifierFlags(shift
, ctrl
, alt
));
4565 bool Editor::PositionIsHotspot(int position
) const {
4566 return vs
.styles
[pdoc
->StyleIndexAt(position
)].hotspot
;
4569 bool Editor::PointIsHotspot(Point pt
) {
4570 int pos
= PositionFromLocation(pt
, true, true);
4571 if (pos
== INVALID_POSITION
)
4573 return PositionIsHotspot(pos
);
4576 void Editor::SetHoverIndicatorPosition(int position
) {
4577 int hoverIndicatorPosPrev
= hoverIndicatorPos
;
4578 hoverIndicatorPos
= INVALID_POSITION
;
4579 if (vs
.indicatorsDynamic
== 0)
4581 if (position
!= INVALID_POSITION
) {
4582 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
4583 if (vs
.indicators
[deco
->indicator
].IsDynamic()) {
4584 if (pdoc
->decorations
.ValueAt(deco
->indicator
, position
)) {
4585 hoverIndicatorPos
= position
;
4590 if (hoverIndicatorPosPrev
!= hoverIndicatorPos
) {
4595 void Editor::SetHoverIndicatorPoint(Point pt
) {
4596 if (vs
.indicatorsDynamic
== 0) {
4597 SetHoverIndicatorPosition(INVALID_POSITION
);
4599 SetHoverIndicatorPosition(PositionFromLocation(pt
, true, true));
4603 void Editor::SetHotSpotRange(Point
*pt
) {
4605 int pos
= PositionFromLocation(*pt
, false, true);
4607 // If we don't limit this to word characters then the
4608 // range can encompass more than the run range and then
4609 // the underline will not be drawn properly.
4611 hsNew
.start
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4612 hsNew
.end
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4614 // Only invalidate the range if the hotspot range has changed...
4615 if (!(hsNew
== hotspot
)) {
4616 if (hotspot
.Valid()) {
4617 InvalidateRange(hotspot
.start
, hotspot
.end
);
4620 InvalidateRange(hotspot
.start
, hotspot
.end
);
4623 if (hotspot
.Valid()) {
4624 InvalidateRange(hotspot
.start
, hotspot
.end
);
4626 hotspot
= Range(invalidPosition
);
4630 Range
Editor::GetHotSpotRange() const {
4634 void Editor::ButtonMoveWithModifiers(Point pt
, int modifiers
) {
4635 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4639 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
4640 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4641 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
4643 if (inDragDrop
== ddInitial
) {
4644 if (DragThreshold(ptMouseLast
, pt
)) {
4645 SetMouseCapture(false);
4646 if (FineTickerAvailable()) {
4647 FineTickerCancel(tickScroll
);
4649 SetDragPosition(movePos
);
4650 CopySelectionRange(&drag
);
4657 PRectangle rcClient
= GetClientRectangle();
4658 Point ptOrigin
= GetVisibleOriginInMain();
4659 rcClient
.Move(0, -ptOrigin
.y
);
4660 if (FineTickerAvailable() && (dwellDelay
< SC_TIME_FOREVER
) && rcClient
.Contains(pt
)) {
4661 FineTickerStart(tickDwell
, dwellDelay
, dwellDelay
/10);
4663 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4664 if (HaveMouseCapture()) {
4666 // Slow down autoscrolling/selection
4667 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4668 if (autoScrollTimer
.ticksToWait
> 0)
4670 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4673 if (posDrag
.IsValid()) {
4674 SetDragPosition(movePos
);
4676 if (selectionType
== selChar
) {
4677 if (sel
.selType
== Selection::selStream
&& (modifiers
& SCI_ALT
) && mouseSelectionRectangularSwitch
) {
4678 sel
.selType
= Selection::selRectangle
;
4680 if (sel
.IsRectangular()) {
4681 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
4682 SetSelection(movePos
, sel
.RangeMain().anchor
);
4683 } else if (sel
.Count() > 1) {
4684 InvalidateSelection(sel
.RangeMain(), false);
4685 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
4686 sel
.TentativeSelection(range
);
4687 InvalidateSelection(range
, true);
4689 SetSelection(movePos
, sel
.RangeMain().anchor
);
4691 } else if (selectionType
== selWord
) {
4692 // Continue selecting by word
4693 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
4694 // No need to do anything. Previously this case was lumped
4695 // in with "Moved forward", but that can be harmful in this
4696 // case: a handler for the NotifyDoubleClick re-adjusts
4697 // the selection for a fancier definition of "word" (for
4698 // example, in Perl it is useful to include the leading
4699 // '$', '%' or '@' on variables for word selection). In this
4700 // the ButtonMove() called via Tick() for auto-scrolling
4701 // could result in the fancier word selection adjustment
4704 wordSelectInitialCaretPos
= -1;
4705 WordSelection(movePos
.Position());
4708 // Continue selecting by line
4709 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4714 int lineMove
= DisplayFromPosition(movePos
.Position());
4715 if (pt
.y
> rcClient
.bottom
) {
4716 ScrollTo(lineMove
- LinesOnScreen() + 1);
4718 } else if (pt
.y
< rcClient
.top
) {
4722 EnsureCaretVisible(false, false, true);
4724 if (hotspot
.Valid() && !PointIsHotspot(pt
))
4725 SetHotSpotRange(NULL
);
4727 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,true) != hotSpotClickPos
) {
4728 if (inDragDrop
== ddNone
) {
4729 DisplayCursor(Window::cursorText
);
4731 hotSpotClickPos
= INVALID_POSITION
;
4735 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4736 if (PointInSelMargin(pt
)) {
4737 DisplayCursor(GetMarginCursor(pt
));
4738 SetHotSpotRange(NULL
);
4739 return; // No need to test for selection
4742 // Display regular (drag) cursor over selection
4743 if (PointInSelection(pt
) && !SelectionEmpty()) {
4744 DisplayCursor(Window::cursorArrow
);
4746 SetHoverIndicatorPoint(pt
);
4747 if (PointIsHotspot(pt
)) {
4748 DisplayCursor(Window::cursorHand
);
4749 SetHotSpotRange(&pt
);
4751 if (hoverIndicatorPos
!= invalidPosition
)
4752 DisplayCursor(Window::cursorHand
);
4754 DisplayCursor(Window::cursorText
);
4755 SetHotSpotRange(NULL
);
4761 void Editor::ButtonMove(Point pt
) {
4762 ButtonMoveWithModifiers(pt
, 0);
4765 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4766 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
4767 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
4768 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4769 if (hoverIndicatorPos
!= INVALID_POSITION
)
4770 InvalidateRange(newPos
.Position(), newPos
.Position() + 1);
4771 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4772 if (inDragDrop
== ddInitial
) {
4773 inDragDrop
= ddNone
;
4774 SetEmptySelection(newPos
);
4775 selectionType
= selChar
;
4776 originalAnchorPos
= sel
.MainCaret();
4778 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
4779 hotSpotClickPos
= INVALID_POSITION
;
4780 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4781 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4782 NotifyHotSpotReleaseClick(newCharPos
.Position(), ctrl
? SCI_CTRL
: 0);
4784 if (HaveMouseCapture()) {
4785 if (PointInSelMargin(pt
)) {
4786 DisplayCursor(GetMarginCursor(pt
));
4788 DisplayCursor(Window::cursorText
);
4789 SetHotSpotRange(NULL
);
4792 SetMouseCapture(false);
4793 if (FineTickerAvailable()) {
4794 FineTickerCancel(tickScroll
);
4796 NotifyIndicatorClick(false, newPos
.Position(), 0);
4797 if (inDragDrop
== ddDragging
) {
4798 SelectionPosition selStart
= SelectionStart();
4799 SelectionPosition selEnd
= SelectionEnd();
4800 if (selStart
< selEnd
) {
4801 if (drag
.Length()) {
4802 const int length
= static_cast<int>(drag
.Length());
4804 const int lengthInserted
= pdoc
->InsertString(
4805 newPos
.Position(), drag
.Data(), length
);
4806 if (lengthInserted
> 0) {
4807 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4809 } else if (newPos
< selStart
) {
4810 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4811 const int lengthInserted
= pdoc
->InsertString(
4812 newPos
.Position(), drag
.Data(), length
);
4813 if (lengthInserted
> 0) {
4814 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4816 } else if (newPos
> selEnd
) {
4817 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4818 newPos
.Add(-static_cast<int>(drag
.Length()));
4819 const int lengthInserted
= pdoc
->InsertString(
4820 newPos
.Position(), drag
.Data(), length
);
4821 if (lengthInserted
> 0) {
4822 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4825 SetEmptySelection(newPos
.Position());
4829 selectionType
= selChar
;
4832 if (selectionType
== selChar
) {
4833 if (sel
.Count() > 1) {
4835 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
4836 InvalidateWholeSelection();
4838 SetSelection(newPos
, sel
.RangeMain().anchor
);
4841 sel
.CommitTentative();
4843 SetRectangularRange();
4844 lastClickTime
= curTime
;
4846 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4847 if (sel
.selType
== Selection::selStream
) {
4850 inDragDrop
= ddNone
;
4851 EnsureCaretVisible(false);
4855 // Called frequently to perform background UI including
4856 // caret blinking and automatic scrolling.
4857 void Editor::Tick() {
4858 if (HaveMouseCapture()) {
4860 ButtonMove(ptMouseLast
);
4862 if (caret
.period
> 0) {
4863 timer
.ticksToWait
-= timer
.tickSize
;
4864 if (timer
.ticksToWait
<= 0) {
4865 caret
.on
= !caret
.on
;
4866 timer
.ticksToWait
= caret
.period
;
4872 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
4873 scrollWidth
= view
.lineWidthMaxSeen
;
4876 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4877 (ticksToDwell
> 0) &&
4878 (!HaveMouseCapture()) &&
4879 (ptMouseLast
.y
>= 0)) {
4880 ticksToDwell
-= timer
.tickSize
;
4881 if (ticksToDwell
<= 0) {
4883 NotifyDwelling(ptMouseLast
, dwelling
);
4888 bool Editor::Idle() {
4889 bool needWrap
= Wrapping() && wrapPending
.NeedsWrap();
4892 // Wrap lines during idle.
4895 needWrap
= wrapPending
.NeedsWrap();
4896 } else if (needIdleStyling
) {
4900 // Add more idle things to do here, but make sure idleDone is
4901 // set correctly before the function returns. returning
4902 // false will stop calling this idle function until SetIdle() is
4905 const bool idleDone
= !needWrap
&& !needIdleStyling
; // && thatDone && theOtherThingDone...
4910 void Editor::SetTicking(bool) {
4911 // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
4912 // derived platform class but fine grained timers should now be implemented.
4913 // Either way, execution should not arrive here so assert failure.
4917 void Editor::TickFor(TickReason reason
) {
4920 caret
.on
= !caret
.on
;
4927 ButtonMove(ptMouseLast
);
4931 FineTickerCancel(tickWiden
);
4934 if ((!HaveMouseCapture()) &&
4935 (ptMouseLast
.y
>= 0)) {
4937 NotifyDwelling(ptMouseLast
, dwelling
);
4939 FineTickerCancel(tickDwell
);
4942 // tickPlatform handled by subclass
4947 bool Editor::FineTickerAvailable() {
4951 // FineTickerStart is be overridden by subclasses that support fine ticking so
4952 // this method should never be called.
4953 bool Editor::FineTickerRunning(TickReason
) {
4958 // FineTickerStart is be overridden by subclasses that support fine ticking so
4959 // this method should never be called.
4960 void Editor::FineTickerStart(TickReason
, int, int) {
4964 // FineTickerCancel is be overridden by subclasses that support fine ticking so
4965 // this method should never be called.
4966 void Editor::FineTickerCancel(TickReason
) {
4970 void Editor::SetFocusState(bool focusState
) {
4971 hasFocus
= focusState
;
4972 NotifyFocus(hasFocus
);
4976 ShowCaretAtCurrentPosition();
4979 int Editor::PositionAfterArea(PRectangle rcArea
) const {
4980 // The start of the document line after the display line after the area
4981 // This often means that the line after a modification is restyled which helps
4982 // detect multiline comment additions and heals single line comments
4983 int lineAfter
= TopLineOfMain() + static_cast<int>(rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
4984 if (lineAfter
< cs
.LinesDisplayed())
4985 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
4987 return pdoc
->Length();
4990 // Style to a position within the view. If this causes a change at end of last line then
4991 // affects later lines so style all the viewed text.
4992 void Editor::StyleToPositionInView(Position pos
) {
4993 int endWindow
= PositionAfterArea(GetClientDrawingRectangle());
4994 if (pos
> endWindow
)
4996 const int styleAtEnd
= pdoc
->StyleIndexAt(pos
-1);
4997 pdoc
->EnsureStyledTo(pos
);
4998 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleIndexAt(pos
-1))) {
4999 // Style at end of line changed so is multi-line change like starting a comment
5000 // so require rest of window to be styled.
5001 DiscardOverdraw(); // Prepared bitmaps may be invalid
5002 // DiscardOverdraw may have truncated client drawing area so recalculate endWindow
5003 endWindow
= PositionAfterArea(GetClientDrawingRectangle());
5004 pdoc
->EnsureStyledTo(endWindow
);
5008 int Editor::PositionAfterMaxStyling(int posMax
, bool scrolling
) const {
5009 if ((idleStyling
== SC_IDLESTYLING_NONE
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5010 // Both states do not limit styling
5014 // Try to keep time taken by styling reasonable so interaction remains smooth.
5015 // When scrolling, allow less time to ensure responsive
5016 const double secondsAllowed
= scrolling
? 0.005 : 0.02;
5018 const int linesToStyle
= Platform::Clamp(static_cast<int>(secondsAllowed
/ pdoc
->durationStyleOneLine
),
5020 const int stylingMaxLine
= std::min(
5021 static_cast<int>(pdoc
->LineFromPosition(pdoc
->GetEndStyled()) + linesToStyle
),
5022 pdoc
->LinesTotal());
5023 return std::min(static_cast<int>(pdoc
->LineStart(stylingMaxLine
)), posMax
);
5026 void Editor::StartIdleStyling(bool truncatedLastStyling
) {
5027 if ((idleStyling
== SC_IDLESTYLING_ALL
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5028 if (pdoc
->GetEndStyled() < pdoc
->Length()) {
5029 // Style remainder of document in idle time
5030 needIdleStyling
= true;
5032 } else if (truncatedLastStyling
) {
5033 needIdleStyling
= true;
5036 if (needIdleStyling
) {
5041 // Style for an area but bound the amount of styling to remain responsive
5042 void Editor::StyleAreaBounded(PRectangle rcArea
, bool scrolling
) {
5043 const int posAfterArea
= PositionAfterArea(rcArea
);
5044 const int posAfterMax
= PositionAfterMaxStyling(posAfterArea
, scrolling
);
5045 if (posAfterMax
< posAfterArea
) {
5046 // Idle styling may be performed before current visible area
5047 // Style a bit now then style further in idle time
5048 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5050 // Can style all wanted now.
5051 StyleToPositionInView(posAfterArea
);
5053 StartIdleStyling(posAfterMax
< posAfterArea
);
5056 void Editor::IdleStyling() {
5057 const int posAfterArea
= PositionAfterArea(GetClientRectangle());
5058 const int endGoal
= (idleStyling
>= SC_IDLESTYLING_AFTERVISIBLE
) ?
5059 pdoc
->Length() : posAfterArea
;
5060 const int posAfterMax
= PositionAfterMaxStyling(endGoal
, false);
5061 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5062 if (pdoc
->GetEndStyled() >= endGoal
) {
5063 needIdleStyling
= false;
5067 void Editor::IdleWork() {
5068 // Style the line after the modification as this allows modifications that change just the
5069 // line of the modification to heal instead of propagating to the rest of the window.
5070 if (workNeeded
.items
& WorkNeeded::workStyle
) {
5071 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(workNeeded
.upTo
) + 2));
5077 void Editor::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
5078 workNeeded
.Need(items
, upTo
);
5081 bool Editor::PaintContains(PRectangle rc
) {
5085 return rcPaint
.Contains(rc
);
5089 bool Editor::PaintContainsMargin() {
5090 if (wMargin
.GetID()) {
5091 // With separate margin view, paint of text view
5092 // never contains margin.
5095 PRectangle rcSelMargin
= GetClientRectangle();
5096 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
);
5097 return PaintContains(rcSelMargin
);
5100 void Editor::CheckForChangeOutsidePaint(Range r
) {
5101 if (paintState
== painting
&& !paintingAllText
) {
5102 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5106 PRectangle rcRange
= RectangleFromRange(r
, 0);
5107 PRectangle rcText
= GetTextRectangle();
5108 if (rcRange
.top
< rcText
.top
) {
5109 rcRange
.top
= rcText
.top
;
5111 if (rcRange
.bottom
> rcText
.bottom
) {
5112 rcRange
.bottom
= rcText
.bottom
;
5115 if (!PaintContains(rcRange
)) {
5117 paintAbandonedByStyling
= true;
5122 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5123 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5124 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5125 CheckForChangeOutsidePaint(Range(braces
[0]));
5126 CheckForChangeOutsidePaint(Range(pos0
));
5129 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5130 CheckForChangeOutsidePaint(Range(braces
[1]));
5131 CheckForChangeOutsidePaint(Range(pos1
));
5134 bracesMatchStyle
= matchStyle
;
5135 if (paintState
== notPainting
) {
5141 void Editor::SetAnnotationHeights(int start
, int end
) {
5142 if (vs
.annotationVisible
) {
5144 bool changedHeight
= false;
5145 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
5146 int linesWrapped
= 1;
5148 AutoSurface
surface(this);
5149 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5150 if (surface
&& ll
) {
5151 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5152 linesWrapped
= ll
->lines
;
5155 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
5156 changedHeight
= true;
5158 if (changedHeight
) {
5164 void Editor::SetDocPointer(Document
*document
) {
5165 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5166 pdoc
->RemoveWatcher(this, 0);
5168 if (document
== NULL
) {
5169 pdoc
= new Document();
5175 // Ensure all positions within document
5180 braces
[0] = invalidPosition
;
5181 braces
[1] = invalidPosition
;
5183 vs
.ReleaseAllExtendedStyles();
5185 SetRepresentations();
5187 // Reset the contraction state to fully shown.
5189 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5190 SetAnnotationHeights(0, pdoc
->LinesTotal());
5191 view
.llc
.Deallocate();
5194 hotspot
= Range(invalidPosition
);
5195 hoverIndicatorPos
= invalidPosition
;
5197 view
.ClearAllTabstops();
5199 pdoc
->AddWatcher(this, 0);
5204 void Editor::SetAnnotationVisible(int visible
) {
5205 if (vs
.annotationVisible
!= visible
) {
5206 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
5207 vs
.annotationVisible
= visible
;
5208 if (changedFromOrToHidden
) {
5209 int dir
= vs
.annotationVisible
? 1 : -1;
5210 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
5211 int annotationLines
= pdoc
->AnnotationLines(line
);
5212 if (annotationLines
> 0) {
5213 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
5222 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5224 int Editor::ExpandLine(int line
) {
5225 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5227 while (line
<= lineMaxSubord
) {
5228 cs
.SetVisible(line
, line
, true);
5229 int level
= pdoc
->GetLevel(line
);
5230 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5231 if (cs
.GetExpanded(line
)) {
5232 line
= ExpandLine(line
);
5234 line
= pdoc
->GetLastChild(line
);
5239 return lineMaxSubord
;
5242 void Editor::SetFoldExpanded(int lineDoc
, bool expanded
) {
5243 if (cs
.SetExpanded(lineDoc
, expanded
)) {
5248 void Editor::FoldLine(int line
, int action
) {
5250 if (action
== SC_FOLDACTION_TOGGLE
) {
5251 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5252 line
= pdoc
->GetFoldParent(line
);
5256 action
= (cs
.GetExpanded(line
)) ? SC_FOLDACTION_CONTRACT
: SC_FOLDACTION_EXPAND
;
5259 if (action
== SC_FOLDACTION_CONTRACT
) {
5260 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5261 if (lineMaxSubord
> line
) {
5262 cs
.SetExpanded(line
, 0);
5263 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5265 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
5266 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5267 // This does not re-expand the fold
5268 EnsureCaretVisible();
5273 if (!(cs
.GetVisible(line
))) {
5274 EnsureLineVisible(line
, false);
5277 cs
.SetExpanded(line
, 1);
5286 void Editor::FoldExpand(int line
, int action
, int level
) {
5287 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5288 if (action
== SC_FOLDACTION_TOGGLE
) {
5289 expanding
= !cs
.GetExpanded(line
);
5291 SetFoldExpanded(line
, expanding
);
5292 if (expanding
&& (cs
.HiddenLines() == 0))
5295 int lineMaxSubord
= pdoc
->GetLastChild(line
, level
& SC_FOLDLEVELNUMBERMASK
);
5297 cs
.SetVisible(line
, lineMaxSubord
, expanding
);
5298 while (line
<= lineMaxSubord
) {
5299 int levelLine
= pdoc
->GetLevel(line
);
5300 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5301 SetFoldExpanded(line
, expanding
);
5309 int Editor::ContractedFoldNext(int lineStart
) const {
5310 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
5311 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
5313 line
= cs
.ContractedNext(line
+1);
5322 * Recurse up from this line to find any folds that prevent this line from being visible
5323 * and unfold them all.
5325 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5327 // In case in need of wrapping to ensure DisplayFromDoc works.
5328 if (lineDoc
>= wrapPending
.start
)
5331 if (!cs
.GetVisible(lineDoc
)) {
5332 // Back up to find a non-blank line
5333 int lookLine
= lineDoc
;
5334 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
5335 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
5336 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
5338 int lineParent
= pdoc
->GetFoldParent(lookLine
);
5339 if (lineParent
< 0) {
5340 // Backed up to a top level line, so try to find parent of initial line
5341 lineParent
= pdoc
->GetFoldParent(lineDoc
);
5343 if (lineParent
>= 0) {
5344 if (lineDoc
!= lineParent
)
5345 EnsureLineVisible(lineParent
, enforcePolicy
);
5346 if (!cs
.GetExpanded(lineParent
)) {
5347 cs
.SetExpanded(lineParent
, 1);
5348 ExpandLine(lineParent
);
5354 if (enforcePolicy
) {
5355 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5356 if (visiblePolicy
& VISIBLE_SLOP
) {
5357 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5358 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5359 SetVerticalScrollPos();
5361 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5362 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5363 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5364 SetVerticalScrollPos();
5368 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5369 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5370 SetVerticalScrollPos();
5377 void Editor::FoldAll(int action
) {
5378 pdoc
->EnsureStyledTo(pdoc
->Length());
5379 int maxLine
= pdoc
->LinesTotal();
5380 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5381 if (action
== SC_FOLDACTION_TOGGLE
) {
5382 // Discover current state
5383 for (int lineSeek
= 0; lineSeek
< maxLine
; lineSeek
++) {
5384 if (pdoc
->GetLevel(lineSeek
) & SC_FOLDLEVELHEADERFLAG
) {
5385 expanding
= !cs
.GetExpanded(lineSeek
);
5391 cs
.SetVisible(0, maxLine
-1, true);
5392 for (int line
= 0; line
< maxLine
; line
++) {
5393 int levelLine
= pdoc
->GetLevel(line
);
5394 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5395 SetFoldExpanded(line
, true);
5399 for (int line
= 0; line
< maxLine
; line
++) {
5400 int level
= pdoc
->GetLevel(line
);
5401 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
5402 (SC_FOLDLEVELBASE
== (level
& SC_FOLDLEVELNUMBERMASK
))) {
5403 SetFoldExpanded(line
, false);
5404 int lineMaxSubord
= pdoc
->GetLastChild(line
, -1);
5405 if (lineMaxSubord
> line
) {
5406 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5415 void Editor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
5416 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
5417 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
5418 // Adding a fold point.
5419 if (cs
.SetExpanded(line
, true)) {
5422 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5424 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
5425 if (!cs
.GetExpanded(line
)) {
5426 // Removing the fold from one that has been contracted so should expand
5427 // otherwise lines are left invisible with no way to make them visible
5428 if (cs
.SetExpanded(line
, true)) {
5431 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5434 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) &&
5435 ((levelPrev
& SC_FOLDLEVELNUMBERMASK
) > (levelNow
& SC_FOLDLEVELNUMBERMASK
))) {
5436 if (cs
.HiddenLines()) {
5437 // See if should still be hidden
5438 int parentLine
= pdoc
->GetFoldParent(line
);
5439 if ((parentLine
< 0) || (cs
.GetExpanded(parentLine
) && cs
.GetVisible(parentLine
))) {
5440 cs
.SetVisible(line
, line
, true);
5448 void Editor::NeedShown(int pos
, int len
) {
5449 if (foldAutomatic
& SC_AUTOMATICFOLD_SHOW
) {
5450 int lineStart
= pdoc
->LineFromPosition(pos
);
5451 int lineEnd
= pdoc
->LineFromPosition(pos
+len
);
5452 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
5453 EnsureLineVisible(line
, false);
5456 NotifyNeedShown(pos
, len
);
5460 int Editor::GetTag(char *tagValue
, int tagNumber
) {
5461 const char *text
= 0;
5463 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
5464 char name
[3] = "\\?";
5465 name
[1] = static_cast<char>(tagNumber
+ '0');
5467 text
= pdoc
->SubstituteByPosition(name
, &length
);
5471 memcpy(tagValue
, text
, length
+ 1);
5478 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5481 length
= istrlen(text
);
5482 if (replacePatterns
) {
5483 text
= pdoc
->SubstituteByPosition(text
, &length
);
5488 if (targetStart
!= targetEnd
)
5489 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5490 targetEnd
= targetStart
;
5491 const int lengthInserted
= pdoc
->InsertString(targetStart
, text
, length
);
5492 targetEnd
= targetStart
+ lengthInserted
;
5496 bool Editor::IsUnicodeMode() const {
5497 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5500 int Editor::CodePage() const {
5502 return pdoc
->dbcsCodePage
;
5507 int Editor::WrapCount(int line
) {
5508 AutoSurface
surface(this);
5509 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5511 if (surface
&& ll
) {
5512 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5519 void Editor::AddStyledText(char *buffer
, int appendLength
) {
5520 // The buffer consists of alternating character bytes and style bytes
5521 int textLength
= appendLength
/ 2;
5522 std::string
text(textLength
, '\0');
5524 for (i
= 0; i
< textLength
; i
++) {
5525 text
[i
] = buffer
[i
*2];
5527 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), text
.c_str(), textLength
);
5528 for (i
= 0; i
< textLength
; i
++) {
5529 text
[i
] = buffer
[i
*2+1];
5531 pdoc
->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
5532 pdoc
->SetStyles(textLength
, text
.c_str());
5533 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5536 static bool ValidMargin(uptr_t wParam
) {
5537 return wParam
<= SC_MAX_MARGIN
;
5540 static char *CharPtrFromSPtr(sptr_t lParam
) {
5541 return reinterpret_cast<char *>(lParam
);
5544 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5545 vs
.EnsureStyle(wParam
);
5547 case SCI_STYLESETFORE
:
5548 vs
.styles
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
5550 case SCI_STYLESETBACK
:
5551 vs
.styles
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
5553 case SCI_STYLESETBOLD
:
5554 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
5556 case SCI_STYLESETWEIGHT
:
5557 vs
.styles
[wParam
].weight
= static_cast<int>(lParam
);
5559 case SCI_STYLESETITALIC
:
5560 vs
.styles
[wParam
].italic
= lParam
!= 0;
5562 case SCI_STYLESETEOLFILLED
:
5563 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5565 case SCI_STYLESETSIZE
:
5566 vs
.styles
[wParam
].size
= static_cast<int>(lParam
* SC_FONT_SIZE_MULTIPLIER
);
5568 case SCI_STYLESETSIZEFRACTIONAL
:
5569 vs
.styles
[wParam
].size
= static_cast<int>(lParam
);
5571 case SCI_STYLESETFONT
:
5573 vs
.SetStyleFontName(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5576 case SCI_STYLESETUNDERLINE
:
5577 vs
.styles
[wParam
].underline
= lParam
!= 0;
5579 case SCI_STYLESETCASE
:
5580 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5582 case SCI_STYLESETCHARACTERSET
:
5583 vs
.styles
[wParam
].characterSet
= static_cast<int>(lParam
);
5584 pdoc
->SetCaseFolder(NULL
);
5586 case SCI_STYLESETVISIBLE
:
5587 vs
.styles
[wParam
].visible
= lParam
!= 0;
5589 case SCI_STYLESETCHANGEABLE
:
5590 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5592 case SCI_STYLESETHOTSPOT
:
5593 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5596 InvalidateStyleRedraw();
5599 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5600 vs
.EnsureStyle(wParam
);
5602 case SCI_STYLEGETFORE
:
5603 return vs
.styles
[wParam
].fore
.AsLong();
5604 case SCI_STYLEGETBACK
:
5605 return vs
.styles
[wParam
].back
.AsLong();
5606 case SCI_STYLEGETBOLD
:
5607 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
5608 case SCI_STYLEGETWEIGHT
:
5609 return vs
.styles
[wParam
].weight
;
5610 case SCI_STYLEGETITALIC
:
5611 return vs
.styles
[wParam
].italic
? 1 : 0;
5612 case SCI_STYLEGETEOLFILLED
:
5613 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5614 case SCI_STYLEGETSIZE
:
5615 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
5616 case SCI_STYLEGETSIZEFRACTIONAL
:
5617 return vs
.styles
[wParam
].size
;
5618 case SCI_STYLEGETFONT
:
5619 return StringResult(lParam
, vs
.styles
[wParam
].fontName
);
5620 case SCI_STYLEGETUNDERLINE
:
5621 return vs
.styles
[wParam
].underline
? 1 : 0;
5622 case SCI_STYLEGETCASE
:
5623 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5624 case SCI_STYLEGETCHARACTERSET
:
5625 return vs
.styles
[wParam
].characterSet
;
5626 case SCI_STYLEGETVISIBLE
:
5627 return vs
.styles
[wParam
].visible
? 1 : 0;
5628 case SCI_STYLEGETCHANGEABLE
:
5629 return vs
.styles
[wParam
].changeable
? 1 : 0;
5630 case SCI_STYLEGETHOTSPOT
:
5631 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5636 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
5637 const size_t len
= val
? strlen(val
) : 0;
5639 char *ptr
= CharPtrFromSPtr(lParam
);
5641 memcpy(ptr
, val
, len
+1);
5645 return len
; // Not including NUL
5648 sptr_t
Editor::BytesResult(sptr_t lParam
, const unsigned char *val
, size_t len
) {
5649 // No NUL termination: len is number of valid/displayed bytes
5650 if ((lParam
) && (len
> 0)) {
5651 char *ptr
= CharPtrFromSPtr(lParam
);
5653 memcpy(ptr
, val
, len
);
5657 return val
? len
: 0;
5660 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5661 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5663 // Optional macro recording hook
5665 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5671 return pdoc
->Length() + 1;
5674 char *ptr
= CharPtrFromSPtr(lParam
);
5675 unsigned int iChar
= 0;
5676 for (; iChar
< wParam
- 1; iChar
++)
5677 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5686 pdoc
->DeleteChars(0, pdoc
->Length());
5687 SetEmptySelection(0);
5688 const char *text
= CharPtrFromSPtr(lParam
);
5689 pdoc
->InsertString(0, text
, istrlen(text
));
5693 case SCI_GETTEXTLENGTH
:
5694 return pdoc
->Length();
5705 case SCI_COPYALLOWLINE
:
5709 case SCI_VERTICALCENTRECARET
:
5710 VerticalCentreCaret();
5713 case SCI_MOVESELECTEDLINESUP
:
5714 MoveSelectedLinesUp();
5717 case SCI_MOVESELECTEDLINESDOWN
:
5718 MoveSelectedLinesDown();
5722 CopyRangeToClipboard(static_cast<int>(wParam
), static_cast<int>(lParam
));
5726 CopyText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5731 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5734 EnsureCaretVisible();
5740 EnsureCaretVisible();
5749 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5751 case SCI_EMPTYUNDOBUFFER
:
5752 pdoc
->DeleteUndoHistory();
5755 case SCI_GETFIRSTVISIBLELINE
:
5758 case SCI_SETFIRSTVISIBLELINE
:
5759 ScrollTo(static_cast<int>(wParam
));
5762 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5763 int lineStart
= pdoc
->LineStart(static_cast<int>(wParam
));
5764 int lineEnd
= pdoc
->LineStart(static_cast<int>(wParam
+ 1));
5766 return lineEnd
- lineStart
;
5768 char *ptr
= CharPtrFromSPtr(lParam
);
5770 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5771 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5776 case SCI_GETLINECOUNT
:
5777 if (pdoc
->LinesTotal() == 0)
5780 return pdoc
->LinesTotal();
5783 return !pdoc
->IsSavePoint();
5786 int nStart
= static_cast<int>(wParam
);
5787 int nEnd
= static_cast<int>(lParam
);
5789 nEnd
= pdoc
->Length();
5791 nStart
= nEnd
; // Remove selection
5792 InvalidateSelection(SelectionRange(nStart
, nEnd
));
5794 sel
.selType
= Selection::selStream
;
5795 SetSelection(nEnd
, nStart
);
5796 EnsureCaretVisible();
5800 case SCI_GETSELTEXT
: {
5801 SelectionText selectedText
;
5802 CopySelectionRange(&selectedText
);
5804 return selectedText
.LengthWithTerminator();
5806 char *ptr
= CharPtrFromSPtr(lParam
);
5807 unsigned int iChar
= 0;
5808 if (selectedText
.Length()) {
5809 for (; iChar
< selectedText
.LengthWithTerminator(); iChar
++)
5810 ptr
[iChar
] = selectedText
.Data()[iChar
];
5818 case SCI_LINEFROMPOSITION
:
5819 if (static_cast<int>(wParam
) < 0)
5821 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
5823 case SCI_POSITIONFROMLINE
:
5824 if (static_cast<int>(wParam
) < 0)
5825 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
5827 return 0; // Even if there is no text, there is a first line that starts at 0
5828 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5830 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5832 return pdoc
->LineStart(static_cast<int>(wParam
));
5834 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5835 case SCI_LINELENGTH
:
5836 if ((static_cast<int>(wParam
) < 0) ||
5837 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5839 return pdoc
->LineStart(static_cast<int>(wParam
) + 1) - pdoc
->LineStart(static_cast<int>(wParam
));
5841 case SCI_REPLACESEL
: {
5846 char *replacement
= CharPtrFromSPtr(lParam
);
5847 const int lengthInserted
= pdoc
->InsertString(
5848 sel
.MainCaret(), replacement
, istrlen(replacement
));
5849 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5850 EnsureCaretVisible();
5854 case SCI_SETTARGETSTART
:
5855 targetStart
= static_cast<int>(wParam
);
5858 case SCI_GETTARGETSTART
:
5861 case SCI_SETTARGETEND
:
5862 targetEnd
= static_cast<int>(wParam
);
5865 case SCI_GETTARGETEND
:
5868 case SCI_SETTARGETRANGE
:
5869 targetStart
= static_cast<int>(wParam
);
5870 targetEnd
= static_cast<int>(lParam
);
5873 case SCI_TARGETWHOLEDOCUMENT
:
5875 targetEnd
= pdoc
->Length();
5878 case SCI_TARGETFROMSELECTION
:
5879 if (sel
.MainCaret() < sel
.MainAnchor()) {
5880 targetStart
= sel
.MainCaret();
5881 targetEnd
= sel
.MainAnchor();
5883 targetStart
= sel
.MainAnchor();
5884 targetEnd
= sel
.MainCaret();
5888 case SCI_GETTARGETTEXT
: {
5889 std::string text
= RangeText(targetStart
, targetEnd
);
5890 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(text
.c_str()), text
.length());
5893 case SCI_REPLACETARGET
:
5894 PLATFORM_ASSERT(lParam
);
5895 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5897 case SCI_REPLACETARGETRE
:
5898 PLATFORM_ASSERT(lParam
);
5899 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5901 case SCI_SEARCHINTARGET
:
5902 PLATFORM_ASSERT(lParam
);
5903 return SearchInTarget(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5905 case SCI_SETSEARCHFLAGS
:
5906 searchFlags
= static_cast<int>(wParam
);
5909 case SCI_GETSEARCHFLAGS
:
5913 return GetTag(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5915 case SCI_POSITIONBEFORE
:
5916 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) - 1, -1, true);
5918 case SCI_POSITIONAFTER
:
5919 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) + 1, 1, true);
5921 case SCI_POSITIONRELATIVE
:
5922 return Platform::Clamp(pdoc
->GetRelativePosition(static_cast<int>(wParam
), static_cast<int>(lParam
)), 0, pdoc
->Length());
5924 case SCI_LINESCROLL
:
5925 ScrollTo(topLine
+ static_cast<int>(lParam
));
5926 HorizontalScrollTo(xOffset
+ static_cast<int>(wParam
)* static_cast<int>(vs
.spaceWidth
));
5929 case SCI_SETXOFFSET
:
5930 xOffset
= static_cast<int>(wParam
);
5931 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
5932 SetHorizontalScrollPos();
5936 case SCI_GETXOFFSET
:
5939 case SCI_CHOOSECARETX
:
5943 case SCI_SCROLLCARET
:
5944 EnsureCaretVisible();
5947 case SCI_SETREADONLY
:
5948 pdoc
->SetReadOnly(wParam
!= 0);
5951 case SCI_GETREADONLY
:
5952 return pdoc
->IsReadOnly();
5957 case SCI_POINTXFROMPOSITION
:
5961 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5962 // Convert to view-relative
5963 return static_cast<int>(pt
.x
) - vs
.textStart
+ vs
.fixedColumnWidth
;
5966 case SCI_POINTYFROMPOSITION
:
5970 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5971 return static_cast<int>(pt
.y
);
5975 return FindText(wParam
, lParam
);
5977 case SCI_GETTEXTRANGE
: {
5980 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
5981 int cpMax
= static_cast<int>(tr
->chrg
.cpMax
);
5983 cpMax
= pdoc
->Length();
5984 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5985 int len
= static_cast<int>(cpMax
- tr
->chrg
.cpMin
); // No -1 as cpMin and cpMax are referring to inter character positions
5986 pdoc
->GetCharRange(tr
->lpstrText
, static_cast<int>(tr
->chrg
.cpMin
), len
);
5987 // Spec says copied text is terminated with a NUL
5988 tr
->lpstrText
[len
] = '\0';
5989 return len
; // Not including NUL
5992 case SCI_HIDESELECTION
:
5993 view
.hideSelection
= wParam
!= 0;
5997 case SCI_FORMATRANGE
:
5998 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
6000 case SCI_GETMARGINLEFT
:
6001 return vs
.leftMarginWidth
;
6003 case SCI_GETMARGINRIGHT
:
6004 return vs
.rightMarginWidth
;
6006 case SCI_SETMARGINLEFT
:
6007 lastXChosen
+= static_cast<int>(lParam
) - vs
.leftMarginWidth
;
6008 vs
.leftMarginWidth
= static_cast<int>(lParam
);
6009 InvalidateStyleRedraw();
6012 case SCI_SETMARGINRIGHT
:
6013 vs
.rightMarginWidth
= static_cast<int>(lParam
);
6014 InvalidateStyleRedraw();
6017 // Control specific mesages
6022 const int lengthInserted
= pdoc
->InsertString(
6023 CurrentPosition(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6024 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
6028 case SCI_ADDSTYLEDTEXT
:
6030 AddStyledText(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6033 case SCI_INSERTTEXT
: {
6036 int insertPos
= static_cast<int>(wParam
);
6037 if (static_cast<int>(wParam
) == -1)
6038 insertPos
= CurrentPosition();
6039 int newCurrent
= CurrentPosition();
6040 char *sz
= CharPtrFromSPtr(lParam
);
6041 const int lengthInserted
= pdoc
->InsertString(insertPos
, sz
, istrlen(sz
));
6042 if (newCurrent
> insertPos
)
6043 newCurrent
+= lengthInserted
;
6044 SetEmptySelection(newCurrent
);
6048 case SCI_CHANGEINSERTION
:
6049 PLATFORM_ASSERT(lParam
);
6050 pdoc
->ChangeInsertion(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6053 case SCI_APPENDTEXT
:
6054 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6061 case SCI_DELETERANGE
:
6062 pdoc
->DeleteChars(static_cast<int>(wParam
), static_cast<int>(lParam
));
6065 case SCI_CLEARDOCUMENTSTYLE
:
6066 ClearDocumentStyle();
6069 case SCI_SETUNDOCOLLECTION
:
6070 pdoc
->SetUndoCollection(wParam
!= 0);
6073 case SCI_GETUNDOCOLLECTION
:
6074 return pdoc
->IsCollectingUndo();
6076 case SCI_BEGINUNDOACTION
:
6077 pdoc
->BeginUndoAction();
6080 case SCI_ENDUNDOACTION
:
6081 pdoc
->EndUndoAction();
6084 case SCI_GETCARETPERIOD
:
6085 return caret
.period
;
6087 case SCI_SETCARETPERIOD
:
6088 CaretSetPeriod(static_cast<int>(wParam
));
6091 case SCI_GETWORDCHARS
:
6092 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
6094 case SCI_SETWORDCHARS
: {
6095 pdoc
->SetDefaultCharClasses(false);
6098 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6102 case SCI_GETWHITESPACECHARS
:
6103 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
6105 case SCI_SETWHITESPACECHARS
: {
6108 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6112 case SCI_GETPUNCTUATIONCHARS
:
6113 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
6115 case SCI_SETPUNCTUATIONCHARS
: {
6118 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
6122 case SCI_SETCHARSDEFAULT
:
6123 pdoc
->SetDefaultCharClasses(true);
6127 return pdoc
->Length();
6130 pdoc
->Allocate(static_cast<int>(wParam
));
6134 return pdoc
->CharAt(static_cast<int>(wParam
));
6136 case SCI_SETCURRENTPOS
:
6137 if (sel
.IsRectangular()) {
6138 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
6139 SetRectangularRange();
6142 SetSelection(static_cast<int>(wParam
), sel
.MainAnchor());
6146 case SCI_GETCURRENTPOS
:
6147 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
6150 if (sel
.IsRectangular()) {
6151 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
6152 SetRectangularRange();
6155 SetSelection(sel
.MainCaret(), static_cast<int>(wParam
));
6160 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
6162 case SCI_SETSELECTIONSTART
:
6163 SetSelection(Platform::Maximum(sel
.MainCaret(), static_cast<int>(wParam
)), static_cast<int>(wParam
));
6166 case SCI_GETSELECTIONSTART
:
6167 return sel
.LimitsForRectangularElseMain().start
.Position();
6169 case SCI_SETSELECTIONEND
:
6170 SetSelection(static_cast<int>(wParam
), Platform::Minimum(sel
.MainAnchor(), static_cast<int>(wParam
)));
6173 case SCI_GETSELECTIONEND
:
6174 return sel
.LimitsForRectangularElseMain().end
.Position();
6176 case SCI_SETEMPTYSELECTION
:
6177 SetEmptySelection(static_cast<int>(wParam
));
6180 case SCI_SETPRINTMAGNIFICATION
:
6181 view
.printParameters
.magnification
= static_cast<int>(wParam
);
6184 case SCI_GETPRINTMAGNIFICATION
:
6185 return view
.printParameters
.magnification
;
6187 case SCI_SETPRINTCOLOURMODE
:
6188 view
.printParameters
.colourMode
= static_cast<int>(wParam
);
6191 case SCI_GETPRINTCOLOURMODE
:
6192 return view
.printParameters
.colourMode
;
6194 case SCI_SETPRINTWRAPMODE
:
6195 view
.printParameters
.wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6198 case SCI_GETPRINTWRAPMODE
:
6199 return view
.printParameters
.wrapState
;
6201 case SCI_GETSTYLEAT
:
6202 if (static_cast<int>(wParam
) >= pdoc
->Length())
6205 return pdoc
->StyleAt(static_cast<int>(wParam
));
6215 case SCI_SETSAVEPOINT
:
6216 pdoc
->SetSavePoint();
6219 case SCI_GETSTYLEDTEXT
: {
6222 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6224 for (long iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6225 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(static_cast<int>(iChar
));
6226 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(static_cast<int>(iChar
));
6228 tr
->lpstrText
[iPlace
] = '\0';
6229 tr
->lpstrText
[iPlace
+ 1] = '\0';
6234 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6236 case SCI_MARKERLINEFROMHANDLE
:
6237 return pdoc
->LineFromHandle(static_cast<int>(wParam
));
6239 case SCI_MARKERDELETEHANDLE
:
6240 pdoc
->DeleteMarkFromHandle(static_cast<int>(wParam
));
6244 return vs
.viewWhitespace
;
6247 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6251 case SCI_GETWHITESPACESIZE
:
6252 return vs
.whitespaceSize
;
6254 case SCI_SETWHITESPACESIZE
:
6255 vs
.whitespaceSize
= static_cast<int>(wParam
);
6259 case SCI_POSITIONFROMPOINT
:
6260 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6263 case SCI_POSITIONFROMPOINTCLOSE
:
6264 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6267 case SCI_CHARPOSITIONFROMPOINT
:
6268 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6271 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
6272 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6276 GoToLine(static_cast<int>(wParam
));
6280 SetEmptySelection(static_cast<int>(wParam
));
6281 EnsureCaretVisible();
6284 case SCI_GETCURLINE
: {
6285 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
6286 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6287 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6289 return 1 + lineEnd
- lineStart
;
6291 PLATFORM_ASSERT(wParam
> 0);
6292 char *ptr
= CharPtrFromSPtr(lParam
);
6293 unsigned int iPlace
= 0;
6294 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6295 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6298 return sel
.MainCaret() - lineStart
;
6301 case SCI_GETENDSTYLED
:
6302 return pdoc
->GetEndStyled();
6304 case SCI_GETEOLMODE
:
6305 return pdoc
->eolMode
;
6307 case SCI_SETEOLMODE
:
6308 pdoc
->eolMode
= static_cast<int>(wParam
);
6311 case SCI_SETLINEENDTYPESALLOWED
:
6312 if (pdoc
->SetLineEndTypesAllowed(static_cast<int>(wParam
))) {
6314 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6315 SetAnnotationHeights(0, pdoc
->LinesTotal());
6316 InvalidateStyleRedraw();
6320 case SCI_GETLINEENDTYPESALLOWED
:
6321 return pdoc
->GetLineEndTypesAllowed();
6323 case SCI_GETLINEENDTYPESACTIVE
:
6324 return pdoc
->GetLineEndTypesActive();
6326 case SCI_STARTSTYLING
:
6327 pdoc
->StartStyling(static_cast<int>(wParam
), static_cast<char>(lParam
));
6330 case SCI_SETSTYLING
:
6331 if (static_cast<int>(wParam
) < 0)
6332 errorStatus
= SC_STATUS_FAILURE
;
6334 pdoc
->SetStyleFor(static_cast<int>(wParam
), static_cast<char>(lParam
));
6337 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6340 pdoc
->SetStyles(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6343 case SCI_SETBUFFEREDDRAW
:
6344 view
.bufferedDraw
= wParam
!= 0;
6347 case SCI_GETBUFFEREDDRAW
:
6348 return view
.bufferedDraw
;
6350 case SCI_GETTWOPHASEDRAW
:
6351 return view
.phasesDraw
== EditView::phasesTwo
;
6353 case SCI_SETTWOPHASEDRAW
:
6354 if (view
.SetTwoPhaseDraw(wParam
!= 0))
6355 InvalidateStyleRedraw();
6358 case SCI_GETPHASESDRAW
:
6359 return view
.phasesDraw
;
6361 case SCI_SETPHASESDRAW
:
6362 if (view
.SetPhasesDraw(static_cast<int>(wParam
)))
6363 InvalidateStyleRedraw();
6366 case SCI_SETFONTQUALITY
:
6367 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
6368 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
6369 InvalidateStyleRedraw();
6372 case SCI_GETFONTQUALITY
:
6373 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
6375 case SCI_SETTABWIDTH
:
6377 pdoc
->tabInChars
= static_cast<int>(wParam
);
6378 if (pdoc
->indentInChars
== 0)
6379 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6381 InvalidateStyleRedraw();
6384 case SCI_GETTABWIDTH
:
6385 return pdoc
->tabInChars
;
6387 case SCI_CLEARTABSTOPS
:
6388 if (view
.ClearTabstops(static_cast<int>(wParam
))) {
6389 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6390 NotifyModified(pdoc
, mh
, NULL
);
6394 case SCI_ADDTABSTOP
:
6395 if (view
.AddTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
))) {
6396 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6397 NotifyModified(pdoc
, mh
, NULL
);
6401 case SCI_GETNEXTTABSTOP
:
6402 return view
.GetNextTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
));
6405 pdoc
->indentInChars
= static_cast<int>(wParam
);
6406 if (pdoc
->indentInChars
!= 0)
6407 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6409 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6410 InvalidateStyleRedraw();
6414 return pdoc
->indentInChars
;
6416 case SCI_SETUSETABS
:
6417 pdoc
->useTabs
= wParam
!= 0;
6418 InvalidateStyleRedraw();
6421 case SCI_GETUSETABS
:
6422 return pdoc
->useTabs
;
6424 case SCI_SETLINEINDENTATION
:
6425 pdoc
->SetLineIndentation(static_cast<int>(wParam
), static_cast<int>(lParam
));
6428 case SCI_GETLINEINDENTATION
:
6429 return pdoc
->GetLineIndentation(static_cast<int>(wParam
));
6431 case SCI_GETLINEINDENTPOSITION
:
6432 return pdoc
->GetLineIndentPosition(static_cast<int>(wParam
));
6434 case SCI_SETTABINDENTS
:
6435 pdoc
->tabIndents
= wParam
!= 0;
6438 case SCI_GETTABINDENTS
:
6439 return pdoc
->tabIndents
;
6441 case SCI_SETBACKSPACEUNINDENTS
:
6442 pdoc
->backspaceUnindents
= wParam
!= 0;
6445 case SCI_GETBACKSPACEUNINDENTS
:
6446 return pdoc
->backspaceUnindents
;
6448 case SCI_SETMOUSEDWELLTIME
:
6449 dwellDelay
= static_cast<int>(wParam
);
6450 ticksToDwell
= dwellDelay
;
6453 case SCI_GETMOUSEDWELLTIME
:
6456 case SCI_WORDSTARTPOSITION
:
6457 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), -1, lParam
!= 0);
6459 case SCI_WORDENDPOSITION
:
6460 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), 1, lParam
!= 0);
6462 case SCI_ISRANGEWORD
:
6463 return pdoc
->IsWordAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
6465 case SCI_SETIDLESTYLING
:
6466 idleStyling
= static_cast<int>(wParam
);
6469 case SCI_GETIDLESTYLING
:
6472 case SCI_SETWRAPMODE
:
6473 if (vs
.SetWrapState(static_cast<int>(wParam
))) {
6475 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6476 InvalidateStyleRedraw();
6477 ReconfigureScrollBars();
6481 case SCI_GETWRAPMODE
:
6482 return vs
.wrapState
;
6484 case SCI_SETWRAPVISUALFLAGS
:
6485 if (vs
.SetWrapVisualFlags(static_cast<int>(wParam
))) {
6486 InvalidateStyleRedraw();
6487 ReconfigureScrollBars();
6491 case SCI_GETWRAPVISUALFLAGS
:
6492 return vs
.wrapVisualFlags
;
6494 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6495 if (vs
.SetWrapVisualFlagsLocation(static_cast<int>(wParam
))) {
6496 InvalidateStyleRedraw();
6500 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6501 return vs
.wrapVisualFlagsLocation
;
6503 case SCI_SETWRAPSTARTINDENT
:
6504 if (vs
.SetWrapVisualStartIndent(static_cast<int>(wParam
))) {
6505 InvalidateStyleRedraw();
6506 ReconfigureScrollBars();
6510 case SCI_GETWRAPSTARTINDENT
:
6511 return vs
.wrapVisualStartIndent
;
6513 case SCI_SETWRAPINDENTMODE
:
6514 if (vs
.SetWrapIndentMode(static_cast<int>(wParam
))) {
6515 InvalidateStyleRedraw();
6516 ReconfigureScrollBars();
6520 case SCI_GETWRAPINDENTMODE
:
6521 return vs
.wrapIndentMode
;
6523 case SCI_SETLAYOUTCACHE
:
6524 view
.llc
.SetLevel(static_cast<int>(wParam
));
6527 case SCI_GETLAYOUTCACHE
:
6528 return view
.llc
.GetLevel();
6530 case SCI_SETPOSITIONCACHE
:
6531 view
.posCache
.SetSize(wParam
);
6534 case SCI_GETPOSITIONCACHE
:
6535 return view
.posCache
.GetSize();
6537 case SCI_SETSCROLLWIDTH
:
6538 PLATFORM_ASSERT(wParam
> 0);
6539 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6540 view
.lineWidthMaxSeen
= 0;
6541 scrollWidth
= static_cast<int>(wParam
);
6546 case SCI_GETSCROLLWIDTH
:
6549 case SCI_SETSCROLLWIDTHTRACKING
:
6550 trackLineWidth
= wParam
!= 0;
6553 case SCI_GETSCROLLWIDTHTRACKING
:
6554 return trackLineWidth
;
6560 case SCI_LINESSPLIT
:
6561 LinesSplit(static_cast<int>(wParam
));
6565 PLATFORM_ASSERT(wParam
< vs
.styles
.size());
6566 PLATFORM_ASSERT(lParam
);
6567 return TextWidth(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6569 case SCI_TEXTHEIGHT
:
6571 return vs
.lineHeight
;
6573 case SCI_SETENDATLASTLINE
:
6574 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6575 if (endAtLastLine
!= (wParam
!= 0)) {
6576 endAtLastLine
= wParam
!= 0;
6581 case SCI_GETENDATLASTLINE
:
6582 return endAtLastLine
;
6584 case SCI_SETCARETSTICKY
:
6585 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
6586 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
6587 caretSticky
= static_cast<int>(wParam
);
6591 case SCI_GETCARETSTICKY
:
6594 case SCI_TOGGLECARETSTICKY
:
6595 caretSticky
= !caretSticky
;
6599 return pdoc
->GetColumn(static_cast<int>(wParam
));
6601 case SCI_FINDCOLUMN
:
6602 return pdoc
->FindColumn(static_cast<int>(wParam
), static_cast<int>(lParam
));
6604 case SCI_SETHSCROLLBAR
:
6605 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6606 horizontalScrollBarVisible
= wParam
!= 0;
6608 ReconfigureScrollBars();
6612 case SCI_GETHSCROLLBAR
:
6613 return horizontalScrollBarVisible
;
6615 case SCI_SETVSCROLLBAR
:
6616 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6617 verticalScrollBarVisible
= wParam
!= 0;
6619 ReconfigureScrollBars();
6620 if (verticalScrollBarVisible
)
6621 SetVerticalScrollPos();
6625 case SCI_GETVSCROLLBAR
:
6626 return verticalScrollBarVisible
;
6628 case SCI_SETINDENTATIONGUIDES
:
6629 vs
.viewIndentationGuides
= IndentView(wParam
);
6633 case SCI_GETINDENTATIONGUIDES
:
6634 return vs
.viewIndentationGuides
;
6636 case SCI_SETHIGHLIGHTGUIDE
:
6637 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6638 highlightGuideColumn
= static_cast<int>(wParam
);
6643 case SCI_GETHIGHLIGHTGUIDE
:
6644 return highlightGuideColumn
;
6646 case SCI_GETLINEENDPOSITION
:
6647 return pdoc
->LineEnd(static_cast<int>(wParam
));
6649 case SCI_SETCODEPAGE
:
6650 if (ValidCodePage(static_cast<int>(wParam
))) {
6651 if (pdoc
->SetDBCSCodePage(static_cast<int>(wParam
))) {
6653 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6654 SetAnnotationHeights(0, pdoc
->LinesTotal());
6655 InvalidateStyleRedraw();
6656 SetRepresentations();
6661 case SCI_GETCODEPAGE
:
6662 return pdoc
->dbcsCodePage
;
6664 case SCI_SETIMEINTERACTION
:
6665 imeInteraction
= static_cast<EditModel::IMEInteraction
>(wParam
);
6668 case SCI_GETIMEINTERACTION
:
6669 return imeInteraction
;
6671 #ifdef INCLUDE_DEPRECATED_FEATURES
6672 case SCI_SETUSEPALETTE
:
6673 InvalidateStyleRedraw();
6676 case SCI_GETUSEPALETTE
:
6680 // Marker definition and setting
6681 case SCI_MARKERDEFINE
:
6682 if (wParam
<= MARKER_MAX
) {
6683 vs
.markers
[wParam
].markType
= static_cast<int>(lParam
);
6684 vs
.CalcLargestMarkerHeight();
6686 InvalidateStyleData();
6690 case SCI_MARKERSYMBOLDEFINED
:
6691 if (wParam
<= MARKER_MAX
)
6692 return vs
.markers
[wParam
].markType
;
6696 case SCI_MARKERSETFORE
:
6697 if (wParam
<= MARKER_MAX
)
6698 vs
.markers
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6699 InvalidateStyleData();
6702 case SCI_MARKERSETBACKSELECTED
:
6703 if (wParam
<= MARKER_MAX
)
6704 vs
.markers
[wParam
].backSelected
= ColourDesired(static_cast<long>(lParam
));
6705 InvalidateStyleData();
6708 case SCI_MARKERENABLEHIGHLIGHT
:
6709 marginView
.highlightDelimiter
.isEnabled
= wParam
== 1;
6712 case SCI_MARKERSETBACK
:
6713 if (wParam
<= MARKER_MAX
)
6714 vs
.markers
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6715 InvalidateStyleData();
6718 case SCI_MARKERSETALPHA
:
6719 if (wParam
<= MARKER_MAX
)
6720 vs
.markers
[wParam
].alpha
= static_cast<int>(lParam
);
6721 InvalidateStyleRedraw();
6723 case SCI_MARKERADD
: {
6724 int markerID
= pdoc
->AddMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6727 case SCI_MARKERADDSET
:
6729 pdoc
->AddMarkSet(static_cast<int>(wParam
), static_cast<int>(lParam
));
6732 case SCI_MARKERDELETE
:
6733 pdoc
->DeleteMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6736 case SCI_MARKERDELETEALL
:
6737 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6741 return pdoc
->GetMark(static_cast<int>(wParam
));
6743 case SCI_MARKERNEXT
:
6744 return pdoc
->MarkerNext(static_cast<int>(wParam
), static_cast<int>(lParam
));
6746 case SCI_MARKERPREVIOUS
: {
6747 for (int iLine
= static_cast<int>(wParam
); iLine
>= 0; iLine
--) {
6748 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6754 case SCI_MARKERDEFINEPIXMAP
:
6755 if (wParam
<= MARKER_MAX
) {
6756 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6757 vs
.CalcLargestMarkerHeight();
6759 InvalidateStyleData();
6763 case SCI_RGBAIMAGESETWIDTH
:
6764 sizeRGBAImage
.x
= static_cast<XYPOSITION
>(wParam
);
6767 case SCI_RGBAIMAGESETHEIGHT
:
6768 sizeRGBAImage
.y
= static_cast<XYPOSITION
>(wParam
);
6771 case SCI_RGBAIMAGESETSCALE
:
6772 scaleRGBAImage
= static_cast<float>(wParam
);
6775 case SCI_MARKERDEFINERGBAIMAGE
:
6776 if (wParam
<= MARKER_MAX
) {
6777 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0f
, reinterpret_cast<unsigned char *>(lParam
));
6778 vs
.CalcLargestMarkerHeight();
6780 InvalidateStyleData();
6784 case SCI_SETMARGINTYPEN
:
6785 if (ValidMargin(wParam
)) {
6786 vs
.ms
[wParam
].style
= static_cast<int>(lParam
);
6787 InvalidateStyleRedraw();
6791 case SCI_GETMARGINTYPEN
:
6792 if (ValidMargin(wParam
))
6793 return vs
.ms
[wParam
].style
;
6797 case SCI_SETMARGINWIDTHN
:
6798 if (ValidMargin(wParam
)) {
6799 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6800 if (vs
.ms
[wParam
].width
!= lParam
) {
6801 lastXChosen
+= static_cast<int>(lParam
) - vs
.ms
[wParam
].width
;
6802 vs
.ms
[wParam
].width
= static_cast<int>(lParam
);
6803 InvalidateStyleRedraw();
6808 case SCI_GETMARGINWIDTHN
:
6809 if (ValidMargin(wParam
))
6810 return vs
.ms
[wParam
].width
;
6814 case SCI_SETMARGINMASKN
:
6815 if (ValidMargin(wParam
)) {
6816 vs
.ms
[wParam
].mask
= static_cast<int>(lParam
);
6817 InvalidateStyleRedraw();
6821 case SCI_GETMARGINMASKN
:
6822 if (ValidMargin(wParam
))
6823 return vs
.ms
[wParam
].mask
;
6827 case SCI_SETMARGINSENSITIVEN
:
6828 if (ValidMargin(wParam
)) {
6829 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6830 InvalidateStyleRedraw();
6834 case SCI_GETMARGINSENSITIVEN
:
6835 if (ValidMargin(wParam
))
6836 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6840 case SCI_SETMARGINCURSORN
:
6841 if (ValidMargin(wParam
))
6842 vs
.ms
[wParam
].cursor
= static_cast<int>(lParam
);
6845 case SCI_GETMARGINCURSORN
:
6846 if (ValidMargin(wParam
))
6847 return vs
.ms
[wParam
].cursor
;
6851 case SCI_STYLECLEARALL
:
6853 InvalidateStyleRedraw();
6856 case SCI_STYLESETFORE
:
6857 case SCI_STYLESETBACK
:
6858 case SCI_STYLESETBOLD
:
6859 case SCI_STYLESETWEIGHT
:
6860 case SCI_STYLESETITALIC
:
6861 case SCI_STYLESETEOLFILLED
:
6862 case SCI_STYLESETSIZE
:
6863 case SCI_STYLESETSIZEFRACTIONAL
:
6864 case SCI_STYLESETFONT
:
6865 case SCI_STYLESETUNDERLINE
:
6866 case SCI_STYLESETCASE
:
6867 case SCI_STYLESETCHARACTERSET
:
6868 case SCI_STYLESETVISIBLE
:
6869 case SCI_STYLESETCHANGEABLE
:
6870 case SCI_STYLESETHOTSPOT
:
6871 StyleSetMessage(iMessage
, wParam
, lParam
);
6874 case SCI_STYLEGETFORE
:
6875 case SCI_STYLEGETBACK
:
6876 case SCI_STYLEGETBOLD
:
6877 case SCI_STYLEGETWEIGHT
:
6878 case SCI_STYLEGETITALIC
:
6879 case SCI_STYLEGETEOLFILLED
:
6880 case SCI_STYLEGETSIZE
:
6881 case SCI_STYLEGETSIZEFRACTIONAL
:
6882 case SCI_STYLEGETFONT
:
6883 case SCI_STYLEGETUNDERLINE
:
6884 case SCI_STYLEGETCASE
:
6885 case SCI_STYLEGETCHARACTERSET
:
6886 case SCI_STYLEGETVISIBLE
:
6887 case SCI_STYLEGETCHANGEABLE
:
6888 case SCI_STYLEGETHOTSPOT
:
6889 return StyleGetMessage(iMessage
, wParam
, lParam
);
6891 case SCI_STYLERESETDEFAULT
:
6892 vs
.ResetDefaultStyle();
6893 InvalidateStyleRedraw();
6895 case SCI_SETSTYLEBITS
:
6896 vs
.EnsureStyle(0xff);
6899 case SCI_GETSTYLEBITS
:
6902 case SCI_SETLINESTATE
:
6903 return pdoc
->SetLineState(static_cast<int>(wParam
), static_cast<int>(lParam
));
6905 case SCI_GETLINESTATE
:
6906 return pdoc
->GetLineState(static_cast<int>(wParam
));
6908 case SCI_GETMAXLINESTATE
:
6909 return pdoc
->GetMaxLineState();
6911 case SCI_GETCARETLINEVISIBLE
:
6912 return vs
.showCaretLineBackground
;
6913 case SCI_SETCARETLINEVISIBLE
:
6914 vs
.showCaretLineBackground
= wParam
!= 0;
6915 InvalidateStyleRedraw();
6917 case SCI_GETCARETLINEVISIBLEALWAYS
:
6918 return vs
.alwaysShowCaretLineBackground
;
6919 case SCI_SETCARETLINEVISIBLEALWAYS
:
6920 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
6921 InvalidateStyleRedraw();
6924 case SCI_GETCARETLINEBACK
:
6925 return vs
.caretLineBackground
.AsLong();
6926 case SCI_SETCARETLINEBACK
:
6927 vs
.caretLineBackground
= static_cast<int>(wParam
);
6928 InvalidateStyleRedraw();
6930 case SCI_GETCARETLINEBACKALPHA
:
6931 return vs
.caretLineAlpha
;
6932 case SCI_SETCARETLINEBACKALPHA
:
6933 vs
.caretLineAlpha
= static_cast<int>(wParam
);
6934 InvalidateStyleRedraw();
6939 case SCI_VISIBLEFROMDOCLINE
:
6940 return cs
.DisplayFromDoc(static_cast<int>(wParam
));
6942 case SCI_DOCLINEFROMVISIBLE
:
6943 return cs
.DocFromDisplay(static_cast<int>(wParam
));
6946 return WrapCount(static_cast<int>(wParam
));
6948 case SCI_SETFOLDLEVEL
: {
6949 int prev
= pdoc
->SetLevel(static_cast<int>(wParam
), static_cast<int>(lParam
));
6950 if (prev
!= static_cast<int>(lParam
))
6955 case SCI_GETFOLDLEVEL
:
6956 return pdoc
->GetLevel(static_cast<int>(wParam
));
6958 case SCI_GETLASTCHILD
:
6959 return pdoc
->GetLastChild(static_cast<int>(wParam
), static_cast<int>(lParam
));
6961 case SCI_GETFOLDPARENT
:
6962 return pdoc
->GetFoldParent(static_cast<int>(wParam
));
6965 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), true);
6972 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), false);
6977 case SCI_GETLINEVISIBLE
:
6978 return cs
.GetVisible(static_cast<int>(wParam
));
6980 case SCI_GETALLLINESVISIBLE
:
6981 return cs
.HiddenLines() ? 0 : 1;
6983 case SCI_SETFOLDEXPANDED
:
6984 SetFoldExpanded(static_cast<int>(wParam
), lParam
!= 0);
6987 case SCI_GETFOLDEXPANDED
:
6988 return cs
.GetExpanded(static_cast<int>(wParam
));
6990 case SCI_SETAUTOMATICFOLD
:
6991 foldAutomatic
= static_cast<int>(wParam
);
6994 case SCI_GETAUTOMATICFOLD
:
6995 return foldAutomatic
;
6997 case SCI_SETFOLDFLAGS
:
6998 foldFlags
= static_cast<int>(wParam
);
7002 case SCI_TOGGLEFOLD
:
7003 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
7007 FoldLine(static_cast<int>(wParam
), static_cast<int>(lParam
));
7010 case SCI_FOLDCHILDREN
:
7011 FoldExpand(static_cast<int>(wParam
), static_cast<int>(lParam
), pdoc
->GetLevel(static_cast<int>(wParam
)));
7015 FoldAll(static_cast<int>(wParam
));
7018 case SCI_EXPANDCHILDREN
:
7019 FoldExpand(static_cast<int>(wParam
), SC_FOLDACTION_EXPAND
, static_cast<int>(lParam
));
7022 case SCI_CONTRACTEDFOLDNEXT
:
7023 return ContractedFoldNext(static_cast<int>(wParam
));
7025 case SCI_ENSUREVISIBLE
:
7026 EnsureLineVisible(static_cast<int>(wParam
), false);
7029 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
7030 EnsureLineVisible(static_cast<int>(wParam
), true);
7033 case SCI_SCROLLRANGE
:
7034 ScrollRange(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7037 case SCI_SEARCHANCHOR
:
7041 case SCI_SEARCHNEXT
:
7042 case SCI_SEARCHPREV
:
7043 return SearchText(iMessage
, wParam
, lParam
);
7045 case SCI_SETXCARETPOLICY
:
7046 caretXPolicy
= static_cast<int>(wParam
);
7047 caretXSlop
= static_cast<int>(lParam
);
7050 case SCI_SETYCARETPOLICY
:
7051 caretYPolicy
= static_cast<int>(wParam
);
7052 caretYSlop
= static_cast<int>(lParam
);
7055 case SCI_SETVISIBLEPOLICY
:
7056 visiblePolicy
= static_cast<int>(wParam
);
7057 visibleSlop
= static_cast<int>(lParam
);
7060 case SCI_LINESONSCREEN
:
7061 return LinesOnScreen();
7063 case SCI_SETSELFORE
:
7064 vs
.selColours
.fore
= ColourOptional(wParam
, lParam
);
7065 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(lParam
));
7066 InvalidateStyleRedraw();
7069 case SCI_SETSELBACK
:
7070 vs
.selColours
.back
= ColourOptional(wParam
, lParam
);
7071 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(lParam
));
7072 InvalidateStyleRedraw();
7075 case SCI_SETSELALPHA
:
7076 vs
.selAlpha
= static_cast<int>(wParam
);
7077 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7078 InvalidateStyleRedraw();
7081 case SCI_GETSELALPHA
:
7084 case SCI_GETSELEOLFILLED
:
7085 return vs
.selEOLFilled
;
7087 case SCI_SETSELEOLFILLED
:
7088 vs
.selEOLFilled
= wParam
!= 0;
7089 InvalidateStyleRedraw();
7092 case SCI_SETWHITESPACEFORE
:
7093 vs
.whitespaceColours
.fore
= ColourOptional(wParam
, lParam
);
7094 InvalidateStyleRedraw();
7097 case SCI_SETWHITESPACEBACK
:
7098 vs
.whitespaceColours
.back
= ColourOptional(wParam
, lParam
);
7099 InvalidateStyleRedraw();
7102 case SCI_SETCARETFORE
:
7103 vs
.caretcolour
= ColourDesired(static_cast<long>(wParam
));
7104 InvalidateStyleRedraw();
7107 case SCI_GETCARETFORE
:
7108 return vs
.caretcolour
.AsLong();
7110 case SCI_SETCARETSTYLE
:
7111 if (wParam
<= CARETSTYLE_BLOCK
)
7112 vs
.caretStyle
= static_cast<int>(wParam
);
7114 /* Default to the line caret */
7115 vs
.caretStyle
= CARETSTYLE_LINE
;
7116 InvalidateStyleRedraw();
7119 case SCI_GETCARETSTYLE
:
7120 return vs
.caretStyle
;
7122 case SCI_SETCARETWIDTH
:
7123 if (static_cast<int>(wParam
) <= 0)
7125 else if (wParam
>= 3)
7128 vs
.caretWidth
= static_cast<int>(wParam
);
7129 InvalidateStyleRedraw();
7132 case SCI_GETCARETWIDTH
:
7133 return vs
.caretWidth
;
7135 case SCI_ASSIGNCMDKEY
:
7136 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7137 Platform::HighShortFromLong(static_cast<long>(wParam
)), static_cast<unsigned int>(lParam
));
7140 case SCI_CLEARCMDKEY
:
7141 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7142 Platform::HighShortFromLong(static_cast<long>(wParam
)), SCI_NULL
);
7145 case SCI_CLEARALLCMDKEYS
:
7149 case SCI_INDICSETSTYLE
:
7150 if (wParam
<= INDIC_MAX
) {
7151 vs
.indicators
[wParam
].sacNormal
.style
= static_cast<int>(lParam
);
7152 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7153 InvalidateStyleRedraw();
7157 case SCI_INDICGETSTYLE
:
7158 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.style
: 0;
7160 case SCI_INDICSETFORE
:
7161 if (wParam
<= INDIC_MAX
) {
7162 vs
.indicators
[wParam
].sacNormal
.fore
= ColourDesired(static_cast<long>(lParam
));
7163 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7164 InvalidateStyleRedraw();
7168 case SCI_INDICGETFORE
:
7169 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.fore
.AsLong() : 0;
7171 case SCI_INDICSETHOVERSTYLE
:
7172 if (wParam
<= INDIC_MAX
) {
7173 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7174 InvalidateStyleRedraw();
7178 case SCI_INDICGETHOVERSTYLE
:
7179 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.style
: 0;
7181 case SCI_INDICSETHOVERFORE
:
7182 if (wParam
<= INDIC_MAX
) {
7183 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7184 InvalidateStyleRedraw();
7188 case SCI_INDICGETHOVERFORE
:
7189 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.fore
.AsLong() : 0;
7191 case SCI_INDICSETFLAGS
:
7192 if (wParam
<= INDIC_MAX
) {
7193 vs
.indicators
[wParam
].SetFlags(static_cast<int>(lParam
));
7194 InvalidateStyleRedraw();
7198 case SCI_INDICGETFLAGS
:
7199 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].Flags() : 0;
7201 case SCI_INDICSETUNDER
:
7202 if (wParam
<= INDIC_MAX
) {
7203 vs
.indicators
[wParam
].under
= lParam
!= 0;
7204 InvalidateStyleRedraw();
7208 case SCI_INDICGETUNDER
:
7209 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
7211 case SCI_INDICSETALPHA
:
7212 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7213 vs
.indicators
[wParam
].fillAlpha
= static_cast<int>(lParam
);
7214 InvalidateStyleRedraw();
7218 case SCI_INDICGETALPHA
:
7219 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
7221 case SCI_INDICSETOUTLINEALPHA
:
7222 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7223 vs
.indicators
[wParam
].outlineAlpha
= static_cast<int>(lParam
);
7224 InvalidateStyleRedraw();
7228 case SCI_INDICGETOUTLINEALPHA
:
7229 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
7231 case SCI_SETINDICATORCURRENT
:
7232 pdoc
->decorations
.SetCurrentIndicator(static_cast<int>(wParam
));
7234 case SCI_GETINDICATORCURRENT
:
7235 return pdoc
->decorations
.GetCurrentIndicator();
7236 case SCI_SETINDICATORVALUE
:
7237 pdoc
->decorations
.SetCurrentValue(static_cast<int>(wParam
));
7239 case SCI_GETINDICATORVALUE
:
7240 return pdoc
->decorations
.GetCurrentValue();
7242 case SCI_INDICATORFILLRANGE
:
7243 pdoc
->DecorationFillRange(static_cast<int>(wParam
), pdoc
->decorations
.GetCurrentValue(), static_cast<int>(lParam
));
7246 case SCI_INDICATORCLEARRANGE
:
7247 pdoc
->DecorationFillRange(static_cast<int>(wParam
), 0, static_cast<int>(lParam
));
7250 case SCI_INDICATORALLONFOR
:
7251 return pdoc
->decorations
.AllOnFor(static_cast<int>(wParam
));
7253 case SCI_INDICATORVALUEAT
:
7254 return pdoc
->decorations
.ValueAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
7256 case SCI_INDICATORSTART
:
7257 return pdoc
->decorations
.Start(static_cast<int>(wParam
), static_cast<int>(lParam
));
7259 case SCI_INDICATOREND
:
7260 return pdoc
->decorations
.End(static_cast<int>(wParam
), static_cast<int>(lParam
));
7263 case SCI_LINEDOWNEXTEND
:
7265 case SCI_PARADOWNEXTEND
:
7267 case SCI_LINEUPEXTEND
:
7269 case SCI_PARAUPEXTEND
:
7271 case SCI_CHARLEFTEXTEND
:
7273 case SCI_CHARRIGHTEXTEND
:
7275 case SCI_WORDLEFTEXTEND
:
7277 case SCI_WORDRIGHTEXTEND
:
7278 case SCI_WORDLEFTEND
:
7279 case SCI_WORDLEFTENDEXTEND
:
7280 case SCI_WORDRIGHTEND
:
7281 case SCI_WORDRIGHTENDEXTEND
:
7283 case SCI_HOMEEXTEND
:
7285 case SCI_LINEENDEXTEND
:
7287 case SCI_HOMEWRAPEXTEND
:
7288 case SCI_LINEENDWRAP
:
7289 case SCI_LINEENDWRAPEXTEND
:
7290 case SCI_DOCUMENTSTART
:
7291 case SCI_DOCUMENTSTARTEXTEND
:
7292 case SCI_DOCUMENTEND
:
7293 case SCI_DOCUMENTENDEXTEND
:
7294 case SCI_SCROLLTOSTART
:
7295 case SCI_SCROLLTOEND
:
7297 case SCI_STUTTEREDPAGEUP
:
7298 case SCI_STUTTEREDPAGEUPEXTEND
:
7299 case SCI_STUTTEREDPAGEDOWN
:
7300 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7303 case SCI_PAGEUPEXTEND
:
7305 case SCI_PAGEDOWNEXTEND
:
7306 case SCI_EDITTOGGLEOVERTYPE
:
7308 case SCI_DELETEBACK
:
7314 case SCI_VCHOMEEXTEND
:
7315 case SCI_VCHOMEWRAP
:
7316 case SCI_VCHOMEWRAPEXTEND
:
7317 case SCI_VCHOMEDISPLAY
:
7318 case SCI_VCHOMEDISPLAYEXTEND
:
7321 case SCI_DELWORDLEFT
:
7322 case SCI_DELWORDRIGHT
:
7323 case SCI_DELWORDRIGHTEND
:
7324 case SCI_DELLINELEFT
:
7325 case SCI_DELLINERIGHT
:
7328 case SCI_LINEDELETE
:
7329 case SCI_LINETRANSPOSE
:
7330 case SCI_LINEDUPLICATE
:
7333 case SCI_LINESCROLLDOWN
:
7334 case SCI_LINESCROLLUP
:
7335 case SCI_WORDPARTLEFT
:
7336 case SCI_WORDPARTLEFTEXTEND
:
7337 case SCI_WORDPARTRIGHT
:
7338 case SCI_WORDPARTRIGHTEXTEND
:
7339 case SCI_DELETEBACKNOTLINE
:
7340 case SCI_HOMEDISPLAY
:
7341 case SCI_HOMEDISPLAYEXTEND
:
7342 case SCI_LINEENDDISPLAY
:
7343 case SCI_LINEENDDISPLAYEXTEND
:
7344 case SCI_LINEDOWNRECTEXTEND
:
7345 case SCI_LINEUPRECTEXTEND
:
7346 case SCI_CHARLEFTRECTEXTEND
:
7347 case SCI_CHARRIGHTRECTEXTEND
:
7348 case SCI_HOMERECTEXTEND
:
7349 case SCI_VCHOMERECTEXTEND
:
7350 case SCI_LINEENDRECTEXTEND
:
7351 case SCI_PAGEUPRECTEXTEND
:
7352 case SCI_PAGEDOWNRECTEXTEND
:
7353 case SCI_SELECTIONDUPLICATE
:
7354 return KeyCommand(iMessage
);
7356 case SCI_BRACEHIGHLIGHT
:
7357 SetBraceHighlight(static_cast<int>(wParam
), static_cast<int>(lParam
), STYLE_BRACELIGHT
);
7360 case SCI_BRACEHIGHLIGHTINDICATOR
:
7361 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7362 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
7363 vs
.braceHighlightIndicator
= static_cast<int>(lParam
);
7367 case SCI_BRACEBADLIGHT
:
7368 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7371 case SCI_BRACEBADLIGHTINDICATOR
:
7372 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7373 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
7374 vs
.braceBadLightIndicator
= static_cast<int>(lParam
);
7378 case SCI_BRACEMATCH
:
7379 // wParam is position of char to find brace for,
7380 // lParam is maximum amount of text to restyle to find it
7381 return pdoc
->BraceMatch(static_cast<int>(wParam
), static_cast<int>(lParam
));
7383 case SCI_GETVIEWEOL
:
7386 case SCI_SETVIEWEOL
:
7387 vs
.viewEOL
= wParam
!= 0;
7388 InvalidateStyleRedraw();
7392 vs
.zoomLevel
= static_cast<int>(wParam
);
7393 InvalidateStyleRedraw();
7398 return vs
.zoomLevel
;
7400 case SCI_GETEDGECOLUMN
:
7403 case SCI_SETEDGECOLUMN
:
7404 vs
.theEdge
= static_cast<int>(wParam
);
7405 InvalidateStyleRedraw();
7408 case SCI_GETEDGEMODE
:
7409 return vs
.edgeState
;
7411 case SCI_SETEDGEMODE
:
7412 vs
.edgeState
= static_cast<int>(wParam
);
7413 InvalidateStyleRedraw();
7416 case SCI_GETEDGECOLOUR
:
7417 return vs
.edgecolour
.AsLong();
7419 case SCI_SETEDGECOLOUR
:
7420 vs
.edgecolour
= ColourDesired(static_cast<long>(wParam
));
7421 InvalidateStyleRedraw();
7424 case SCI_GETDOCPOINTER
:
7425 return reinterpret_cast<sptr_t
>(pdoc
);
7427 case SCI_SETDOCPOINTER
:
7429 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7432 case SCI_CREATEDOCUMENT
: {
7433 Document
*doc
= new Document();
7435 return reinterpret_cast<sptr_t
>(doc
);
7438 case SCI_ADDREFDOCUMENT
:
7439 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7442 case SCI_RELEASEDOCUMENT
:
7443 (reinterpret_cast<Document
*>(lParam
))->Release();
7446 case SCI_CREATELOADER
: {
7447 Document
*doc
= new Document();
7449 doc
->Allocate(static_cast<int>(wParam
));
7450 doc
->SetUndoCollection(false);
7451 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
7454 case SCI_SETMODEVENTMASK
:
7455 modEventMask
= static_cast<int>(wParam
);
7458 case SCI_GETMODEVENTMASK
:
7459 return modEventMask
;
7461 case SCI_CONVERTEOLS
:
7462 pdoc
->ConvertLineEnds(static_cast<int>(wParam
));
7463 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7466 case SCI_SETLENGTHFORENCODE
:
7467 lengthForEncode
= static_cast<int>(wParam
);
7470 case SCI_SELECTIONISRECTANGLE
:
7471 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7473 case SCI_SETSELECTIONMODE
: {
7476 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7477 sel
.selType
= Selection::selStream
;
7479 case SC_SEL_RECTANGLE
:
7480 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7481 sel
.selType
= Selection::selRectangle
;
7484 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7485 sel
.selType
= Selection::selLines
;
7488 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7489 sel
.selType
= Selection::selThin
;
7492 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7493 sel
.selType
= Selection::selStream
;
7495 InvalidateWholeSelection();
7498 case SCI_GETSELECTIONMODE
:
7499 switch (sel
.selType
) {
7500 case Selection::selStream
:
7501 return SC_SEL_STREAM
;
7502 case Selection::selRectangle
:
7503 return SC_SEL_RECTANGLE
;
7504 case Selection::selLines
:
7505 return SC_SEL_LINES
;
7506 case Selection::selThin
:
7509 return SC_SEL_STREAM
;
7511 case SCI_GETLINESELSTARTPOSITION
:
7512 case SCI_GETLINESELENDPOSITION
: {
7513 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(static_cast<int>(wParam
))),
7514 SelectionPosition(pdoc
->LineEnd(static_cast<int>(wParam
))));
7515 for (size_t r
=0; r
<sel
.Count(); r
++) {
7516 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7517 if (portion
.start
.IsValid()) {
7518 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
7521 return INVALID_POSITION
;
7524 case SCI_SETOVERTYPE
:
7525 inOverstrike
= wParam
!= 0;
7528 case SCI_GETOVERTYPE
:
7529 return inOverstrike
? 1 : 0;
7532 SetFocusState(wParam
!= 0);
7539 errorStatus
= static_cast<int>(wParam
);
7545 case SCI_SETMOUSEDOWNCAPTURES
:
7546 mouseDownCaptures
= wParam
!= 0;
7549 case SCI_GETMOUSEDOWNCAPTURES
:
7550 return mouseDownCaptures
;
7553 cursorMode
= static_cast<int>(wParam
);
7554 DisplayCursor(Window::cursorText
);
7560 case SCI_SETCONTROLCHARSYMBOL
:
7561 vs
.controlCharSymbol
= static_cast<int>(wParam
);
7562 InvalidateStyleRedraw();
7565 case SCI_GETCONTROLCHARSYMBOL
:
7566 return vs
.controlCharSymbol
;
7568 case SCI_SETREPRESENTATION
:
7569 reprs
.SetRepresentation(reinterpret_cast<const char *>(wParam
), CharPtrFromSPtr(lParam
));
7572 case SCI_GETREPRESENTATION
: {
7573 const Representation
*repr
= reprs
.RepresentationFromCharacter(
7574 reinterpret_cast<const char *>(wParam
), UTF8MaxBytes
);
7576 return StringResult(lParam
, repr
->stringRep
.c_str());
7581 case SCI_CLEARREPRESENTATION
:
7582 reprs
.ClearRepresentation(reinterpret_cast<const char *>(wParam
));
7585 case SCI_STARTRECORD
:
7586 recordingMacro
= true;
7589 case SCI_STOPRECORD
:
7590 recordingMacro
= false;
7593 case SCI_MOVECARETINSIDEVIEW
:
7594 MoveCaretInsideView();
7597 case SCI_SETFOLDMARGINCOLOUR
:
7598 vs
.foldmarginColour
= ColourOptional(wParam
, lParam
);
7599 InvalidateStyleRedraw();
7602 case SCI_SETFOLDMARGINHICOLOUR
:
7603 vs
.foldmarginHighlightColour
= ColourOptional(wParam
, lParam
);
7604 InvalidateStyleRedraw();
7607 case SCI_SETHOTSPOTACTIVEFORE
:
7608 vs
.hotspotColours
.fore
= ColourOptional(wParam
, lParam
);
7609 InvalidateStyleRedraw();
7612 case SCI_GETHOTSPOTACTIVEFORE
:
7613 return vs
.hotspotColours
.fore
.AsLong();
7615 case SCI_SETHOTSPOTACTIVEBACK
:
7616 vs
.hotspotColours
.back
= ColourOptional(wParam
, lParam
);
7617 InvalidateStyleRedraw();
7620 case SCI_GETHOTSPOTACTIVEBACK
:
7621 return vs
.hotspotColours
.back
.AsLong();
7623 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7624 vs
.hotspotUnderline
= wParam
!= 0;
7625 InvalidateStyleRedraw();
7628 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7629 return vs
.hotspotUnderline
? 1 : 0;
7631 case SCI_SETHOTSPOTSINGLELINE
:
7632 vs
.hotspotSingleLine
= wParam
!= 0;
7633 InvalidateStyleRedraw();
7636 case SCI_GETHOTSPOTSINGLELINE
:
7637 return vs
.hotspotSingleLine
? 1 : 0;
7639 case SCI_SETPASTECONVERTENDINGS
:
7640 convertPastes
= wParam
!= 0;
7643 case SCI_GETPASTECONVERTENDINGS
:
7644 return convertPastes
? 1 : 0;
7646 case SCI_GETCHARACTERPOINTER
:
7647 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
7649 case SCI_GETRANGEPOINTER
:
7650 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7652 case SCI_GETGAPPOSITION
:
7653 return pdoc
->GapPosition();
7655 case SCI_SETEXTRAASCENT
:
7656 vs
.extraAscent
= static_cast<int>(wParam
);
7657 InvalidateStyleRedraw();
7660 case SCI_GETEXTRAASCENT
:
7661 return vs
.extraAscent
;
7663 case SCI_SETEXTRADESCENT
:
7664 vs
.extraDescent
= static_cast<int>(wParam
);
7665 InvalidateStyleRedraw();
7668 case SCI_GETEXTRADESCENT
:
7669 return vs
.extraDescent
;
7671 case SCI_MARGINSETSTYLEOFFSET
:
7672 vs
.marginStyleOffset
= static_cast<int>(wParam
);
7673 InvalidateStyleRedraw();
7676 case SCI_MARGINGETSTYLEOFFSET
:
7677 return vs
.marginStyleOffset
;
7679 case SCI_SETMARGINOPTIONS
:
7680 marginOptions
= static_cast<int>(wParam
);
7683 case SCI_GETMARGINOPTIONS
:
7684 return marginOptions
;
7686 case SCI_MARGINSETTEXT
:
7687 pdoc
->MarginSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7690 case SCI_MARGINGETTEXT
: {
7691 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7692 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7695 case SCI_MARGINSETSTYLE
:
7696 pdoc
->MarginSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7699 case SCI_MARGINGETSTYLE
: {
7700 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7704 case SCI_MARGINSETSTYLES
:
7705 pdoc
->MarginSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7708 case SCI_MARGINGETSTYLES
: {
7709 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7710 return BytesResult(lParam
, st
.styles
, st
.length
);
7713 case SCI_MARGINTEXTCLEARALL
:
7714 pdoc
->MarginClearAll();
7717 case SCI_ANNOTATIONSETTEXT
:
7718 pdoc
->AnnotationSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7721 case SCI_ANNOTATIONGETTEXT
: {
7722 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7723 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7726 case SCI_ANNOTATIONGETSTYLE
: {
7727 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7731 case SCI_ANNOTATIONSETSTYLE
:
7732 pdoc
->AnnotationSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7735 case SCI_ANNOTATIONSETSTYLES
:
7736 pdoc
->AnnotationSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7739 case SCI_ANNOTATIONGETSTYLES
: {
7740 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7741 return BytesResult(lParam
, st
.styles
, st
.length
);
7744 case SCI_ANNOTATIONGETLINES
:
7745 return pdoc
->AnnotationLines(static_cast<int>(wParam
));
7747 case SCI_ANNOTATIONCLEARALL
:
7748 pdoc
->AnnotationClearAll();
7751 case SCI_ANNOTATIONSETVISIBLE
:
7752 SetAnnotationVisible(static_cast<int>(wParam
));
7755 case SCI_ANNOTATIONGETVISIBLE
:
7756 return vs
.annotationVisible
;
7758 case SCI_ANNOTATIONSETSTYLEOFFSET
:
7759 vs
.annotationStyleOffset
= static_cast<int>(wParam
);
7760 InvalidateStyleRedraw();
7763 case SCI_ANNOTATIONGETSTYLEOFFSET
:
7764 return vs
.annotationStyleOffset
;
7766 case SCI_RELEASEALLEXTENDEDSTYLES
:
7767 vs
.ReleaseAllExtendedStyles();
7770 case SCI_ALLOCATEEXTENDEDSTYLES
:
7771 return vs
.AllocateExtendedStyles(static_cast<int>(wParam
));
7773 case SCI_ADDUNDOACTION
:
7774 pdoc
->AddUndoAction(static_cast<int>(wParam
), lParam
& UNDO_MAY_COALESCE
);
7777 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH
:
7778 mouseSelectionRectangularSwitch
= wParam
!= 0;
7781 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH
:
7782 return mouseSelectionRectangularSwitch
;
7784 case SCI_SETMULTIPLESELECTION
:
7785 multipleSelection
= wParam
!= 0;
7789 case SCI_GETMULTIPLESELECTION
:
7790 return multipleSelection
;
7792 case SCI_SETADDITIONALSELECTIONTYPING
:
7793 additionalSelectionTyping
= wParam
!= 0;
7797 case SCI_GETADDITIONALSELECTIONTYPING
:
7798 return additionalSelectionTyping
;
7800 case SCI_SETMULTIPASTE
:
7801 multiPasteMode
= static_cast<int>(wParam
);
7804 case SCI_GETMULTIPASTE
:
7805 return multiPasteMode
;
7807 case SCI_SETADDITIONALCARETSBLINK
:
7808 view
.additionalCaretsBlink
= wParam
!= 0;
7812 case SCI_GETADDITIONALCARETSBLINK
:
7813 return view
.additionalCaretsBlink
;
7815 case SCI_SETADDITIONALCARETSVISIBLE
:
7816 view
.additionalCaretsVisible
= wParam
!= 0;
7820 case SCI_GETADDITIONALCARETSVISIBLE
:
7821 return view
.additionalCaretsVisible
;
7823 case SCI_GETSELECTIONS
:
7826 case SCI_GETSELECTIONEMPTY
:
7829 case SCI_CLEARSELECTIONS
:
7831 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7835 case SCI_SETSELECTION
:
7836 sel
.SetSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7840 case SCI_ADDSELECTION
:
7841 sel
.AddSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7842 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7846 case SCI_DROPSELECTIONN
:
7847 sel
.DropSelection(static_cast<int>(wParam
));
7848 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7852 case SCI_SETMAINSELECTION
:
7853 sel
.SetMain(static_cast<int>(wParam
));
7854 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7858 case SCI_GETMAINSELECTION
:
7861 case SCI_SETSELECTIONNCARET
:
7862 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7863 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7867 case SCI_GETSELECTIONNCARET
:
7868 return sel
.Range(wParam
).caret
.Position();
7870 case SCI_SETSELECTIONNANCHOR
:
7871 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7872 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7875 case SCI_GETSELECTIONNANCHOR
:
7876 return sel
.Range(wParam
).anchor
.Position();
7878 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
7879 sel
.Range(wParam
).caret
.SetVirtualSpace(static_cast<int>(lParam
));
7880 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7884 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
7885 return sel
.Range(wParam
).caret
.VirtualSpace();
7887 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
7888 sel
.Range(wParam
).anchor
.SetVirtualSpace(static_cast<int>(lParam
));
7889 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7893 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
7894 return sel
.Range(wParam
).anchor
.VirtualSpace();
7896 case SCI_SETSELECTIONNSTART
:
7897 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7898 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7902 case SCI_GETSELECTIONNSTART
:
7903 return sel
.Range(wParam
).Start().Position();
7905 case SCI_SETSELECTIONNEND
:
7906 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7907 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7911 case SCI_GETSELECTIONNEND
:
7912 return sel
.Range(wParam
).End().Position();
7914 case SCI_SETRECTANGULARSELECTIONCARET
:
7915 if (!sel
.IsRectangular())
7917 sel
.selType
= Selection::selRectangle
;
7918 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
7919 SetRectangularRange();
7923 case SCI_GETRECTANGULARSELECTIONCARET
:
7924 return sel
.Rectangular().caret
.Position();
7926 case SCI_SETRECTANGULARSELECTIONANCHOR
:
7927 if (!sel
.IsRectangular())
7929 sel
.selType
= Selection::selRectangle
;
7930 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
7931 SetRectangularRange();
7935 case SCI_GETRECTANGULARSELECTIONANCHOR
:
7936 return sel
.Rectangular().anchor
.Position();
7938 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7939 if (!sel
.IsRectangular())
7941 sel
.selType
= Selection::selRectangle
;
7942 sel
.Rectangular().caret
.SetVirtualSpace(static_cast<int>(wParam
));
7943 SetRectangularRange();
7947 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7948 return sel
.Rectangular().caret
.VirtualSpace();
7950 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7951 if (!sel
.IsRectangular())
7953 sel
.selType
= Selection::selRectangle
;
7954 sel
.Rectangular().anchor
.SetVirtualSpace(static_cast<int>(wParam
));
7955 SetRectangularRange();
7959 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7960 return sel
.Rectangular().anchor
.VirtualSpace();
7962 case SCI_SETVIRTUALSPACEOPTIONS
:
7963 virtualSpaceOptions
= static_cast<int>(wParam
);
7966 case SCI_GETVIRTUALSPACEOPTIONS
:
7967 return virtualSpaceOptions
;
7969 case SCI_SETADDITIONALSELFORE
:
7970 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(wParam
));
7971 InvalidateStyleRedraw();
7974 case SCI_SETADDITIONALSELBACK
:
7975 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(wParam
));
7976 InvalidateStyleRedraw();
7979 case SCI_SETADDITIONALSELALPHA
:
7980 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7981 InvalidateStyleRedraw();
7984 case SCI_GETADDITIONALSELALPHA
:
7985 return vs
.selAdditionalAlpha
;
7987 case SCI_SETADDITIONALCARETFORE
:
7988 vs
.additionalCaretColour
= ColourDesired(static_cast<long>(wParam
));
7989 InvalidateStyleRedraw();
7992 case SCI_GETADDITIONALCARETFORE
:
7993 return vs
.additionalCaretColour
.AsLong();
7995 case SCI_ROTATESELECTION
:
7997 InvalidateWholeSelection();
8000 case SCI_SWAPMAINANCHORCARET
:
8001 InvalidateSelection(sel
.RangeMain());
8002 sel
.RangeMain().Swap();
8005 case SCI_MULTIPLESELECTADDNEXT
:
8006 MultipleSelectAdd(addOne
);
8009 case SCI_MULTIPLESELECTADDEACH
:
8010 MultipleSelectAdd(addEach
);
8013 case SCI_CHANGELEXERSTATE
:
8014 pdoc
->ChangeLexerState(static_cast<int>(wParam
), static_cast<int>(lParam
));
8017 case SCI_SETIDENTIFIER
:
8018 SetCtrlID(static_cast<int>(wParam
));
8021 case SCI_GETIDENTIFIER
:
8024 case SCI_SETTECHNOLOGY
:
8025 // No action by default
8028 case SCI_GETTECHNOLOGY
:
8031 case SCI_COUNTCHARACTERS
:
8032 return pdoc
->CountCharacters(static_cast<int>(wParam
), static_cast<int>(lParam
));
8035 return DefWndProc(iMessage
, wParam
, lParam
);
8037 //Platform::DebugPrintf("end wnd proc\n");