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 {
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();
834 SetHoverIndicatorPosition(sel
.MainCaret());
835 QueueIdleWork(WorkNeeded::workUpdateUI
);
837 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
842 void Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
843 const SelectionPosition spCaret
= ((sel
.Count() == 1) && sel
.Empty()) ?
844 sel
.Last() : SelectionPosition(INVALID_POSITION
);
846 int delta
= newPos
.Position() - sel
.MainCaret();
847 newPos
= ClampPositionIntoDocument(newPos
);
848 newPos
= MovePositionOutsideChar(newPos
, delta
);
849 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
850 // Can't turn into multiple selection so clear additional selections
851 InvalidateSelection(SelectionRange(newPos
), true);
852 sel
.DropAdditionalRanges();
854 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
855 // Switching to rectangular
856 InvalidateSelection(sel
.RangeMain(), false);
857 SelectionRange rangeMain
= sel
.RangeMain();
859 sel
.Rectangular() = rangeMain
;
861 if (selt
!= Selection::noSel
) {
864 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
865 SetSelection(newPos
);
867 SetEmptySelection(newPos
);
870 MovedCaret(newPos
, spCaret
, ensureVisible
);
873 void Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
874 MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
877 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
878 pos
= ClampPositionIntoDocument(pos
);
879 pos
= MovePositionOutsideChar(pos
, moveDir
);
880 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
881 if (cs
.GetVisible(lineDoc
)) {
884 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
886 // lineDisplay is already line before fold as lines in fold use display line of line after fold
887 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
888 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
890 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
891 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
896 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
897 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
900 Point
Editor::PointMainCaret() {
901 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
905 * Choose the x position that the caret will try to stick to
906 * as it moves up and down.
908 void Editor::SetLastXChosen() {
909 Point pt
= PointMainCaret();
910 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
913 void Editor::ScrollTo(int line
, bool moveThumb
) {
914 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
915 if (topLineNew
!= topLine
) {
916 // Try to optimise small scrolls
918 int linesToMove
= topLine
- topLineNew
;
919 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
920 willRedrawAll
= !performBlit
;
922 SetTopLine(topLineNew
);
923 // Optimize by styling the view as this will invalidate any needed area
924 // which could abort the initial paint if discovered later.
925 StyleAreaBounded(GetClientRectangle(), true);
927 // Perform redraw rather than scroll if many lines would be redrawn anyway.
929 ScrollText(linesToMove
);
933 willRedrawAll
= false;
938 SetVerticalScrollPos();
943 void Editor::ScrollText(int /* linesToMove */) {
944 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
948 void Editor::HorizontalScrollTo(int xPos
) {
949 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
952 if (!Wrapping() && (xOffset
!= xPos
)) {
954 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
955 SetHorizontalScrollPos();
956 RedrawRect(GetClientRectangle());
960 void Editor::VerticalCentreCaret() {
961 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
962 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
963 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
964 if (topLine
!= newTop
) {
965 SetTopLine(newTop
> 0 ? newTop
: 0);
966 RedrawRect(GetClientRectangle());
970 // Avoid 64 bit compiler warnings.
971 // Scintilla does not support text buffers larger than 2**31
972 static int istrlen(const char *s
) {
973 return static_cast<int>(s
? strlen(s
) : 0);
976 void Editor::MoveSelectedLines(int lineDelta
) {
978 // if selection doesn't start at the beginning of the line, set the new start
979 int selectionStart
= SelectionStart().Position();
980 int startLine
= pdoc
->LineFromPosition(selectionStart
);
981 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
982 selectionStart
= beginningOfStartLine
;
984 // if selection doesn't end at the beginning of a line greater than that of the start,
985 // then set it at the beginning of the next one
986 int selectionEnd
= SelectionEnd().Position();
987 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
988 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
989 bool appendEol
= false;
990 if (selectionEnd
> beginningOfEndLine
991 || selectionStart
== selectionEnd
) {
992 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
993 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
996 // if there's nowhere for the selection to move
997 // (i.e. at the beginning going up or at the end going down),
998 // stop it right there!
999 if ((selectionStart
== 0 && lineDelta
< 0)
1000 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
1001 || selectionStart
== selectionEnd
) {
1007 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
1008 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
1010 selectionEnd
= CurrentPosition();
1012 SetSelection(selectionStart
, selectionEnd
);
1014 SelectionText selectedText
;
1015 CopySelectionRange(&selectedText
);
1017 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
1018 Point currentLocation
= LocationFromPosition(CurrentPosition());
1019 int currentLine
= LineFromLocation(currentLocation
);
1022 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
1025 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1026 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
1027 pdoc
->InsertString(pdoc
->Length(), eol
, istrlen(eol
));
1028 GoToLine(currentLine
+ lineDelta
);
1030 selectionLength
= pdoc
->InsertString(CurrentPosition(), selectedText
.Data(), selectionLength
);
1032 const int lengthInserted
= pdoc
->InsertString(CurrentPosition() + selectionLength
, eol
, istrlen(eol
));
1033 selectionLength
+= lengthInserted
;
1035 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
1038 void Editor::MoveSelectedLinesUp() {
1039 MoveSelectedLines(-1);
1042 void Editor::MoveSelectedLinesDown() {
1043 MoveSelectedLines(1);
1046 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1047 PRectangle rcClient
= GetTextRectangle();
1048 Point pt
= PointMainCaret();
1049 if (pt
.y
< rcClient
.top
) {
1050 MovePositionTo(SPositionFromLocation(
1051 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
)),
1052 false, false, UserVirtualSpace()),
1053 Selection::noSel
, ensureVisible
);
1054 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1055 int yOfLastLineFullyDisplayed
= static_cast<int>(rcClient
.top
) + (LinesOnScreen() - 1) * vs
.lineHeight
;
1056 MovePositionTo(SPositionFromLocation(
1057 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
) + yOfLastLineFullyDisplayed
),
1058 false, false, UserVirtualSpace()),
1059 Selection::noSel
, ensureVisible
);
1063 int Editor::DisplayFromPosition(int pos
) {
1064 AutoSurface
surface(this);
1065 return view
.DisplayFromPosition(surface
, *this, pos
, vs
);
1069 * Ensure the caret is reasonably visible in context.
1071 Caret policy in SciTE
1073 If slop is set, we can define a slop value.
1074 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1075 This zone is defined as a number of pixels near the vertical margins,
1076 and as a number of lines near the horizontal margins.
1077 By keeping the caret away from the edges, it is seen within its context,
1078 so it is likely that the identifier that the caret is on can be completely seen,
1079 and that the current line is seen with some of the lines following it which are
1080 often dependent on that line.
1082 If strict is set, the policy is enforced... strictly.
1083 The caret is centred on the display if slop is not set,
1084 and cannot go in the UZ if slop is set.
1086 If jumps is set, the display is moved more energetically
1087 so the caret can move in the same direction longer before the policy is applied again.
1088 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1090 If even is not set, instead of having symmetrical UZs,
1091 the left and bottom UZs are extended up to right and top UZs respectively.
1092 This way, we favour the displaying of useful information: the beginning of lines,
1093 where most code reside, and the lines after the caret, eg. the body of a function.
1096 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1097 | | | | | visibility or going into the UZ) display is...
1098 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1099 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1100 0 | 0 | 0 | 1 | Yes | moved by one position
1101 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1102 0 | 0 | 1 | 1 | Yes | centred on the caret
1103 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1104 0 | 1 | - | 1 | No, caret is always centred | -
1105 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1106 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1107 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1108 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1109 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1110 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1111 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1114 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const SelectionRange
&range
, const XYScrollOptions options
) {
1115 PRectangle rcClient
= GetTextRectangle();
1116 Point pt
= LocationFromPosition(range
.caret
);
1117 Point ptAnchor
= LocationFromPosition(range
.anchor
);
1118 const Point ptOrigin
= GetVisibleOriginInMain();
1121 ptAnchor
.x
+= ptOrigin
.x
;
1122 ptAnchor
.y
+= ptOrigin
.y
;
1123 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1125 XYScrollPosition
newXY(xOffset
, topLine
);
1126 if (rcClient
.Empty()) {
1130 // Vertical positioning
1131 if ((options
& xysVertical
) && (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1132 const int lineCaret
= DisplayFromPosition(range
.caret
.Position());
1133 const int linesOnScreen
= LinesOnScreen();
1134 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1135 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1136 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1137 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1138 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1140 // It should be possible to scroll the window to show the caret,
1141 // but this fails to remove the caret on GTK+
1142 if (bSlop
) { // A margin is defined
1145 int yMarginT
, yMarginB
;
1146 if (!(options
& xysUseMargin
)) {
1147 // In drag mode, avoid moves
1148 // otherwise, a double click will select several lines.
1149 yMarginT
= yMarginB
= 0;
1151 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1152 // a maximum of slightly less than half the heigth of the text area.
1153 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1155 yMarginB
= yMarginT
;
1157 yMarginB
= linesOnScreen
- yMarginT
- 1;
1163 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1167 yMoveB
= linesOnScreen
- yMoveT
- 1;
1169 if (lineCaret
< topLine
+ yMarginT
) {
1170 // Caret goes too high
1171 newXY
.topLine
= lineCaret
- yMoveT
;
1172 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1173 // Caret goes too low
1174 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1176 } else { // Not strict
1177 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1178 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1182 yMoveB
= linesOnScreen
- yMoveT
- 1;
1184 if (lineCaret
< topLine
) {
1185 // Caret goes too high
1186 newXY
.topLine
= lineCaret
- yMoveT
;
1187 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1188 // Caret goes too low
1189 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1193 if (!bStrict
&& !bJump
) {
1195 if (lineCaret
< topLine
) {
1196 // Caret goes too high
1197 newXY
.topLine
= lineCaret
;
1198 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1199 // Caret goes too low
1201 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1203 newXY
.topLine
= lineCaret
;
1206 } else { // Strict or going out of display
1208 // Always center caret
1209 newXY
.topLine
= lineCaret
- halfScreen
;
1211 // Always put caret on top of display
1212 newXY
.topLine
= lineCaret
;
1216 if (!(range
.caret
== range
.anchor
)) {
1217 const int lineAnchor
= DisplayFromPosition(range
.anchor
.Position());
1218 if (lineAnchor
< lineCaret
) {
1219 // Shift up to show anchor or as much of range as possible
1220 newXY
.topLine
= std::min(newXY
.topLine
, lineAnchor
);
1221 newXY
.topLine
= std::max(newXY
.topLine
, lineCaret
- LinesOnScreen());
1223 // Shift down to show anchor or as much of range as possible
1224 newXY
.topLine
= std::max(newXY
.topLine
, lineAnchor
- LinesOnScreen());
1225 newXY
.topLine
= std::min(newXY
.topLine
, lineCaret
);
1228 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1231 // Horizontal positioning
1232 if ((options
& xysHorizontal
) && !Wrapping()) {
1233 const int halfScreen
= Platform::Maximum(static_cast<int>(rcClient
.Width()) - 4, 4) / 2;
1234 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1235 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1236 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1237 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1239 if (bSlop
) { // A margin is defined
1242 int xMarginL
, xMarginR
;
1243 if (!(options
& xysUseMargin
)) {
1244 // In drag mode, avoid moves unless very near of the margin
1245 // otherwise, a simple click will select text.
1246 xMarginL
= xMarginR
= 2;
1248 // xMargin must equal to caretXSlop, with a minimum of 2 and
1249 // a maximum of slightly less than half the width of the text area.
1250 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1252 xMarginL
= xMarginR
;
1254 xMarginL
= static_cast<int>(rcClient
.Width()) - xMarginR
- 4;
1257 if (bJump
&& bEven
) {
1258 // Jump is used only in even mode
1259 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1261 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1263 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1264 // Caret is on the left of the display
1265 if (bJump
&& bEven
) {
1266 newXY
.xOffset
-= xMoveL
;
1268 // Move just enough to allow to display the caret
1269 newXY
.xOffset
-= static_cast<int>((rcClient
.left
+ xMarginL
) - pt
.x
);
1271 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1272 // Caret is on the right of the display
1273 if (bJump
&& bEven
) {
1274 newXY
.xOffset
+= xMoveR
;
1276 // Move just enough to allow to display the caret
1277 newXY
.xOffset
+= static_cast<int>(pt
.x
- (rcClient
.right
- xMarginR
) + 1);
1280 } else { // Not strict
1281 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1282 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1286 xMoveL
= static_cast<int>(rcClient
.Width()) - xMoveR
- 4;
1288 if (pt
.x
< rcClient
.left
) {
1289 // Caret is on the left of the display
1290 newXY
.xOffset
-= xMoveL
;
1291 } else if (pt
.x
>= rcClient
.right
) {
1292 // Caret is on the right of the display
1293 newXY
.xOffset
+= xMoveR
;
1298 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1299 // Strict or going out of display
1302 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.left
- halfScreen
);
1304 // Put caret on right
1305 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
+ 1);
1308 // Move just enough to allow to display the caret
1309 if (pt
.x
< rcClient
.left
) {
1310 // Caret is on the left of the display
1312 newXY
.xOffset
-= static_cast<int>(rcClient
.left
- pt
.x
);
1314 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1316 } else if (pt
.x
>= rcClient
.right
) {
1317 // Caret is on the right of the display
1318 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1322 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1323 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1324 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 2;
1325 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1326 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 2;
1327 if ((vs
.caretStyle
== CARETSTYLE_BLOCK
) || view
.imeCaretBlockOverride
) {
1328 // Ensure we can see a good portion of the block caret
1329 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1332 if (!(range
.caret
== range
.anchor
)) {
1333 if (ptAnchor
.x
< pt
.x
) {
1334 // Shift to left to show anchor or as much of range as possible
1335 int maxOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.left
) - 1;
1336 int minOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 1;
1337 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1338 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1340 // Shift to right to show anchor or as much of range as possible
1341 int minOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.right
) + 1;
1342 int maxOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 1;
1343 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1344 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1347 if (newXY
.xOffset
< 0) {
1355 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1356 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1357 if (newXY
.topLine
!= topLine
) {
1358 SetTopLine(newXY
.topLine
);
1359 SetVerticalScrollPos();
1361 if (newXY
.xOffset
!= xOffset
) {
1362 xOffset
= newXY
.xOffset
;
1363 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1364 if (newXY
.xOffset
> 0) {
1365 PRectangle rcText
= GetTextRectangle();
1366 if (horizontalScrollBarVisible
&&
1367 rcText
.Width() + xOffset
> scrollWidth
) {
1368 scrollWidth
= xOffset
+ static_cast<int>(rcText
.Width());
1372 SetHorizontalScrollPos();
1375 UpdateSystemCaret();
1379 void Editor::ScrollRange(SelectionRange range
) {
1380 SetXYScroll(XYScrollToMakeVisible(range
, xysDefault
));
1383 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1384 SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
),
1385 static_cast<XYScrollOptions
>((useMargin
?xysUseMargin
:0)|(vert
?xysVertical
:0)|(horiz
?xysHorizontal
:0))));
1388 void Editor::ShowCaretAtCurrentPosition() {
1390 caret
.active
= true;
1392 if (FineTickerAvailable()) {
1393 FineTickerCancel(tickCaret
);
1394 if (caret
.period
> 0)
1395 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1400 caret
.active
= false;
1402 if (FineTickerAvailable()) {
1403 FineTickerCancel(tickCaret
);
1409 void Editor::DropCaret() {
1410 caret
.active
= false;
1411 if (FineTickerAvailable()) {
1412 FineTickerCancel(tickCaret
);
1417 void Editor::CaretSetPeriod(int period
) {
1418 if (caret
.period
!= period
) {
1419 caret
.period
= period
;
1421 if (FineTickerAvailable()) {
1422 FineTickerCancel(tickCaret
);
1423 if ((caret
.active
) && (caret
.period
> 0))
1424 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1430 void Editor::InvalidateCaret() {
1431 if (posDrag
.IsValid()) {
1432 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1434 for (size_t r
=0; r
<sel
.Count(); r
++) {
1435 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1438 UpdateSystemCaret();
1441 void Editor::NotifyCaretMove() {
1444 void Editor::UpdateSystemCaret() {
1447 bool Editor::Wrapping() const {
1448 return vs
.wrapState
!= eWrapNone
;
1451 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1452 //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd);
1453 if (wrapPending
.AddRange(docLineStart
, docLineEnd
)) {
1454 view
.llc
.Invalidate(LineLayout::llPositions
);
1456 // Wrap lines during idle.
1457 if (Wrapping() && wrapPending
.NeedsWrap()) {
1462 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1463 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(lineToWrap
, *this));
1464 int linesWrapped
= 1;
1466 view
.LayoutLine(*this, lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1467 linesWrapped
= ll
->lines
;
1469 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1470 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1473 // Perform wrapping for a subset of the lines needing wrapping.
1474 // wsAll: wrap all lines which need wrapping in this single call
1475 // wsVisible: wrap currently visible lines
1476 // wsIdle: wrap one page + 100 lines
1477 // Return true if wrapping occurred.
1478 bool Editor::WrapLines(enum wrapScope ws
) {
1479 int goodTopLine
= topLine
;
1480 bool wrapOccurred
= false;
1482 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1483 wrapWidth
= LineLayout::wrapWidthInfinite
;
1484 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1485 cs
.SetHeight(lineDoc
, 1 +
1486 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1488 wrapOccurred
= true;
1490 wrapPending
.Reset();
1492 } else if (wrapPending
.NeedsWrap()) {
1493 wrapPending
.start
= std::min(wrapPending
.start
, pdoc
->LinesTotal());
1494 if (!SetIdle(true)) {
1495 // Idle processing not supported so full wrap required.
1498 // Decide where to start wrapping
1499 int lineToWrap
= wrapPending
.start
;
1500 int lineToWrapEnd
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1501 const int lineDocTop
= cs
.DocFromDisplay(topLine
);
1502 const int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1503 if (ws
== wsVisible
) {
1504 lineToWrap
= Platform::Clamp(lineDocTop
-5, wrapPending
.start
, pdoc
->LinesTotal());
1505 // Priority wrap to just after visible area.
1506 // Since wrapping could reduce display lines, treat each
1507 // as taking only one display line.
1508 lineToWrapEnd
= lineDocTop
;
1509 int lines
= LinesOnScreen() + 1;
1510 while ((lineToWrapEnd
< cs
.LinesInDoc()) && (lines
>0)) {
1511 if (cs
.GetVisible(lineToWrapEnd
))
1515 // .. and if the paint window is outside pending wraps
1516 if ((lineToWrap
> wrapPending
.end
) || (lineToWrapEnd
< wrapPending
.start
)) {
1517 // Currently visible text does not need wrapping
1520 } else if (ws
== wsIdle
) {
1521 lineToWrapEnd
= lineToWrap
+ LinesOnScreen() + 100;
1523 const int lineEndNeedWrap
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1524 lineToWrapEnd
= std::min(lineToWrapEnd
, lineEndNeedWrap
);
1526 // Ensure all lines being wrapped are styled.
1527 pdoc
->EnsureStyledTo(pdoc
->LineStart(lineToWrapEnd
));
1529 if (lineToWrap
< lineToWrapEnd
) {
1531 PRectangle rcTextArea
= GetClientRectangle();
1532 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1533 rcTextArea
.right
-= vs
.rightMarginWidth
;
1534 wrapWidth
= static_cast<int>(rcTextArea
.Width());
1536 AutoSurface
surface(this);
1538 //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd);
1540 while (lineToWrap
< lineToWrapEnd
) {
1541 if (WrapOneLine(surface
, lineToWrap
)) {
1542 wrapOccurred
= true;
1544 wrapPending
.Wrapped(lineToWrap
);
1548 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
) + std::min(subLineTop
, cs
.GetHeight(lineDocTop
)-1);
1552 // If wrapping is done, bring it to resting position
1553 if (wrapPending
.start
>= lineEndNeedWrap
) {
1554 wrapPending
.Reset();
1560 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1561 SetVerticalScrollPos();
1564 return wrapOccurred
;
1567 void Editor::LinesJoin() {
1568 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1570 bool prevNonWS
= true;
1571 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1572 if (pdoc
->IsPositionInLineEnd(pos
)) {
1573 targetEnd
-= pdoc
->LenChar(pos
);
1576 // Ensure at least one space separating previous lines
1577 const int lengthInserted
= pdoc
->InsertString(pos
, " ", 1);
1578 targetEnd
+= lengthInserted
;
1581 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1587 const char *Editor::StringFromEOLMode(int eolMode
) {
1588 if (eolMode
== SC_EOL_CRLF
) {
1590 } else if (eolMode
== SC_EOL_CR
) {
1597 void Editor::LinesSplit(int pixelWidth
) {
1598 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1599 if (pixelWidth
== 0) {
1600 PRectangle rcText
= GetTextRectangle();
1601 pixelWidth
= static_cast<int>(rcText
.Width());
1603 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1604 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1605 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1607 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1608 AutoSurface
surface(this);
1609 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
1610 if (surface
&& ll
) {
1611 unsigned int posLineStart
= pdoc
->LineStart(line
);
1612 view
.LayoutLine(*this, line
, surface
, vs
, ll
, pixelWidth
);
1613 int lengthInsertedTotal
= 0;
1614 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1615 const int lengthInserted
= pdoc
->InsertString(
1616 static_cast<int>(posLineStart
+ lengthInsertedTotal
+
1617 ll
->LineStart(subLine
)),
1619 targetEnd
+= lengthInserted
;
1620 lengthInsertedTotal
+= lengthInserted
;
1623 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1628 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1629 if (vs
.fixedColumnWidth
== 0)
1634 RefreshPixMaps(surfWindow
);
1636 // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished
1637 // at this point. The Initialised call checks for this case and sets the status
1638 // to be bad which avoids crashes in following calls.
1639 if (!surfWindow
->Initialised()) {
1643 PRectangle rcMargin
= GetClientRectangle();
1644 Point ptOrigin
= GetVisibleOriginInMain();
1645 rcMargin
.Move(0, -ptOrigin
.y
);
1647 rcMargin
.right
= static_cast<XYPOSITION
>(vs
.fixedColumnWidth
);
1649 if (!rc
.Intersects(rcMargin
))
1653 if (view
.bufferedDraw
) {
1654 surface
= marginView
.pixmapSelMargin
;
1656 surface
= surfWindow
;
1659 // Clip vertically to paint area to avoid drawing line numbers
1660 if (rcMargin
.bottom
> rc
.bottom
)
1661 rcMargin
.bottom
= rc
.bottom
;
1662 if (rcMargin
.top
< rc
.top
)
1663 rcMargin
.top
= rc
.top
;
1665 marginView
.PaintMargin(surface
, topLine
, rc
, rcMargin
, *this, vs
);
1667 if (view
.bufferedDraw
) {
1668 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *marginView
.pixmapSelMargin
);
1672 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
1673 view
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1674 marginView
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1675 if (view
.bufferedDraw
) {
1676 PRectangle rcClient
= GetClientRectangle();
1677 if (!view
.pixmapLine
->Initialised()) {
1679 view
.pixmapLine
->InitPixMap(static_cast<int>(rcClient
.Width()), vs
.lineHeight
,
1680 surfaceWindow
, wMain
.GetID());
1682 if (!marginView
.pixmapSelMargin
->Initialised()) {
1683 marginView
.pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1684 static_cast<int>(rcClient
.Height()), surfaceWindow
, wMain
.GetID());
1689 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1690 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1691 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1695 if (paintState
== paintAbandoned
)
1696 return; // Scroll bars may have changed so need redraw
1697 RefreshPixMaps(surfaceWindow
);
1699 paintAbandonedByStyling
= false;
1701 StyleAreaBounded(rcArea
, false);
1703 PRectangle rcClient
= GetClientRectangle();
1704 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1705 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1707 if (NotifyUpdateUI()) {
1709 RefreshPixMaps(surfaceWindow
);
1712 // Wrap the visible lines if needed.
1713 if (WrapLines(wsVisible
)) {
1714 // The wrapping process has changed the height of some lines so
1715 // abandon this paint for a complete repaint.
1716 if (AbandonPaint()) {
1719 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
1721 PLATFORM_ASSERT(marginView
.pixmapSelPattern
->Initialised());
1723 if (!view
.bufferedDraw
)
1724 surfaceWindow
->SetClip(rcArea
);
1726 if (paintState
!= paintAbandoned
) {
1727 if (vs
.marginInside
) {
1728 PaintSelMargin(surfaceWindow
, rcArea
);
1729 PRectangle rcRightMargin
= rcClient
;
1730 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1731 if (rcArea
.Intersects(rcRightMargin
)) {
1732 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1734 } else { // Else separate view so separate paint event but leftMargin included to allow overlap
1735 PRectangle rcLeftMargin
= rcArea
;
1736 rcLeftMargin
.left
= 0;
1737 rcLeftMargin
.right
= rcLeftMargin
.left
+ vs
.leftMarginWidth
;
1738 if (rcArea
.Intersects(rcLeftMargin
)) {
1739 surfaceWindow
->FillRectangle(rcLeftMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1744 if (paintState
== paintAbandoned
) {
1745 // Either styling or NotifyUpdateUI noticed that painting is needed
1746 // outside the current painting rectangle
1747 //Platform::DebugPrintf("Abandoning paint\n");
1749 if (paintAbandonedByStyling
) {
1750 // Styling has spilled over a line end, such as occurs by starting a multiline
1751 // comment. The width of subsequent text may have changed, so rewrap.
1752 NeedWrapping(cs
.DocFromDisplay(topLine
));
1758 view
.PaintText(surfaceWindow
, *this, rcArea
, rcClient
, vs
);
1760 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
1761 if (FineTickerAvailable()) {
1762 scrollWidth
= view
.lineWidthMaxSeen
;
1763 if (!FineTickerRunning(tickWiden
)) {
1764 FineTickerStart(tickWiden
, 50, 5);
1772 // This is mostly copied from the Paint method but with some things omitted
1773 // such as the margin markers, line numbers, selection and caret
1774 // Should be merged back into a combined Draw method.
1775 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
1779 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
1782 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
1783 if (!surfaceMeasure
) {
1786 return view
.FormatRange(draw
, pfr
, surface
, surfaceMeasure
, *this, vs
);
1789 int Editor::TextWidth(int style
, const char *text
) {
1791 AutoSurface
surface(this);
1793 return static_cast<int>(surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
)));
1799 // Empty method is overridden on GTK+ to show / hide scrollbars
1800 void Editor::ReconfigureScrollBars() {}
1802 void Editor::SetScrollBars() {
1805 int nMax
= MaxScrollPos();
1806 int nPage
= LinesOnScreen();
1807 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
1812 // TODO: ensure always showing as many lines as possible
1813 // May not be, if, for example, window made larger
1814 if (topLine
> MaxScrollPos()) {
1815 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1816 SetVerticalScrollPos();
1820 if (!AbandonPaint())
1823 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1826 void Editor::ChangeSize() {
1827 DropGraphics(false);
1830 PRectangle rcTextArea
= GetClientRectangle();
1831 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1832 rcTextArea
.right
-= vs
.rightMarginWidth
;
1833 if (wrapWidth
!= rcTextArea
.Width()) {
1840 int Editor::RealizeVirtualSpace(int position
, unsigned int virtualSpace
) {
1841 if (virtualSpace
> 0) {
1842 const int line
= pdoc
->LineFromPosition(position
);
1843 const int indent
= pdoc
->GetLineIndentPosition(line
);
1844 if (indent
== position
) {
1845 return pdoc
->SetLineIndentation(line
, pdoc
->GetLineIndentation(line
) + virtualSpace
);
1847 std::string
spaceText(virtualSpace
, ' ');
1848 const int lengthInserted
= pdoc
->InsertString(position
, spaceText
.c_str(), virtualSpace
);
1849 position
+= lengthInserted
;
1855 SelectionPosition
Editor::RealizeVirtualSpace(const SelectionPosition
&position
) {
1856 // Return the new position with no virtual space
1857 return SelectionPosition(RealizeVirtualSpace(position
.Position(), position
.VirtualSpace()));
1860 void Editor::AddChar(char ch
) {
1867 void Editor::FilterSelections() {
1868 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
1869 InvalidateWholeSelection();
1870 sel
.DropAdditionalRanges();
1874 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
1878 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
1879 void Editor::AddCharUTF(const char *s
, unsigned int len
, bool treatAsDBCS
) {
1882 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1884 // Vector elements point into selection in order to change selection.
1885 std::vector
<SelectionRange
*> selPtrs
;
1886 for (size_t r
= 0; r
< sel
.Count(); r
++) {
1887 selPtrs
.push_back(&sel
.Range(r
));
1889 // Order selections by position in document.
1890 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
1892 // Loop in reverse to avoid disturbing positions of selections yet to be processed.
1893 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
1894 rit
!= selPtrs
.rend(); ++rit
) {
1895 SelectionRange
*currentSel
= *rit
;
1896 if (!RangeContainsProtected(currentSel
->Start().Position(),
1897 currentSel
->End().Position())) {
1898 int positionInsert
= currentSel
->Start().Position();
1899 if (!currentSel
->Empty()) {
1900 if (currentSel
->Length()) {
1901 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
1902 currentSel
->ClearVirtualSpace();
1904 // Range is all virtual so collapse to start of virtual space
1905 currentSel
->MinimizeVirtualSpace();
1907 } else if (inOverstrike
) {
1908 if (positionInsert
< pdoc
->Length()) {
1909 if (!pdoc
->IsPositionInLineEnd(positionInsert
)) {
1910 pdoc
->DelChar(positionInsert
);
1911 currentSel
->ClearVirtualSpace();
1915 positionInsert
= RealizeVirtualSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
1916 const int lengthInserted
= pdoc
->InsertString(positionInsert
, s
, len
);
1917 if (lengthInserted
> 0) {
1918 currentSel
->caret
.SetPosition(positionInsert
+ lengthInserted
);
1919 currentSel
->anchor
.SetPosition(positionInsert
+ lengthInserted
);
1921 currentSel
->ClearVirtualSpace();
1922 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1924 AutoSurface
surface(this);
1926 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
1928 SetVerticalScrollPos();
1939 ThinRectangularRange();
1940 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1941 EnsureCaretVisible();
1942 // Avoid blinking during rapid typing:
1943 ShowCaretAtCurrentPosition();
1944 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
1945 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
1950 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
1951 static_cast<unsigned char>(s
[1]));
1952 } else if (len
> 0) {
1953 int byte
= static_cast<unsigned char>(s
[0]);
1954 if ((byte
< 0xC0) || (1 == len
)) {
1955 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1956 // characters when not in UTF-8 mode.
1957 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1958 // characters representing themselves.
1960 unsigned int utf32
[1] = { 0 };
1961 UTF32FromUTF8(s
, len
, utf32
, ELEMENTS(utf32
));
1967 if (recordingMacro
) {
1968 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
1972 void Editor::ClearBeforeTentativeStart() {
1973 // Make positions for the first composition string.
1975 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1976 for (size_t r
= 0; r
<sel
.Count(); r
++) {
1977 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1978 sel
.Range(r
).End().Position())) {
1979 int positionInsert
= sel
.Range(r
).Start().Position();
1980 if (!sel
.Range(r
).Empty()) {
1981 if (sel
.Range(r
).Length()) {
1982 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1983 sel
.Range(r
).ClearVirtualSpace();
1985 // Range is all virtual so collapse to start of virtual space
1986 sel
.Range(r
).MinimizeVirtualSpace();
1989 RealizeVirtualSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
1990 sel
.Range(r
).ClearVirtualSpace();
1995 void Editor::InsertPaste(const char *text
, int len
) {
1996 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
1997 SelectionPosition selStart
= sel
.Start();
1998 selStart
= RealizeVirtualSpace(selStart
);
1999 const int lengthInserted
= pdoc
->InsertString(selStart
.Position(), text
, len
);
2000 if (lengthInserted
> 0) {
2001 SetEmptySelection(selStart
.Position() + lengthInserted
);
2004 // SC_MULTIPASTE_EACH
2005 for (size_t r
=0; r
<sel
.Count(); r
++) {
2006 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
2007 sel
.Range(r
).End().Position())) {
2008 int positionInsert
= sel
.Range(r
).Start().Position();
2009 if (!sel
.Range(r
).Empty()) {
2010 if (sel
.Range(r
).Length()) {
2011 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
2012 sel
.Range(r
).ClearVirtualSpace();
2014 // Range is all virtual so collapse to start of virtual space
2015 sel
.Range(r
).MinimizeVirtualSpace();
2018 positionInsert
= RealizeVirtualSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
2019 const int lengthInserted
= pdoc
->InsertString(positionInsert
, text
, len
);
2020 if (lengthInserted
> 0) {
2021 sel
.Range(r
).caret
.SetPosition(positionInsert
+ lengthInserted
);
2022 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ lengthInserted
);
2024 sel
.Range(r
).ClearVirtualSpace();
2030 void Editor::InsertPasteShape(const char *text
, int len
, PasteShape shape
) {
2031 std::string convertedText
;
2032 if (convertPastes
) {
2033 // Convert line endings of the paste into our local line-endings mode
2034 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
2035 len
= static_cast<int>(convertedText
.length());
2036 text
= convertedText
.c_str();
2038 if (shape
== pasteRectangular
) {
2039 PasteRectangular(sel
.Start(), text
, len
);
2041 if (shape
== pasteLine
) {
2042 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
2043 int lengthInserted
= pdoc
->InsertString(insertPos
, text
, len
);
2044 // add the newline if necessary
2045 if ((len
> 0) && (text
[len
- 1] != '\n' && text
[len
- 1] != '\r')) {
2046 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
2047 int length
= static_cast<int>(strlen(endline
));
2048 lengthInserted
+= pdoc
->InsertString(insertPos
+ lengthInserted
, endline
, length
);
2050 if (sel
.MainCaret() == insertPos
) {
2051 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
2054 InsertPaste(text
, len
);
2059 void Editor::ClearSelection(bool retainMultipleSelections
) {
2060 if (!sel
.IsRectangular() && !retainMultipleSelections
)
2063 for (size_t r
=0; r
<sel
.Count(); r
++) {
2064 if (!sel
.Range(r
).Empty()) {
2065 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
2066 sel
.Range(r
).End().Position())) {
2067 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
2068 sel
.Range(r
).Length());
2069 sel
.Range(r
) = SelectionRange(sel
.Range(r
).Start());
2073 ThinRectangularRange();
2074 sel
.RemoveDuplicates();
2076 SetHoverIndicatorPosition(sel
.MainCaret());
2079 void Editor::ClearAll() {
2082 if (0 != pdoc
->Length()) {
2083 pdoc
->DeleteChars(0, pdoc
->Length());
2085 if (!pdoc
->IsReadOnly()) {
2087 pdoc
->AnnotationClearAll();
2088 pdoc
->MarginClearAll();
2092 view
.ClearAllTabstops();
2096 SetVerticalScrollPos();
2097 InvalidateStyleRedraw();
2100 void Editor::ClearDocumentStyle() {
2101 Decoration
*deco
= pdoc
->decorations
.root
;
2103 // Save next in case deco deleted
2104 Decoration
*decoNext
= deco
->next
;
2105 if (deco
->indicator
< INDIC_CONTAINER
) {
2106 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
2107 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
2111 pdoc
->StartStyling(0, '\377');
2112 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2114 SetAnnotationHeights(0, pdoc
->LinesTotal());
2115 pdoc
->ClearLevels();
2118 void Editor::CopyAllowLine() {
2119 SelectionText selectedText
;
2120 CopySelectionRange(&selectedText
, true);
2121 CopyToClipboard(selectedText
);
2124 void Editor::Cut() {
2125 pdoc
->CheckReadOnly();
2126 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2132 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
2133 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2137 sel
.RangeMain() = SelectionRange(pos
);
2138 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2140 sel
.RangeMain().caret
= RealizeVirtualSpace(sel
.RangeMain().caret
);
2141 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
2142 bool prevCr
= false;
2143 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
2145 for (int i
= 0; i
< len
; i
++) {
2146 if (IsEOLChar(ptr
[i
])) {
2147 if ((ptr
[i
] == '\r') || (!prevCr
))
2149 if (line
>= pdoc
->LinesTotal()) {
2150 if (pdoc
->eolMode
!= SC_EOL_LF
)
2151 pdoc
->InsertString(pdoc
->Length(), "\r", 1);
2152 if (pdoc
->eolMode
!= SC_EOL_CR
)
2153 pdoc
->InsertString(pdoc
->Length(), "\n", 1);
2155 // Pad the end of lines with spaces if required
2156 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
2157 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
2158 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
2160 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), " ", 1);
2161 sel
.RangeMain().caret
.Add(lengthInserted
);
2164 prevCr
= ptr
[i
] == '\r';
2166 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
2167 sel
.RangeMain().caret
.Add(lengthInserted
);
2171 SetEmptySelection(pos
);
2174 bool Editor::CanPaste() {
2175 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
2178 void Editor::Clear() {
2179 // If multiple selections, don't delete EOLS
2181 bool singleVirtual
= false;
2182 if ((sel
.Count() == 1) &&
2183 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
2184 sel
.RangeMain().Start().VirtualSpace()) {
2185 singleVirtual
= true;
2187 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
2188 for (size_t r
=0; r
<sel
.Count(); r
++) {
2189 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
2190 if (sel
.Range(r
).Start().VirtualSpace()) {
2191 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
2192 sel
.Range(r
) = SelectionRange(RealizeVirtualSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
2194 sel
.Range(r
) = SelectionRange(RealizeVirtualSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
2196 if ((sel
.Count() == 1) || !pdoc
->IsPositionInLineEnd(sel
.Range(r
).caret
.Position())) {
2197 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
2198 sel
.Range(r
).ClearVirtualSpace();
2199 } // else multiple selection so don't eat line ends
2201 sel
.Range(r
).ClearVirtualSpace();
2207 sel
.RemoveDuplicates();
2208 ShowCaretAtCurrentPosition(); // Avoid blinking
2211 void Editor::SelectAll() {
2213 SetSelection(0, pdoc
->Length());
2217 void Editor::Undo() {
2218 if (pdoc
->CanUndo()) {
2220 int newPos
= pdoc
->Undo();
2222 SetEmptySelection(newPos
);
2223 EnsureCaretVisible();
2227 void Editor::Redo() {
2228 if (pdoc
->CanRedo()) {
2229 int newPos
= pdoc
->Redo();
2231 SetEmptySelection(newPos
);
2232 EnsureCaretVisible();
2236 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2238 if (!sel
.IsRectangular())
2240 if (sel
.IsRectangular())
2241 allowLineStartDeletion
= false;
2242 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
2244 for (size_t r
=0; r
<sel
.Count(); r
++) {
2245 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
2246 if (sel
.Range(r
).caret
.VirtualSpace()) {
2247 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
2248 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
2250 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2251 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
2252 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2253 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
2254 UndoGroup
ugInner(pdoc
, !ug
.Needed());
2255 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2256 int indentationStep
= pdoc
->IndentSize();
2257 int indentationChange
= indentation
% indentationStep
;
2258 if (indentationChange
== 0)
2259 indentationChange
= indentationStep
;
2260 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationChange
);
2261 // SetEmptySelection
2262 sel
.Range(r
) = SelectionRange(posSelect
);
2264 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
2269 sel
.Range(r
).ClearVirtualSpace();
2272 ThinRectangularRange();
2276 sel
.RemoveDuplicates();
2277 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
2278 // Avoid blinking during rapid typing:
2279 ShowCaretAtCurrentPosition();
2282 int Editor::ModifierFlags(bool shift
, bool ctrl
, bool alt
, bool meta
, bool super
) {
2284 (shift
? SCI_SHIFT
: 0) |
2285 (ctrl
? SCI_CTRL
: 0) |
2286 (alt
? SCI_ALT
: 0) |
2287 (meta
? SCI_META
: 0) |
2288 (super
? SCI_SUPER
: 0);
2291 void Editor::NotifyFocus(bool focus
) {
2292 SCNotification scn
= {};
2293 scn
.nmhdr
.code
= focus
? SCN_FOCUSIN
: SCN_FOCUSOUT
;
2297 void Editor::SetCtrlID(int identifier
) {
2298 ctrlID
= identifier
;
2301 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2302 SCNotification scn
= {};
2303 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2304 scn
.position
= endStyleNeeded
;
2308 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2309 NotifyStyleToNeeded(endStyleNeeded
);
2312 void Editor::NotifyLexerChanged(Document
*, void *) {
2315 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
2316 errorStatus
= status
;
2319 void Editor::NotifyChar(int ch
) {
2320 SCNotification scn
= {};
2321 scn
.nmhdr
.code
= SCN_CHARADDED
;
2326 void Editor::NotifySavePoint(bool isSavePoint
) {
2327 SCNotification scn
= {};
2329 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2331 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2336 void Editor::NotifyModifyAttempt() {
2337 SCNotification scn
= {};
2338 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2342 void Editor::NotifyDoubleClick(Point pt
, int modifiers
) {
2343 SCNotification scn
= {};
2344 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2345 scn
.line
= LineFromLocation(pt
);
2346 scn
.position
= PositionFromLocation(pt
, true);
2347 scn
.modifiers
= modifiers
;
2351 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2352 NotifyDoubleClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2355 void Editor::NotifyHotSpotDoubleClicked(int position
, int modifiers
) {
2356 SCNotification scn
= {};
2357 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
2358 scn
.position
= position
;
2359 scn
.modifiers
= modifiers
;
2363 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2364 NotifyHotSpotDoubleClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2367 void Editor::NotifyHotSpotClicked(int position
, int modifiers
) {
2368 SCNotification scn
= {};
2369 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
2370 scn
.position
= position
;
2371 scn
.modifiers
= modifiers
;
2375 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2376 NotifyHotSpotClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2379 void Editor::NotifyHotSpotReleaseClick(int position
, int modifiers
) {
2380 SCNotification scn
= {};
2381 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
2382 scn
.position
= position
;
2383 scn
.modifiers
= modifiers
;
2387 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
2388 NotifyHotSpotReleaseClick(position
, ModifierFlags(shift
, ctrl
, alt
));
2391 bool Editor::NotifyUpdateUI() {
2393 SCNotification scn
= {};
2394 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2395 scn
.updated
= needUpdateUI
;
2403 void Editor::NotifyPainted() {
2404 SCNotification scn
= {};
2405 scn
.nmhdr
.code
= SCN_PAINTED
;
2409 void Editor::NotifyIndicatorClick(bool click
, int position
, int modifiers
) {
2410 int mask
= pdoc
->decorations
.AllOnFor(position
);
2411 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
2412 SCNotification scn
= {};
2413 pdoc
->decorations
.clickNotified
= click
;
2414 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
2415 scn
.modifiers
= modifiers
;
2416 scn
.position
= position
;
2421 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
2422 NotifyIndicatorClick(click
, position
, ModifierFlags(shift
, ctrl
, alt
));
2425 bool Editor::NotifyMarginClick(Point pt
, int modifiers
) {
2426 int marginClicked
= -1;
2427 int x
= vs
.textStart
- vs
.fixedColumnWidth
;
2428 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
2429 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2430 marginClicked
= margin
;
2431 x
+= vs
.ms
[margin
].width
;
2433 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2434 int position
= pdoc
->LineStart(LineFromLocation(pt
));
2435 if ((vs
.ms
[marginClicked
].mask
& SC_MASK_FOLDERS
) && (foldAutomatic
& SC_AUTOMATICFOLD_CLICK
)) {
2436 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
2437 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
2438 int lineClick
= pdoc
->LineFromPosition(position
);
2439 if (shift
&& ctrl
) {
2440 FoldAll(SC_FOLDACTION_TOGGLE
);
2442 int levelClick
= pdoc
->GetLevel(lineClick
);
2443 if (levelClick
& SC_FOLDLEVELHEADERFLAG
) {
2445 // Ensure all children visible
2446 FoldExpand(lineClick
, SC_FOLDACTION_EXPAND
, levelClick
);
2448 FoldExpand(lineClick
, SC_FOLDACTION_TOGGLE
, levelClick
);
2451 FoldLine(lineClick
, SC_FOLDACTION_TOGGLE
);
2457 SCNotification scn
= {};
2458 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2459 scn
.modifiers
= modifiers
;
2460 scn
.position
= position
;
2461 scn
.margin
= marginClicked
;
2469 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2470 return NotifyMarginClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2473 void Editor::NotifyNeedShown(int pos
, int len
) {
2474 SCNotification scn
= {};
2475 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2481 void Editor::NotifyDwelling(Point pt
, bool state
) {
2482 SCNotification scn
= {};
2483 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2484 scn
.position
= PositionFromLocation(pt
, true);
2485 scn
.x
= static_cast<int>(pt
.x
+ vs
.ExternalMarginWidth());
2486 scn
.y
= static_cast<int>(pt
.y
);
2490 void Editor::NotifyZoom() {
2491 SCNotification scn
= {};
2492 scn
.nmhdr
.code
= SCN_ZOOM
;
2496 // Notifications from document
2497 void Editor::NotifyModifyAttempt(Document
*, void *) {
2498 //Platform::DebugPrintf("** Modify Attempt\n");
2499 NotifyModifyAttempt();
2502 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2503 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2504 NotifySavePoint(atSavePoint
);
2507 void Editor::CheckModificationForWrap(DocModification mh
) {
2508 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
2509 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2510 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2511 int lines
= Platform::Maximum(0, mh
.linesAdded
);
2513 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
2516 // Fix up annotation heights
2517 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
2521 // Move a position so it is still after the same character as before the insertion.
2522 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2523 if (position
> startInsertion
) {
2524 return position
+ length
;
2529 // Move a position so it is still after the same character as before the deletion if that
2530 // character is still present else after the previous surviving character.
2531 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2532 if (position
> startDeletion
) {
2533 int endDeletion
= startDeletion
+ length
;
2534 if (position
> endDeletion
) {
2535 return position
- length
;
2537 return startDeletion
;
2544 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2545 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
2546 if (paintState
== painting
) {
2547 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2549 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
2550 if (paintState
== painting
) {
2551 CheckForChangeOutsidePaint(
2552 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
2554 // Could check that change is before last visible line.
2558 if (mh
.modificationType
& SC_MOD_CHANGETABSTOPS
) {
2561 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
2562 if (paintState
== painting
) {
2563 CheckForChangeOutsidePaint(
2564 Range(mh
.position
, mh
.position
+ mh
.length
));
2569 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
2570 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2571 pdoc
->IncrementStyleClock();
2573 if (paintState
== notPainting
) {
2574 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2575 // Styling performed before this view
2578 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2581 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2582 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2585 // Move selection and brace highlights
2586 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2587 sel
.MovePositions(true, mh
.position
, mh
.length
);
2588 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2589 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2590 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2591 sel
.MovePositions(false, mh
.position
, mh
.length
);
2592 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2593 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2595 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
2596 // Some lines are hidden so may need shown.
2597 const int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2598 int endNeedShown
= mh
.position
;
2599 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2600 if (pdoc
->ContainsLineEnd(mh
.text
, mh
.length
) && (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
2601 endNeedShown
= pdoc
->LineStart(lineOfPos
+1);
2602 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2603 // Extend the need shown area over any folded lines
2604 endNeedShown
= mh
.position
+ mh
.length
;
2605 int lineLast
= pdoc
->LineFromPosition(mh
.position
+mh
.length
);
2606 for (int line
= lineOfPos
; line
<= lineLast
; line
++) {
2607 const int lineMaxSubord
= pdoc
->GetLastChild(line
, -1, -1);
2608 if (lineLast
< lineMaxSubord
) {
2609 lineLast
= lineMaxSubord
;
2610 endNeedShown
= pdoc
->LineEnd(lineLast
);
2614 NeedShown(mh
.position
, endNeedShown
- mh
.position
);
2616 if (mh
.linesAdded
!= 0) {
2617 // Update contraction state for inserted and removed lines
2618 // lineOfPos should be calculated in context of state before modification, shouldn't it
2619 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2620 if (mh
.position
> pdoc
->LineStart(lineOfPos
))
2621 lineOfPos
++; // Affecting subsequent lines
2622 if (mh
.linesAdded
> 0) {
2623 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2625 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2627 view
.LinesAddedOrRemoved(lineOfPos
, mh
.linesAdded
);
2629 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
2630 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2631 if (vs
.annotationVisible
) {
2632 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
2636 CheckModificationForWrap(mh
);
2637 if (mh
.linesAdded
!= 0) {
2638 // Avoid scrolling of display if change before current display
2639 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
2640 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2641 if (newTop
!= topLine
) {
2643 SetVerticalScrollPos();
2647 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
2648 QueueIdleWork(WorkNeeded::workStyle
, pdoc
->Length());
2652 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
2653 QueueIdleWork(WorkNeeded::workStyle
, mh
.position
+ mh
.length
);
2654 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2659 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
2663 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
2664 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
2665 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
2666 // Fold changes can affect the drawing of following lines so redraw whole margin
2667 RedrawSelMargin(marginView
.highlightDelimiter
.isEnabled
? -1 : mh
.line
- 1, true);
2669 RedrawSelMargin(mh
.line
);
2673 if ((mh
.modificationType
& SC_MOD_CHANGEFOLD
) && (foldAutomatic
& SC_AUTOMATICFOLD_CHANGE
)) {
2674 FoldChanged(mh
.line
, mh
.foldLevelNow
, mh
.foldLevelPrev
);
2677 // NOW pay the piper WRT "deferred" visual updates
2678 if (IsLastStep(mh
)) {
2683 // If client wants to see this modification
2684 if (mh
.modificationType
& modEventMask
) {
2685 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
2686 // Real modification made to text of document.
2687 NotifyChange(); // Send EN_CHANGE
2690 SCNotification scn
= {};
2691 scn
.nmhdr
.code
= SCN_MODIFIED
;
2692 scn
.position
= mh
.position
;
2693 scn
.modificationType
= mh
.modificationType
;
2695 scn
.length
= mh
.length
;
2696 scn
.linesAdded
= mh
.linesAdded
;
2698 scn
.foldLevelNow
= mh
.foldLevelNow
;
2699 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2700 scn
.token
= mh
.token
;
2701 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
2706 void Editor::NotifyDeleted(Document
*, void *) {
2710 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2712 // Enumerates all macroable messages
2718 case SCI_REPLACESEL
:
2720 case SCI_INSERTTEXT
:
2721 case SCI_APPENDTEXT
:
2726 case SCI_SEARCHANCHOR
:
2727 case SCI_SEARCHNEXT
:
2728 case SCI_SEARCHPREV
:
2730 case SCI_LINEDOWNEXTEND
:
2732 case SCI_PARADOWNEXTEND
:
2734 case SCI_LINEUPEXTEND
:
2736 case SCI_PARAUPEXTEND
:
2738 case SCI_CHARLEFTEXTEND
:
2740 case SCI_CHARRIGHTEXTEND
:
2742 case SCI_WORDLEFTEXTEND
:
2744 case SCI_WORDRIGHTEXTEND
:
2745 case SCI_WORDPARTLEFT
:
2746 case SCI_WORDPARTLEFTEXTEND
:
2747 case SCI_WORDPARTRIGHT
:
2748 case SCI_WORDPARTRIGHTEXTEND
:
2749 case SCI_WORDLEFTEND
:
2750 case SCI_WORDLEFTENDEXTEND
:
2751 case SCI_WORDRIGHTEND
:
2752 case SCI_WORDRIGHTENDEXTEND
:
2754 case SCI_HOMEEXTEND
:
2756 case SCI_LINEENDEXTEND
:
2758 case SCI_HOMEWRAPEXTEND
:
2759 case SCI_LINEENDWRAP
:
2760 case SCI_LINEENDWRAPEXTEND
:
2761 case SCI_DOCUMENTSTART
:
2762 case SCI_DOCUMENTSTARTEXTEND
:
2763 case SCI_DOCUMENTEND
:
2764 case SCI_DOCUMENTENDEXTEND
:
2765 case SCI_STUTTEREDPAGEUP
:
2766 case SCI_STUTTEREDPAGEUPEXTEND
:
2767 case SCI_STUTTEREDPAGEDOWN
:
2768 case SCI_STUTTEREDPAGEDOWNEXTEND
:
2770 case SCI_PAGEUPEXTEND
:
2772 case SCI_PAGEDOWNEXTEND
:
2773 case SCI_EDITTOGGLEOVERTYPE
:
2775 case SCI_DELETEBACK
:
2780 case SCI_VCHOMEEXTEND
:
2781 case SCI_VCHOMEWRAP
:
2782 case SCI_VCHOMEWRAPEXTEND
:
2783 case SCI_VCHOMEDISPLAY
:
2784 case SCI_VCHOMEDISPLAYEXTEND
:
2785 case SCI_DELWORDLEFT
:
2786 case SCI_DELWORDRIGHT
:
2787 case SCI_DELWORDRIGHTEND
:
2788 case SCI_DELLINELEFT
:
2789 case SCI_DELLINERIGHT
:
2792 case SCI_LINEDELETE
:
2793 case SCI_LINETRANSPOSE
:
2794 case SCI_LINEDUPLICATE
:
2797 case SCI_LINESCROLLDOWN
:
2798 case SCI_LINESCROLLUP
:
2799 case SCI_DELETEBACKNOTLINE
:
2800 case SCI_HOMEDISPLAY
:
2801 case SCI_HOMEDISPLAYEXTEND
:
2802 case SCI_LINEENDDISPLAY
:
2803 case SCI_LINEENDDISPLAYEXTEND
:
2804 case SCI_SETSELECTIONMODE
:
2805 case SCI_LINEDOWNRECTEXTEND
:
2806 case SCI_LINEUPRECTEXTEND
:
2807 case SCI_CHARLEFTRECTEXTEND
:
2808 case SCI_CHARRIGHTRECTEXTEND
:
2809 case SCI_HOMERECTEXTEND
:
2810 case SCI_VCHOMERECTEXTEND
:
2811 case SCI_LINEENDRECTEXTEND
:
2812 case SCI_PAGEUPRECTEXTEND
:
2813 case SCI_PAGEDOWNRECTEXTEND
:
2814 case SCI_SELECTIONDUPLICATE
:
2815 case SCI_COPYALLOWLINE
:
2816 case SCI_VERTICALCENTRECARET
:
2817 case SCI_MOVESELECTEDLINESUP
:
2818 case SCI_MOVESELECTEDLINESDOWN
:
2819 case SCI_SCROLLTOSTART
:
2820 case SCI_SCROLLTOEND
:
2823 // Filter out all others like display changes. Also, newlines are redundant
2824 // with char insert messages.
2827 // printf("Filtered out %ld of macro recording\n", iMessage);
2831 // Send notification
2832 SCNotification scn
= {};
2833 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2834 scn
.message
= iMessage
;
2835 scn
.wParam
= wParam
;
2836 scn
.lParam
= lParam
;
2840 // Something has changed that the container should know about
2841 void Editor::ContainerNeedsUpdate(int flags
) {
2842 needUpdateUI
|= flags
;
2846 * Force scroll and keep position relative to top of window.
2848 * If stuttered = true and not already at first/last row, move to first/last row of window.
2849 * If stuttered = true and already at first/last row, scroll as normal.
2851 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
2853 SelectionPosition newPos
;
2855 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
2856 int topStutterLine
= topLine
+ caretYSlop
;
2857 int bottomStutterLine
=
2858 pdoc
->LineFromPosition(PositionFromLocation(
2859 Point::FromInts(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
2862 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
2863 topLineNew
= topLine
;
2864 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
2865 false, false, UserVirtualSpace());
2867 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
2868 topLineNew
= topLine
;
2869 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
2870 false, false, UserVirtualSpace());
2873 Point pt
= LocationFromPosition(sel
.MainCaret());
2875 topLineNew
= Platform::Clamp(
2876 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2877 newPos
= SPositionFromLocation(
2878 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(pt
.y
) + direction
* (vs
.lineHeight
* LinesToScroll())),
2879 false, false, UserVirtualSpace());
2882 if (topLineNew
!= topLine
) {
2883 SetTopLine(topLineNew
);
2884 MovePositionTo(newPos
, selt
);
2886 SetVerticalScrollPos();
2888 MovePositionTo(newPos
, selt
);
2892 void Editor::ChangeCaseOfSelection(int caseMapping
) {
2894 for (size_t r
=0; r
<sel
.Count(); r
++) {
2895 SelectionRange current
= sel
.Range(r
);
2896 SelectionRange currentNoVS
= current
;
2897 currentNoVS
.ClearVirtualSpace();
2898 size_t rangeBytes
= currentNoVS
.Length();
2899 if (rangeBytes
> 0) {
2900 std::string sText
= RangeText(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
2902 std::string sMapped
= CaseMapString(sText
, caseMapping
);
2904 if (sMapped
!= sText
) {
2905 size_t firstDifference
= 0;
2906 while (sMapped
[firstDifference
] == sText
[firstDifference
])
2908 size_t lastDifferenceText
= sText
.size() - 1;
2909 size_t lastDifferenceMapped
= sMapped
.size() - 1;
2910 while (sMapped
[lastDifferenceMapped
] == sText
[lastDifferenceText
]) {
2911 lastDifferenceText
--;
2912 lastDifferenceMapped
--;
2914 size_t endDifferenceText
= sText
.size() - 1 - lastDifferenceText
;
2916 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2917 static_cast<int>(rangeBytes
- firstDifference
- endDifferenceText
));
2918 const int lengthChange
= static_cast<int>(lastDifferenceMapped
- firstDifference
+ 1);
2919 const int lengthInserted
= pdoc
->InsertString(
2920 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2921 sMapped
.c_str() + firstDifference
,
2923 // Automatic movement changes selection so reset to exactly the same as it was.
2924 int diffSizes
= static_cast<int>(sMapped
.size() - sText
.size()) + lengthInserted
- lengthChange
;
2925 if (diffSizes
!= 0) {
2926 if (current
.anchor
> current
.caret
)
2927 current
.anchor
.Add(diffSizes
);
2929 current
.caret
.Add(diffSizes
);
2931 sel
.Range(r
) = current
;
2937 void Editor::LineTranspose() {
2938 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2942 const int startPrevious
= pdoc
->LineStart(line
- 1);
2943 const std::string linePrevious
= RangeText(startPrevious
, pdoc
->LineEnd(line
- 1));
2945 int startCurrent
= pdoc
->LineStart(line
);
2946 const std::string lineCurrent
= RangeText(startCurrent
, pdoc
->LineEnd(line
));
2948 pdoc
->DeleteChars(startCurrent
, static_cast<int>(lineCurrent
.length()));
2949 pdoc
->DeleteChars(startPrevious
, static_cast<int>(linePrevious
.length()));
2950 startCurrent
-= static_cast<int>(linePrevious
.length());
2952 startCurrent
+= pdoc
->InsertString(startPrevious
, lineCurrent
.c_str(),
2953 static_cast<int>(lineCurrent
.length()));
2954 pdoc
->InsertString(startCurrent
, linePrevious
.c_str(),
2955 static_cast<int>(linePrevious
.length()));
2956 // Move caret to start of current line
2957 MovePositionTo(SelectionPosition(startCurrent
));
2961 void Editor::Duplicate(bool forLine
) {
2966 const char *eol
= "";
2969 eol
= StringFromEOLMode(pdoc
->eolMode
);
2970 eolLen
= istrlen(eol
);
2972 for (size_t r
=0; r
<sel
.Count(); r
++) {
2973 SelectionPosition start
= sel
.Range(r
).Start();
2974 SelectionPosition end
= sel
.Range(r
).End();
2976 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2977 start
= SelectionPosition(pdoc
->LineStart(line
));
2978 end
= SelectionPosition(pdoc
->LineEnd(line
));
2980 std::string text
= RangeText(start
.Position(), end
.Position());
2981 int lengthInserted
= eolLen
;
2983 lengthInserted
= pdoc
->InsertString(end
.Position(), eol
, eolLen
);
2984 pdoc
->InsertString(end
.Position() + lengthInserted
, text
.c_str(), static_cast<int>(text
.length()));
2986 if (sel
.Count() && sel
.IsRectangular()) {
2987 SelectionPosition last
= sel
.Last();
2989 int line
= pdoc
->LineFromPosition(last
.Position());
2990 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
2992 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
2993 sel
.Rectangular().anchor
= last
;
2995 sel
.Rectangular().caret
= last
;
2996 SetRectangularRange();
3000 void Editor::CancelModes() {
3001 sel
.SetMoveExtends(false);
3004 void Editor::NewLine() {
3005 InvalidateWholeSelection();
3006 if (sel
.IsRectangular() || !additionalSelectionTyping
) {
3007 // Remove non-main ranges
3008 sel
.DropAdditionalRanges();
3011 UndoGroup
ug(pdoc
, !sel
.Empty() || (sel
.Count() > 1));
3018 // Insert each line end
3019 size_t countInsertions
= 0;
3020 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3021 sel
.Range(r
).ClearVirtualSpace();
3022 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3023 const int positionInsert
= sel
.Range(r
).caret
.Position();
3024 const int insertLength
= pdoc
->InsertString(positionInsert
, eol
, istrlen(eol
));
3025 if (insertLength
> 0) {
3026 sel
.Range(r
) = SelectionRange(positionInsert
+ insertLength
);
3031 // Perform notifications after all the changes as the application may change the
3032 // selections in response to the characters.
3033 for (size_t i
= 0; i
< countInsertions
; i
++) {
3034 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3037 if (recordingMacro
) {
3041 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3049 EnsureCaretVisible();
3050 // Avoid blinking during rapid typing:
3051 ShowCaretAtCurrentPosition();
3054 SelectionPosition
Editor::PositionUpOrDown(SelectionPosition spStart
, int direction
, int lastX
) {
3055 const Point pt
= LocationFromPosition(spStart
);
3058 if (vs
.annotationVisible
) {
3059 const int lineDoc
= pdoc
->LineFromPosition(spStart
.Position());
3060 const Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
3061 const int subLine
= static_cast<int>(pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
3063 if (direction
< 0 && subLine
== 0) {
3064 const int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
3065 if (lineDisplay
> 0) {
3066 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
3068 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
3069 skipLines
= pdoc
->AnnotationLines(lineDoc
);
3073 const int newY
= static_cast<int>(pt
.y
) + (1 + skipLines
) * direction
* vs
.lineHeight
;
3075 lastX
= static_cast<int>(pt
.x
) + xOffset
;
3077 SelectionPosition posNew
= SPositionFromLocation(
3078 Point::FromInts(lastX
- xOffset
, newY
), false, false, UserVirtualSpace());
3080 if (direction
< 0) {
3081 // Line wrapping may lead to a location on the same line, so
3082 // seek back if that is the case.
3083 Point ptNew
= LocationFromPosition(posNew
.Position());
3084 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
3086 posNew
.SetVirtualSpace(0);
3087 ptNew
= LocationFromPosition(posNew
.Position());
3089 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
3090 // There is an equivalent case when moving down which skips
3092 Point ptNew
= LocationFromPosition(posNew
.Position());
3093 while ((posNew
.Position() > spStart
.Position()) && (ptNew
.y
> newY
)) {
3095 posNew
.SetVirtualSpace(0);
3096 ptNew
= LocationFromPosition(posNew
.Position());
3102 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
3103 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
3104 if (sel
.IsRectangular()) {
3105 if (selt
== Selection::noSel
) {
3106 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
3108 caretToUse
= sel
.Rectangular().caret
;
3111 if (selt
== Selection::selRectangle
) {
3112 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3113 if (!sel
.IsRectangular()) {
3114 InvalidateWholeSelection();
3115 sel
.DropAdditionalRanges();
3117 const SelectionPosition posNew
= MovePositionSoVisible(
3118 PositionUpOrDown(caretToUse
, direction
, lastXChosen
), direction
);
3119 sel
.selType
= Selection::selRectangle
;
3120 sel
.Rectangular() = SelectionRange(posNew
, rangeBase
.anchor
);
3121 SetRectangularRange();
3122 MovedCaret(posNew
, caretToUse
, true);
3124 InvalidateWholeSelection();
3125 if (!additionalSelectionTyping
|| (sel
.IsRectangular())) {
3126 sel
.DropAdditionalRanges();
3128 sel
.selType
= Selection::selStream
;
3129 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3130 const int lastX
= (r
== sel
.Main()) ? lastXChosen
: -1;
3131 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3132 const SelectionPosition posNew
= MovePositionSoVisible(
3133 PositionUpOrDown(spCaretNow
, direction
, lastX
), direction
);
3134 sel
.Range(r
) = selt
== Selection::selStream
?
3135 SelectionRange(posNew
, sel
.Range(r
).anchor
) : SelectionRange(posNew
);
3137 sel
.RemoveDuplicates();
3138 MovedCaret(sel
.RangeMain().caret
, caretToUse
, true);
3142 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
3143 int lineDoc
, savedPos
= sel
.MainCaret();
3145 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
3146 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
3147 if (direction
> 0) {
3148 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
3149 if (selt
== Selection::noSel
) {
3150 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
3155 } while (!cs
.GetVisible(lineDoc
));
3158 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3160 AutoSurface
surface(this);
3161 int posRet
= view
.StartEndDisplayLine(surface
, *this, pos
, start
, vs
);
3162 if (posRet
== INVALID_POSITION
) {
3171 unsigned int WithExtends(unsigned int iMessage
) {
3173 case SCI_CHARLEFT
: return SCI_CHARLEFTEXTEND
;
3174 case SCI_CHARRIGHT
: return SCI_CHARRIGHTEXTEND
;
3176 case SCI_WORDLEFT
: return SCI_WORDLEFTEXTEND
;
3177 case SCI_WORDRIGHT
: return SCI_WORDRIGHTEXTEND
;
3178 case SCI_WORDLEFTEND
: return SCI_WORDLEFTENDEXTEND
;
3179 case SCI_WORDRIGHTEND
: return SCI_WORDRIGHTENDEXTEND
;
3180 case SCI_WORDPARTLEFT
: return SCI_WORDPARTLEFTEXTEND
;
3181 case SCI_WORDPARTRIGHT
: return SCI_WORDPARTRIGHTEXTEND
;
3183 case SCI_HOME
: return SCI_HOMEEXTEND
;
3184 case SCI_HOMEDISPLAY
: return SCI_HOMEDISPLAYEXTEND
;
3185 case SCI_HOMEWRAP
: return SCI_HOMEWRAPEXTEND
;
3186 case SCI_VCHOME
: return SCI_VCHOMEEXTEND
;
3187 case SCI_VCHOMEDISPLAY
: return SCI_VCHOMEDISPLAYEXTEND
;
3188 case SCI_VCHOMEWRAP
: return SCI_VCHOMEWRAPEXTEND
;
3190 case SCI_LINEEND
: return SCI_LINEENDEXTEND
;
3191 case SCI_LINEENDDISPLAY
: return SCI_LINEENDDISPLAYEXTEND
;
3192 case SCI_LINEENDWRAP
: return SCI_LINEENDWRAPEXTEND
;
3194 default: return iMessage
;
3198 int NaturalDirection(unsigned int iMessage
) {
3201 case SCI_CHARLEFTEXTEND
:
3202 case SCI_CHARLEFTRECTEXTEND
:
3204 case SCI_WORDLEFTEXTEND
:
3205 case SCI_WORDLEFTEND
:
3206 case SCI_WORDLEFTENDEXTEND
:
3207 case SCI_WORDPARTLEFT
:
3208 case SCI_WORDPARTLEFTEXTEND
:
3210 case SCI_HOMEEXTEND
:
3211 case SCI_HOMEDISPLAY
:
3212 case SCI_HOMEDISPLAYEXTEND
:
3214 case SCI_HOMEWRAPEXTEND
:
3215 // VC_HOME* mostly goes back
3217 case SCI_VCHOMEEXTEND
:
3218 case SCI_VCHOMEDISPLAY
:
3219 case SCI_VCHOMEDISPLAYEXTEND
:
3220 case SCI_VCHOMEWRAP
:
3221 case SCI_VCHOMEWRAPEXTEND
:
3229 bool IsRectExtend(unsigned int iMessage
) {
3231 case SCI_CHARLEFTRECTEXTEND
:
3232 case SCI_CHARRIGHTRECTEXTEND
:
3233 case SCI_HOMERECTEXTEND
:
3234 case SCI_VCHOMERECTEXTEND
:
3235 case SCI_LINEENDRECTEXTEND
:
3244 int Editor::VCHomeDisplayPosition(int position
) {
3245 const int homePos
= pdoc
->VCHomePosition(position
);
3246 const int viewLineStart
= StartEndDisplayLine(position
, true);
3247 if (viewLineStart
> homePos
)
3248 return viewLineStart
;
3253 int Editor::VCHomeWrapPosition(int position
) {
3254 const int homePos
= pdoc
->VCHomePosition(position
);
3255 const int viewLineStart
= StartEndDisplayLine(position
, true);
3256 if ((viewLineStart
< position
) && (viewLineStart
> homePos
))
3257 return viewLineStart
;
3262 int Editor::LineEndWrapPosition(int position
) {
3263 const int endPos
= StartEndDisplayLine(position
, false);
3264 const int realEndPos
= pdoc
->LineEndPosition(position
);
3265 if (endPos
> realEndPos
// if moved past visible EOLs
3266 || position
>= endPos
) // if at end of display line already
3272 int Editor::HorizontalMove(unsigned int iMessage
) {
3273 if (sel
.MoveExtends()) {
3274 iMessage
= WithExtends(iMessage
);
3277 if (!multipleSelection
&& !sel
.IsRectangular()) {
3278 // Simplify selection down to 1
3279 sel
.SetSelection(sel
.RangeMain());
3282 // Invalidate each of the current selections
3283 InvalidateWholeSelection();
3285 if (IsRectExtend(iMessage
)) {
3286 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3287 if (!sel
.IsRectangular()) {
3288 sel
.DropAdditionalRanges();
3290 // Will change to rectangular if not currently rectangular
3291 SelectionPosition spCaret
= rangeBase
.caret
;
3293 case SCI_CHARLEFTRECTEXTEND
:
3294 if (pdoc
->IsLineEndPosition(spCaret
.Position()) && spCaret
.VirtualSpace()) {
3295 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3296 } else if ((virtualSpaceOptions
& SCVS_NOWRAPLINESTART
) == 0 || pdoc
->GetColumn(spCaret
.Position()) > 0) {
3297 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3300 case SCI_CHARRIGHTRECTEXTEND
:
3301 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3302 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3304 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3307 case SCI_HOMERECTEXTEND
:
3308 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3310 case SCI_VCHOMERECTEXTEND
:
3311 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3313 case SCI_LINEENDRECTEXTEND
:
3314 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3317 const int directionMove
= (spCaret
< rangeBase
.caret
) ? -1 : 1;
3318 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3319 sel
.selType
= Selection::selRectangle
;
3320 sel
.Rectangular() = SelectionRange(spCaret
, rangeBase
.anchor
);
3321 SetRectangularRange();
3323 if (sel
.IsRectangular()) {
3324 // Not a rectangular extension so switch to stream.
3325 SelectionPosition selAtLimit
= (NaturalDirection(iMessage
) > 0) ? sel
.Limits().end
: sel
.Limits().start
;
3326 sel
.selType
= Selection::selStream
;
3327 sel
.SetSelection(SelectionRange(selAtLimit
));
3329 if (!additionalSelectionTyping
) {
3330 InvalidateWholeSelection();
3331 sel
.DropAdditionalRanges();
3333 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3334 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3335 SelectionPosition spCaret
= spCaretNow
;
3338 case SCI_CHARLEFTEXTEND
:
3339 if (spCaret
.VirtualSpace()) {
3340 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3341 } else if ((virtualSpaceOptions
& SCVS_NOWRAPLINESTART
) == 0 || pdoc
->GetColumn(spCaret
.Position()) > 0) {
3342 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3346 case SCI_CHARRIGHTEXTEND
:
3347 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(spCaret
.Position())) {
3348 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3350 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3354 case SCI_WORDLEFTEXTEND
:
3355 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), -1));
3358 case SCI_WORDRIGHTEXTEND
:
3359 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), 1));
3361 case SCI_WORDLEFTEND
:
3362 case SCI_WORDLEFTENDEXTEND
:
3363 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), -1));
3365 case SCI_WORDRIGHTEND
:
3366 case SCI_WORDRIGHTENDEXTEND
:
3367 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), 1));
3369 case SCI_WORDPARTLEFT
:
3370 case SCI_WORDPARTLEFTEXTEND
:
3371 spCaret
= SelectionPosition(pdoc
->WordPartLeft(spCaret
.Position()));
3373 case SCI_WORDPARTRIGHT
:
3374 case SCI_WORDPARTRIGHTEXTEND
:
3375 spCaret
= SelectionPosition(pdoc
->WordPartRight(spCaret
.Position()));
3378 case SCI_HOMEEXTEND
:
3379 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3381 case SCI_HOMEDISPLAY
:
3382 case SCI_HOMEDISPLAYEXTEND
:
3383 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), true));
3386 case SCI_HOMEWRAPEXTEND
:
3387 spCaret
= MovePositionSoVisible(StartEndDisplayLine(spCaret
.Position(), true), -1);
3388 if (spCaretNow
<= spCaret
)
3389 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3392 case SCI_VCHOMEEXTEND
:
3393 // VCHome alternates between beginning of line and beginning of text so may move back or forwards
3394 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3396 case SCI_VCHOMEDISPLAY
:
3397 case SCI_VCHOMEDISPLAYEXTEND
:
3398 spCaret
= SelectionPosition(VCHomeDisplayPosition(spCaret
.Position()));
3400 case SCI_VCHOMEWRAP
:
3401 case SCI_VCHOMEWRAPEXTEND
:
3402 spCaret
= SelectionPosition(VCHomeWrapPosition(spCaret
.Position()));
3405 case SCI_LINEENDEXTEND
:
3406 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3408 case SCI_LINEENDDISPLAY
:
3409 case SCI_LINEENDDISPLAYEXTEND
:
3410 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), false));
3412 case SCI_LINEENDWRAP
:
3413 case SCI_LINEENDWRAPEXTEND
:
3414 spCaret
= SelectionPosition(LineEndWrapPosition(spCaret
.Position()));
3418 PLATFORM_ASSERT(false);
3421 const int directionMove
= (spCaret
< spCaretNow
) ? -1 : 1;
3422 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3424 // Handle move versus extend, and special behaviour for non-emoty left/right
3428 if (sel
.Range(r
).Empty()) {
3429 sel
.Range(r
) = SelectionRange(spCaret
);
3431 sel
.Range(r
) = SelectionRange(
3432 (iMessage
== SCI_CHARLEFT
) ? sel
.Range(r
).Start() : sel
.Range(r
).End());
3438 case SCI_WORDLEFTEND
:
3439 case SCI_WORDRIGHTEND
:
3440 case SCI_WORDPARTLEFT
:
3441 case SCI_WORDPARTRIGHT
:
3443 case SCI_HOMEDISPLAY
:
3446 case SCI_VCHOMEDISPLAY
:
3447 case SCI_VCHOMEWRAP
:
3449 case SCI_LINEENDDISPLAY
:
3450 case SCI_LINEENDWRAP
:
3451 sel
.Range(r
) = SelectionRange(spCaret
);
3454 case SCI_CHARLEFTEXTEND
:
3455 case SCI_CHARRIGHTEXTEND
:
3456 case SCI_WORDLEFTEXTEND
:
3457 case SCI_WORDRIGHTEXTEND
:
3458 case SCI_WORDLEFTENDEXTEND
:
3459 case SCI_WORDRIGHTENDEXTEND
:
3460 case SCI_WORDPARTLEFTEXTEND
:
3461 case SCI_WORDPARTRIGHTEXTEND
:
3462 case SCI_HOMEEXTEND
:
3463 case SCI_HOMEDISPLAYEXTEND
:
3464 case SCI_HOMEWRAPEXTEND
:
3465 case SCI_VCHOMEEXTEND
:
3466 case SCI_VCHOMEDISPLAYEXTEND
:
3467 case SCI_VCHOMEWRAPEXTEND
:
3468 case SCI_LINEENDEXTEND
:
3469 case SCI_LINEENDDISPLAYEXTEND
:
3470 case SCI_LINEENDWRAPEXTEND
: {
3471 SelectionRange rangeNew
= SelectionRange(spCaret
, sel
.Range(r
).anchor
);
3472 sel
.TrimOtherSelections(r
, SelectionRange(rangeNew
));
3473 sel
.Range(r
) = rangeNew
;
3478 PLATFORM_ASSERT(false);
3483 sel
.RemoveDuplicates();
3485 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3487 // Invalidate the new state of the selection
3488 InvalidateWholeSelection();
3491 // Need the line moving and so forth from MovePositionTo
3495 int Editor::DelWordOrLine(unsigned int iMessage
) {
3496 // Virtual space may be realised for SCI_DELWORDRIGHT or SCI_DELWORDRIGHTEND
3497 // which means 2 actions so wrap in an undo group.
3499 // Rightwards and leftwards deletions differ in treatment of virtual space.
3500 // Clear virtual space for leftwards, realise for rightwards.
3501 const bool leftwards
= (iMessage
== SCI_DELWORDLEFT
) || (iMessage
== SCI_DELLINELEFT
);
3503 if (!additionalSelectionTyping
) {
3504 InvalidateWholeSelection();
3505 sel
.DropAdditionalRanges();
3508 UndoGroup
ug0(pdoc
, (sel
.Count() > 1) || !leftwards
);
3510 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3512 // Delete to the left so first clear the virtual space.
3513 sel
.Range(r
).ClearVirtualSpace();
3515 // Delete to the right so first realise the virtual space.
3516 sel
.Range(r
) = SelectionRange(
3517 RealizeVirtualSpace(sel
.Range(r
).caret
));
3522 case SCI_DELWORDLEFT
:
3523 rangeDelete
= Range(
3524 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), -1),
3525 sel
.Range(r
).caret
.Position());
3527 case SCI_DELWORDRIGHT
:
3528 rangeDelete
= Range(
3529 sel
.Range(r
).caret
.Position(),
3530 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), 1));
3532 case SCI_DELWORDRIGHTEND
:
3533 rangeDelete
= Range(
3534 sel
.Range(r
).caret
.Position(),
3535 pdoc
->NextWordEnd(sel
.Range(r
).caret
.Position(), 1));
3537 case SCI_DELLINELEFT
:
3538 rangeDelete
= Range(
3539 pdoc
->LineStart(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())),
3540 sel
.Range(r
).caret
.Position());
3542 case SCI_DELLINERIGHT
:
3543 rangeDelete
= Range(
3544 sel
.Range(r
).caret
.Position(),
3545 pdoc
->LineEnd(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())));
3548 if (!RangeContainsProtected(rangeDelete
.start
, rangeDelete
.end
)) {
3549 pdoc
->DeleteChars(rangeDelete
.start
, rangeDelete
.end
- rangeDelete
.start
);
3553 // May need something stronger here: can selections overlap at this point?
3554 sel
.RemoveDuplicates();
3556 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3558 // Invalidate the new state of the selection
3559 InvalidateWholeSelection();
3565 int Editor::KeyCommand(unsigned int iMessage
) {
3568 CursorUpOrDown(1, Selection::noSel
);
3570 case SCI_LINEDOWNEXTEND
:
3571 CursorUpOrDown(1, Selection::selStream
);
3573 case SCI_LINEDOWNRECTEXTEND
:
3574 CursorUpOrDown(1, Selection::selRectangle
);
3577 ParaUpOrDown(1, Selection::noSel
);
3579 case SCI_PARADOWNEXTEND
:
3580 ParaUpOrDown(1, Selection::selStream
);
3582 case SCI_LINESCROLLDOWN
:
3583 ScrollTo(topLine
+ 1);
3584 MoveCaretInsideView(false);
3587 CursorUpOrDown(-1, Selection::noSel
);
3589 case SCI_LINEUPEXTEND
:
3590 CursorUpOrDown(-1, Selection::selStream
);
3592 case SCI_LINEUPRECTEXTEND
:
3593 CursorUpOrDown(-1, Selection::selRectangle
);
3596 ParaUpOrDown(-1, Selection::noSel
);
3598 case SCI_PARAUPEXTEND
:
3599 ParaUpOrDown(-1, Selection::selStream
);
3601 case SCI_LINESCROLLUP
:
3602 ScrollTo(topLine
- 1);
3603 MoveCaretInsideView(false);
3607 case SCI_CHARLEFTEXTEND
:
3608 case SCI_CHARLEFTRECTEXTEND
:
3610 case SCI_CHARRIGHTEXTEND
:
3611 case SCI_CHARRIGHTRECTEXTEND
:
3613 case SCI_WORDLEFTEXTEND
:
3615 case SCI_WORDRIGHTEXTEND
:
3616 case SCI_WORDLEFTEND
:
3617 case SCI_WORDLEFTENDEXTEND
:
3618 case SCI_WORDRIGHTEND
:
3619 case SCI_WORDRIGHTENDEXTEND
:
3620 case SCI_WORDPARTLEFT
:
3621 case SCI_WORDPARTLEFTEXTEND
:
3622 case SCI_WORDPARTRIGHT
:
3623 case SCI_WORDPARTRIGHTEXTEND
:
3625 case SCI_HOMEEXTEND
:
3626 case SCI_HOMERECTEXTEND
:
3627 case SCI_HOMEDISPLAY
:
3628 case SCI_HOMEDISPLAYEXTEND
:
3630 case SCI_HOMEWRAPEXTEND
:
3632 case SCI_VCHOMEEXTEND
:
3633 case SCI_VCHOMERECTEXTEND
:
3634 case SCI_VCHOMEDISPLAY
:
3635 case SCI_VCHOMEDISPLAYEXTEND
:
3636 case SCI_VCHOMEWRAP
:
3637 case SCI_VCHOMEWRAPEXTEND
:
3639 case SCI_LINEENDEXTEND
:
3640 case SCI_LINEENDRECTEXTEND
:
3641 case SCI_LINEENDDISPLAY
:
3642 case SCI_LINEENDDISPLAYEXTEND
:
3643 case SCI_LINEENDWRAP
:
3644 case SCI_LINEENDWRAPEXTEND
:
3645 return HorizontalMove(iMessage
);
3647 case SCI_DOCUMENTSTART
:
3651 case SCI_DOCUMENTSTARTEXTEND
:
3652 MovePositionTo(0, Selection::selStream
);
3655 case SCI_DOCUMENTEND
:
3656 MovePositionTo(pdoc
->Length());
3659 case SCI_DOCUMENTENDEXTEND
:
3660 MovePositionTo(pdoc
->Length(), Selection::selStream
);
3663 case SCI_STUTTEREDPAGEUP
:
3664 PageMove(-1, Selection::noSel
, true);
3666 case SCI_STUTTEREDPAGEUPEXTEND
:
3667 PageMove(-1, Selection::selStream
, true);
3669 case SCI_STUTTEREDPAGEDOWN
:
3670 PageMove(1, Selection::noSel
, true);
3672 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3673 PageMove(1, Selection::selStream
, true);
3678 case SCI_PAGEUPEXTEND
:
3679 PageMove(-1, Selection::selStream
);
3681 case SCI_PAGEUPRECTEXTEND
:
3682 PageMove(-1, Selection::selRectangle
);
3687 case SCI_PAGEDOWNEXTEND
:
3688 PageMove(1, Selection::selStream
);
3690 case SCI_PAGEDOWNRECTEXTEND
:
3691 PageMove(1, Selection::selRectangle
);
3693 case SCI_EDITTOGGLEOVERTYPE
:
3694 inOverstrike
= !inOverstrike
;
3695 ShowCaretAtCurrentPosition();
3696 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
3699 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3700 // Also unselect text
3702 if (sel
.Count() > 1) {
3703 // Drop additional selections
3704 InvalidateWholeSelection();
3705 sel
.DropAdditionalRanges();
3708 case SCI_DELETEBACK
:
3710 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3713 EnsureCaretVisible();
3715 case SCI_DELETEBACKNOTLINE
:
3717 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3720 EnsureCaretVisible();
3724 if (caretSticky
== SC_CARETSTICKY_OFF
) {
3727 EnsureCaretVisible();
3728 ShowCaretAtCurrentPosition(); // Avoid blinking
3732 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3735 EnsureCaretVisible();
3736 ShowCaretAtCurrentPosition(); // Avoid blinking
3745 if (vs
.zoomLevel
< 20) {
3747 InvalidateStyleRedraw();
3752 if (vs
.zoomLevel
> -10) {
3754 InvalidateStyleRedraw();
3759 case SCI_DELWORDLEFT
:
3760 case SCI_DELWORDRIGHT
:
3761 case SCI_DELWORDRIGHTEND
:
3762 case SCI_DELLINELEFT
:
3763 case SCI_DELLINERIGHT
:
3764 return DelWordOrLine(iMessage
);
3766 case SCI_LINECOPY
: {
3767 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3768 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3769 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3770 pdoc
->LineStart(lineEnd
+ 1));
3774 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3775 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3776 int start
= pdoc
->LineStart(lineStart
);
3777 int end
= pdoc
->LineStart(lineEnd
+ 1);
3778 SetSelection(start
, end
);
3783 case SCI_LINEDELETE
: {
3784 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3785 int start
= pdoc
->LineStart(line
);
3786 int end
= pdoc
->LineStart(line
+ 1);
3787 pdoc
->DeleteChars(start
, end
- start
);
3790 case SCI_LINETRANSPOSE
:
3793 case SCI_LINEDUPLICATE
:
3796 case SCI_SELECTIONDUPLICATE
:
3800 ChangeCaseOfSelection(cmLower
);
3803 ChangeCaseOfSelection(cmUpper
);
3805 case SCI_SCROLLTOSTART
:
3808 case SCI_SCROLLTOEND
:
3809 ScrollTo(MaxScrollPos());
3815 int Editor::KeyDefault(int, int) {
3819 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
3821 int msg
= kmap
.Find(key
, modifiers
);
3825 return static_cast<int>(WndProc(msg
, 0, 0));
3829 return KeyDefault(key
, modifiers
);
3833 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3834 return KeyDownWithModifiers(key
, ModifierFlags(shift
, ctrl
, alt
), consumed
);
3837 void Editor::Indent(bool forwards
) {
3839 for (size_t r
=0; r
<sel
.Count(); r
++) {
3840 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
3841 int caretPosition
= sel
.Range(r
).caret
.Position();
3842 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
3843 if (lineOfAnchor
== lineCurrentPos
) {
3845 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
3846 caretPosition
= sel
.Range(r
).caret
.Position();
3847 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3849 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3850 int indentationStep
= pdoc
->IndentSize();
3851 const int posSelect
= pdoc
->SetLineIndentation(
3852 lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
3853 sel
.Range(r
) = SelectionRange(posSelect
);
3855 if (pdoc
->useTabs
) {
3856 const int lengthInserted
= pdoc
->InsertString(caretPosition
, "\t", 1);
3857 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3859 int numSpaces
= (pdoc
->tabInChars
) -
3860 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
3862 numSpaces
= pdoc
->tabInChars
;
3863 const std::string
spaceText(numSpaces
, ' ');
3864 const int lengthInserted
= pdoc
->InsertString(caretPosition
, spaceText
.c_str(),
3865 static_cast<int>(spaceText
.length()));
3866 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3870 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3872 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3873 int indentationStep
= pdoc
->IndentSize();
3874 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3875 sel
.Range(r
) = SelectionRange(posSelect
);
3877 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
3881 int newPos
= caretPosition
;
3882 while (pdoc
->GetColumn(newPos
) > newColumn
)
3884 sel
.Range(r
) = SelectionRange(newPos
);
3887 } else { // Multiline
3888 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
3889 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
3890 // Multiple lines selected so indent / dedent
3891 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3892 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3893 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
3894 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3895 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3896 if (lineOfAnchor
< lineCurrentPos
) {
3897 if (currentPosPosOnLine
== 0)
3898 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3900 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3902 if (anchorPosOnLine
== 0)
3903 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3905 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3909 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
3912 class CaseFolderASCII
: public CaseFolderTable
{
3917 ~CaseFolderASCII() {
3922 CaseFolder
*Editor::CaseFolderForEncoding() {
3923 // Simple default that only maps ASCII upper case to lower case.
3924 return new CaseFolderASCII();
3928 * Search of a text in the document, in the given range.
3929 * @return The position of the found text, -1 if not found.
3931 long Editor::FindText(
3932 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3933 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3934 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3936 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
3937 int lengthFound
= istrlen(ft
->lpstrText
);
3938 if (!pdoc
->HasCaseFolder())
3939 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3941 long pos
= pdoc
->FindText(
3942 static_cast<int>(ft
->chrg
.cpMin
),
3943 static_cast<int>(ft
->chrg
.cpMax
),
3945 static_cast<int>(wParam
),
3948 ft
->chrgText
.cpMin
= pos
;
3949 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3951 return static_cast<int>(pos
);
3952 } catch (RegexError
&) {
3953 errorStatus
= SC_STATUS_WARN_REGEX
;
3959 * Relocatable search support : Searches relative to current selection
3960 * point and sets the selection to the found text range with
3964 * Anchor following searches at current selection start: This allows
3965 * multiple incremental interactive searches to be macro recorded
3966 * while still setting the selection to found text so the find/select
3967 * operation is self-contained.
3969 void Editor::SearchAnchor() {
3970 searchAnchor
= SelectionStart().Position();
3974 * Find text from current search anchor: Must call @c SearchAnchor first.
3975 * Used for next text and previous text requests.
3976 * @return The position of the found text, -1 if not found.
3978 long Editor::SearchText(
3979 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3980 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3981 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3982 sptr_t lParam
) { ///< The text to search for.
3984 const char *txt
= reinterpret_cast<char *>(lParam
);
3986 int lengthFound
= istrlen(txt
);
3987 if (!pdoc
->HasCaseFolder())
3988 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3990 if (iMessage
== SCI_SEARCHNEXT
) {
3991 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3992 static_cast<int>(wParam
),
3995 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3996 static_cast<int>(wParam
),
3999 } catch (RegexError
&) {
4000 errorStatus
= SC_STATUS_WARN_REGEX
;
4004 SetSelection(static_cast<int>(pos
), static_cast<int>(pos
+ lengthFound
));
4010 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
4012 for (size_t i
=0; i
<ret
.size(); i
++) {
4013 switch (caseMapping
) {
4015 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
4016 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
4019 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
4020 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
4028 * Search for text in the target range of the document.
4029 * @return The position of the found text, -1 if not found.
4031 long Editor::SearchInTarget(const char *text
, int length
) {
4032 int lengthFound
= length
;
4034 if (!pdoc
->HasCaseFolder())
4035 pdoc
->SetCaseFolder(CaseFolderForEncoding());
4037 long pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4041 targetStart
= static_cast<int>(pos
);
4042 targetEnd
= static_cast<int>(pos
+ lengthFound
);
4045 } catch (RegexError
&) {
4046 errorStatus
= SC_STATUS_WARN_REGEX
;
4051 void Editor::GoToLine(int lineNo
) {
4052 if (lineNo
> pdoc
->LinesTotal())
4053 lineNo
= pdoc
->LinesTotal();
4056 SetEmptySelection(pdoc
->LineStart(lineNo
));
4057 ShowCaretAtCurrentPosition();
4058 EnsureCaretVisible();
4061 static bool Close(Point pt1
, Point pt2
, Point threshold
) {
4062 if (std::abs(pt1
.x
- pt2
.x
) > threshold
.x
)
4064 if (std::abs(pt1
.y
- pt2
.y
) > threshold
.y
)
4069 std::string
Editor::RangeText(int start
, int end
) const {
4071 int len
= end
- start
;
4072 std::string
ret(len
, '\0');
4073 for (int i
= 0; i
< len
; i
++) {
4074 ret
[i
] = pdoc
->CharAt(start
+ i
);
4078 return std::string();
4081 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
4083 if (allowLineCopy
) {
4084 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4085 int start
= pdoc
->LineStart(currentLine
);
4086 int end
= pdoc
->LineEnd(currentLine
);
4088 std::string text
= RangeText(start
, end
);
4089 if (pdoc
->eolMode
!= SC_EOL_LF
)
4090 text
.push_back('\r');
4091 if (pdoc
->eolMode
!= SC_EOL_CR
)
4092 text
.push_back('\n');
4093 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4094 vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
4098 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
4099 if (sel
.selType
== Selection::selRectangle
)
4100 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
4101 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
4102 SelectionRange current
= rangesInOrder
[r
];
4103 text
.append(RangeText(current
.Start().Position(), current
.End().Position()));
4104 if (sel
.selType
== Selection::selRectangle
) {
4105 if (pdoc
->eolMode
!= SC_EOL_LF
)
4106 text
.push_back('\r');
4107 if (pdoc
->eolMode
!= SC_EOL_CR
)
4108 text
.push_back('\n');
4111 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4112 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
4116 void Editor::CopyRangeToClipboard(int start
, int end
) {
4117 start
= pdoc
->ClampPositionIntoDocument(start
);
4118 end
= pdoc
->ClampPositionIntoDocument(end
);
4119 SelectionText selectedText
;
4120 std::string text
= RangeText(start
, end
);
4121 selectedText
.Copy(text
,
4122 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4123 CopyToClipboard(selectedText
);
4126 void Editor::CopyText(int length
, const char *text
) {
4127 SelectionText selectedText
;
4128 selectedText
.Copy(std::string(text
, length
),
4129 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4130 CopyToClipboard(selectedText
);
4133 void Editor::SetDragPosition(SelectionPosition newPos
) {
4134 if (newPos
.Position() >= 0) {
4135 newPos
= MovePositionOutsideChar(newPos
, 1);
4138 if (!(posDrag
== newPos
)) {
4140 if (FineTickerAvailable()) {
4141 FineTickerCancel(tickCaret
);
4142 if ((caret
.active
) && (caret
.period
> 0) && (newPos
.Position() < 0))
4143 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
4153 void Editor::DisplayCursor(Window::Cursor c
) {
4154 if (cursorMode
== SC_CURSORNORMAL
)
4157 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4160 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
4161 int xMove
= static_cast<int>(ptStart
.x
- ptNow
.x
);
4162 int yMove
= static_cast<int>(ptStart
.y
- ptNow
.y
);
4163 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
4164 return distanceSquared
> 16;
4167 void Editor::StartDrag() {
4168 // Always handled by subclasses
4169 //SetMouseCapture(true);
4170 //DisplayCursor(Window::cursorArrow);
4173 void Editor::DropAt(SelectionPosition position
, const char *value
, size_t lengthValue
, bool moving
, bool rectangular
) {
4174 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
4175 if (inDragDrop
== ddDragging
)
4176 dropWentOutside
= false;
4178 bool positionWasInSelection
= PositionInSelection(position
.Position());
4180 bool positionOnEdgeOfSelection
=
4181 (position
== SelectionStart()) || (position
== SelectionEnd());
4183 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
4184 (positionOnEdgeOfSelection
&& !moving
)) {
4186 SelectionPosition selStart
= SelectionStart();
4187 SelectionPosition selEnd
= SelectionEnd();
4191 SelectionPosition positionAfterDeletion
= position
;
4192 if ((inDragDrop
== ddDragging
) && moving
) {
4193 // Remove dragged out text
4194 if (rectangular
|| sel
.selType
== Selection::selLines
) {
4195 for (size_t r
=0; r
<sel
.Count(); r
++) {
4196 if (position
>= sel
.Range(r
).Start()) {
4197 if (position
> sel
.Range(r
).End()) {
4198 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
4200 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
4205 if (position
> selStart
) {
4206 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
4211 position
= positionAfterDeletion
;
4213 std::string convertedText
= Document::TransformLineEnds(value
, lengthValue
, pdoc
->eolMode
);
4216 PasteRectangular(position
, convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4217 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4218 SetEmptySelection(position
);
4220 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
4221 position
= RealizeVirtualSpace(position
);
4222 const int lengthInserted
= pdoc
->InsertString(
4223 position
.Position(), convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4224 if (lengthInserted
> 0) {
4225 SelectionPosition posAfterInsertion
= position
;
4226 posAfterInsertion
.Add(lengthInserted
);
4227 SetSelection(posAfterInsertion
, position
);
4230 } else if (inDragDrop
== ddDragging
) {
4231 SetEmptySelection(position
);
4235 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
4236 DropAt(position
, value
, strlen(value
), moving
, rectangular
);
4240 * @return true if given position is inside the selection,
4242 bool Editor::PositionInSelection(int pos
) {
4243 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
4244 for (size_t r
=0; r
<sel
.Count(); r
++) {
4245 if (sel
.Range(r
).Contains(pos
))
4251 bool Editor::PointInSelection(Point pt
) {
4252 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
4253 Point ptPos
= LocationFromPosition(pos
);
4254 for (size_t r
=0; r
<sel
.Count(); r
++) {
4255 SelectionRange range
= sel
.Range(r
);
4256 if (range
.Contains(pos
)) {
4258 if (pos
== range
.Start()) {
4259 // see if just before selection
4260 if (pt
.x
< ptPos
.x
) {
4264 if (pos
== range
.End()) {
4265 // see if just after selection
4266 if (pt
.x
> ptPos
.x
) {
4277 bool Editor::PointInSelMargin(Point pt
) const {
4278 // Really means: "Point in a margin"
4279 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4280 PRectangle rcSelMargin
= GetClientRectangle();
4281 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.leftMarginWidth
);
4282 rcSelMargin
.left
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.fixedColumnWidth
);
4283 return rcSelMargin
.ContainsWholePixel(pt
);
4289 Window::Cursor
Editor::GetMarginCursor(Point pt
) const {
4291 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
4292 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4293 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
4294 x
+= vs
.ms
[margin
].width
;
4296 return Window::cursorReverseArrow
;
4299 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
4300 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
4301 SetSelection(currentPos_
, anchor_
);
4304 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
4305 int selCurrentPos
, selAnchorPos
;
4307 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
4308 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
4309 if (lineAnchorPos_
< lineCurrentPos_
) {
4310 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
4311 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4312 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4313 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
4314 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4315 } else { // Same line, select it
4316 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4317 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4320 if (lineAnchorPos_
< lineCurrentPos_
) {
4321 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
4322 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4323 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4324 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4325 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
4326 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4327 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
4328 } else { // Same line, select it
4329 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4330 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4331 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4334 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
4337 void Editor::WordSelection(int pos
) {
4338 if (pos
< wordSelectAnchorStartPos
) {
4339 // Extend backward to the word containing pos.
4340 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
4341 // This ensures that a series of empty lines isn't counted as a single "word".
4342 if (!pdoc
->IsLineEndPosition(pos
))
4343 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
4344 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
4345 } else if (pos
> wordSelectAnchorEndPos
) {
4346 // Extend forward to the word containing the character to the left of pos.
4347 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
4348 // This ensures that a series of empty lines isn't counted as a single "word".
4349 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
4350 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
4351 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
4353 // Select only the anchored word
4354 if (pos
>= originalAnchorPos
)
4355 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
4357 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
4361 void Editor::DwellEnd(bool mouseMoved
) {
4363 ticksToDwell
= dwellDelay
;
4365 ticksToDwell
= SC_TIME_FOREVER
;
4366 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4368 NotifyDwelling(ptMouseLast
, dwelling
);
4370 if (FineTickerAvailable()) {
4371 FineTickerCancel(tickDwell
);
4372 if (mouseMoved
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4373 //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
4378 void Editor::MouseLeave() {
4379 SetHotSpotRange(NULL
);
4380 if (!HaveMouseCapture()) {
4381 ptMouseLast
= Point(-1,-1);
4386 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
4387 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
4388 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
4391 void Editor::ButtonDownWithModifiers(Point pt
, unsigned int curTime
, int modifiers
) {
4392 SetHoverIndicatorPoint(pt
);
4393 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
4395 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
4396 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
4397 const bool alt
= (modifiers
& SCI_ALT
) != 0;
4398 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
4399 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4400 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4401 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4402 inDragDrop
= ddNone
;
4403 sel
.SetMoveExtends(false);
4405 if (NotifyMarginClick(pt
, modifiers
))
4408 NotifyIndicatorClick(true, newPos
.Position(), modifiers
);
4410 bool inSelMargin
= PointInSelMargin(pt
);
4411 // In margin ctrl+(double)click should always select everything
4412 if (ctrl
&& inSelMargin
) {
4414 lastClickTime
= curTime
;
4418 if (shift
&& !inSelMargin
) {
4419 SetSelection(newPos
);
4421 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
, doubleClickCloseThreshold
)) {
4422 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4423 SetMouseCapture(true);
4424 if (FineTickerAvailable()) {
4425 FineTickerStart(tickScroll
, 100, 10);
4427 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
4428 SetEmptySelection(newPos
.Position());
4429 bool doubleClick
= false;
4430 // Stop mouse button bounce changing selection type
4431 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4433 // Inside margin selection type should be either selSubLine or selWholeLine.
4434 if (selectionType
== selSubLine
) {
4435 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
4436 // so we switch to selWholeLine in order to select whole line.
4437 selectionType
= selWholeLine
;
4438 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
4439 // If it is neither, reset selection type to line selection.
4440 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4443 if (selectionType
== selChar
) {
4444 selectionType
= selWord
;
4446 } else if (selectionType
== selWord
) {
4447 // Since we ended up here, we're inside a *triple* click, which should always select
4448 // whole line regardless of word wrap being enabled or not.
4449 selectionType
= selWholeLine
;
4451 selectionType
= selChar
;
4452 originalAnchorPos
= sel
.MainCaret();
4457 if (selectionType
== selWord
) {
4458 int charPos
= originalAnchorPos
;
4459 if (sel
.MainCaret() == originalAnchorPos
) {
4460 charPos
= PositionFromLocation(pt
, false, true);
4461 charPos
= MovePositionOutsideChar(charPos
, -1);
4464 int startWord
, endWord
;
4465 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
4466 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
4467 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
4469 // Selecting backwards, or anchor beyond last character on line. In these cases,
4470 // we select the word containing the character to the *left* of the anchor.
4471 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
4472 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
4473 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
4475 // Anchor at start of line; select nothing to begin with.
4476 startWord
= charPos
;
4481 wordSelectAnchorStartPos
= startWord
;
4482 wordSelectAnchorEndPos
= endWord
;
4483 wordSelectInitialCaretPos
= sel
.MainCaret();
4484 WordSelection(wordSelectInitialCaretPos
);
4485 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
4486 lineAnchorPos
= newPos
.Position();
4487 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4488 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4490 SetEmptySelection(sel
.MainCaret());
4492 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4494 NotifyDoubleClick(pt
, modifiers
);
4495 if (PositionIsHotspot(newCharPos
.Position()))
4496 NotifyHotSpotDoubleClicked(newCharPos
.Position(), modifiers
);
4498 } else { // Single click
4500 sel
.selType
= Selection::selStream
;
4502 // Single click in margin: select whole line or only subline if word wrap is enabled
4503 lineAnchorPos
= newPos
.Position();
4504 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4505 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4507 // Single shift+click in margin: select from line anchor to clicked line
4508 if (sel
.MainAnchor() > sel
.MainCaret())
4509 lineAnchorPos
= sel
.MainAnchor() - 1;
4511 lineAnchorPos
= sel
.MainAnchor();
4512 // Reset selection type if there is an empty selection.
4513 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
4514 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
4515 // This ensures that we continue selecting in the same selection mode.
4516 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
4517 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4518 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4521 SetDragPosition(SelectionPosition(invalidPosition
));
4522 SetMouseCapture(true);
4523 if (FineTickerAvailable()) {
4524 FineTickerStart(tickScroll
, 100, 10);
4527 if (PointIsHotspot(pt
)) {
4528 NotifyHotSpotClicked(newCharPos
.Position(), modifiers
);
4529 hotSpotClickPos
= newCharPos
.Position();
4532 if (PointInSelection(pt
) && !SelectionEmpty())
4533 inDragDrop
= ddInitial
;
4535 inDragDrop
= ddNone
;
4537 SetMouseCapture(true);
4538 if (FineTickerAvailable()) {
4539 FineTickerStart(tickScroll
, 100, 10);
4541 if (inDragDrop
!= ddInitial
) {
4542 SetDragPosition(SelectionPosition(invalidPosition
));
4544 if (ctrl
&& multipleSelection
) {
4545 SelectionRange
range(newPos
);
4546 sel
.TentativeSelection(range
);
4547 InvalidateSelection(range
, true);
4549 InvalidateSelection(SelectionRange(newPos
), true);
4550 if (sel
.Count() > 1)
4552 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
4554 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4555 SetSelection(newPos
, newPos
);
4558 SelectionPosition anchorCurrent
= newPos
;
4560 anchorCurrent
= sel
.IsRectangular() ?
4561 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
4562 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4563 selectionType
= selChar
;
4564 originalAnchorPos
= sel
.MainCaret();
4565 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
4566 SetRectangularRange();
4570 lastClickTime
= curTime
;
4572 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4573 ShowCaretAtCurrentPosition();
4576 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4577 return ButtonDownWithModifiers(pt
, curTime
, ModifierFlags(shift
, ctrl
, alt
));
4580 bool Editor::PositionIsHotspot(int position
) const {
4581 return vs
.styles
[pdoc
->StyleIndexAt(position
)].hotspot
;
4584 bool Editor::PointIsHotspot(Point pt
) {
4585 int pos
= PositionFromLocation(pt
, true, true);
4586 if (pos
== INVALID_POSITION
)
4588 return PositionIsHotspot(pos
);
4591 void Editor::SetHoverIndicatorPosition(int position
) {
4592 int hoverIndicatorPosPrev
= hoverIndicatorPos
;
4593 hoverIndicatorPos
= INVALID_POSITION
;
4594 if (vs
.indicatorsDynamic
== 0)
4596 if (position
!= INVALID_POSITION
) {
4597 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
4598 if (vs
.indicators
[deco
->indicator
].IsDynamic()) {
4599 if (pdoc
->decorations
.ValueAt(deco
->indicator
, position
)) {
4600 hoverIndicatorPos
= position
;
4605 if (hoverIndicatorPosPrev
!= hoverIndicatorPos
) {
4610 void Editor::SetHoverIndicatorPoint(Point pt
) {
4611 if (vs
.indicatorsDynamic
== 0) {
4612 SetHoverIndicatorPosition(INVALID_POSITION
);
4614 SetHoverIndicatorPosition(PositionFromLocation(pt
, true, true));
4618 void Editor::SetHotSpotRange(Point
*pt
) {
4620 int pos
= PositionFromLocation(*pt
, false, true);
4622 // If we don't limit this to word characters then the
4623 // range can encompass more than the run range and then
4624 // the underline will not be drawn properly.
4626 hsNew
.start
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4627 hsNew
.end
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4629 // Only invalidate the range if the hotspot range has changed...
4630 if (!(hsNew
== hotspot
)) {
4631 if (hotspot
.Valid()) {
4632 InvalidateRange(hotspot
.start
, hotspot
.end
);
4635 InvalidateRange(hotspot
.start
, hotspot
.end
);
4638 if (hotspot
.Valid()) {
4639 InvalidateRange(hotspot
.start
, hotspot
.end
);
4641 hotspot
= Range(invalidPosition
);
4645 Range
Editor::GetHotSpotRange() const {
4649 void Editor::ButtonMoveWithModifiers(Point pt
, int modifiers
) {
4650 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4654 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
4655 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4656 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
4658 if (inDragDrop
== ddInitial
) {
4659 if (DragThreshold(ptMouseLast
, pt
)) {
4660 SetMouseCapture(false);
4661 if (FineTickerAvailable()) {
4662 FineTickerCancel(tickScroll
);
4664 SetDragPosition(movePos
);
4665 CopySelectionRange(&drag
);
4672 PRectangle rcClient
= GetClientRectangle();
4673 Point ptOrigin
= GetVisibleOriginInMain();
4674 rcClient
.Move(0, -ptOrigin
.y
);
4675 if (FineTickerAvailable() && (dwellDelay
< SC_TIME_FOREVER
) && rcClient
.Contains(pt
)) {
4676 FineTickerStart(tickDwell
, dwellDelay
, dwellDelay
/10);
4678 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4679 if (HaveMouseCapture()) {
4681 // Slow down autoscrolling/selection
4682 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4683 if (autoScrollTimer
.ticksToWait
> 0)
4685 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4688 if (posDrag
.IsValid()) {
4689 SetDragPosition(movePos
);
4691 if (selectionType
== selChar
) {
4692 if (sel
.selType
== Selection::selStream
&& (modifiers
& SCI_ALT
) && mouseSelectionRectangularSwitch
) {
4693 sel
.selType
= Selection::selRectangle
;
4695 if (sel
.IsRectangular()) {
4696 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
4697 SetSelection(movePos
, sel
.RangeMain().anchor
);
4698 } else if (sel
.Count() > 1) {
4699 InvalidateSelection(sel
.RangeMain(), false);
4700 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
4701 sel
.TentativeSelection(range
);
4702 InvalidateSelection(range
, true);
4704 SetSelection(movePos
, sel
.RangeMain().anchor
);
4706 } else if (selectionType
== selWord
) {
4707 // Continue selecting by word
4708 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
4709 // No need to do anything. Previously this case was lumped
4710 // in with "Moved forward", but that can be harmful in this
4711 // case: a handler for the NotifyDoubleClick re-adjusts
4712 // the selection for a fancier definition of "word" (for
4713 // example, in Perl it is useful to include the leading
4714 // '$', '%' or '@' on variables for word selection). In this
4715 // the ButtonMove() called via Tick() for auto-scrolling
4716 // could result in the fancier word selection adjustment
4719 wordSelectInitialCaretPos
= -1;
4720 WordSelection(movePos
.Position());
4723 // Continue selecting by line
4724 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4729 int lineMove
= DisplayFromPosition(movePos
.Position());
4730 if (pt
.y
> rcClient
.bottom
) {
4731 ScrollTo(lineMove
- LinesOnScreen() + 1);
4733 } else if (pt
.y
< rcClient
.top
) {
4737 EnsureCaretVisible(false, false, true);
4739 if (hotspot
.Valid() && !PointIsHotspot(pt
))
4740 SetHotSpotRange(NULL
);
4742 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,true) != hotSpotClickPos
) {
4743 if (inDragDrop
== ddNone
) {
4744 DisplayCursor(Window::cursorText
);
4746 hotSpotClickPos
= INVALID_POSITION
;
4750 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4751 if (PointInSelMargin(pt
)) {
4752 DisplayCursor(GetMarginCursor(pt
));
4753 SetHotSpotRange(NULL
);
4754 return; // No need to test for selection
4757 // Display regular (drag) cursor over selection
4758 if (PointInSelection(pt
) && !SelectionEmpty()) {
4759 DisplayCursor(Window::cursorArrow
);
4761 SetHoverIndicatorPoint(pt
);
4762 if (PointIsHotspot(pt
)) {
4763 DisplayCursor(Window::cursorHand
);
4764 SetHotSpotRange(&pt
);
4766 if (hoverIndicatorPos
!= invalidPosition
)
4767 DisplayCursor(Window::cursorHand
);
4769 DisplayCursor(Window::cursorText
);
4770 SetHotSpotRange(NULL
);
4776 void Editor::ButtonMove(Point pt
) {
4777 ButtonMoveWithModifiers(pt
, 0);
4780 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4781 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
4782 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
4783 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4784 if (hoverIndicatorPos
!= INVALID_POSITION
)
4785 InvalidateRange(newPos
.Position(), newPos
.Position() + 1);
4786 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4787 if (inDragDrop
== ddInitial
) {
4788 inDragDrop
= ddNone
;
4789 SetEmptySelection(newPos
);
4790 selectionType
= selChar
;
4791 originalAnchorPos
= sel
.MainCaret();
4793 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
4794 hotSpotClickPos
= INVALID_POSITION
;
4795 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4796 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4797 NotifyHotSpotReleaseClick(newCharPos
.Position(), ctrl
? SCI_CTRL
: 0);
4799 if (HaveMouseCapture()) {
4800 if (PointInSelMargin(pt
)) {
4801 DisplayCursor(GetMarginCursor(pt
));
4803 DisplayCursor(Window::cursorText
);
4804 SetHotSpotRange(NULL
);
4807 SetMouseCapture(false);
4808 if (FineTickerAvailable()) {
4809 FineTickerCancel(tickScroll
);
4811 NotifyIndicatorClick(false, newPos
.Position(), 0);
4812 if (inDragDrop
== ddDragging
) {
4813 SelectionPosition selStart
= SelectionStart();
4814 SelectionPosition selEnd
= SelectionEnd();
4815 if (selStart
< selEnd
) {
4816 if (drag
.Length()) {
4817 const int length
= 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
);
4824 } else if (newPos
< selStart
) {
4825 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4826 const int lengthInserted
= pdoc
->InsertString(
4827 newPos
.Position(), drag
.Data(), length
);
4828 if (lengthInserted
> 0) {
4829 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4831 } else if (newPos
> selEnd
) {
4832 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4833 newPos
.Add(-static_cast<int>(drag
.Length()));
4834 const int lengthInserted
= pdoc
->InsertString(
4835 newPos
.Position(), drag
.Data(), length
);
4836 if (lengthInserted
> 0) {
4837 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4840 SetEmptySelection(newPos
.Position());
4844 selectionType
= selChar
;
4847 if (selectionType
== selChar
) {
4848 if (sel
.Count() > 1) {
4850 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
4851 InvalidateWholeSelection();
4853 SetSelection(newPos
, sel
.RangeMain().anchor
);
4856 sel
.CommitTentative();
4858 SetRectangularRange();
4859 lastClickTime
= curTime
;
4861 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4862 if (sel
.selType
== Selection::selStream
) {
4865 inDragDrop
= ddNone
;
4866 EnsureCaretVisible(false);
4870 // Called frequently to perform background UI including
4871 // caret blinking and automatic scrolling.
4872 void Editor::Tick() {
4873 if (HaveMouseCapture()) {
4875 ButtonMove(ptMouseLast
);
4877 if (caret
.period
> 0) {
4878 timer
.ticksToWait
-= timer
.tickSize
;
4879 if (timer
.ticksToWait
<= 0) {
4880 caret
.on
= !caret
.on
;
4881 timer
.ticksToWait
= caret
.period
;
4887 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
4888 scrollWidth
= view
.lineWidthMaxSeen
;
4891 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4892 (ticksToDwell
> 0) &&
4893 (!HaveMouseCapture()) &&
4894 (ptMouseLast
.y
>= 0)) {
4895 ticksToDwell
-= timer
.tickSize
;
4896 if (ticksToDwell
<= 0) {
4898 NotifyDwelling(ptMouseLast
, dwelling
);
4903 bool Editor::Idle() {
4904 bool needWrap
= Wrapping() && wrapPending
.NeedsWrap();
4907 // Wrap lines during idle.
4910 needWrap
= wrapPending
.NeedsWrap();
4911 } else if (needIdleStyling
) {
4915 // Add more idle things to do here, but make sure idleDone is
4916 // set correctly before the function returns. returning
4917 // false will stop calling this idle function until SetIdle() is
4920 const bool idleDone
= !needWrap
&& !needIdleStyling
; // && thatDone && theOtherThingDone...
4925 void Editor::SetTicking(bool) {
4926 // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
4927 // derived platform class but fine grained timers should now be implemented.
4928 // Either way, execution should not arrive here so assert failure.
4932 void Editor::TickFor(TickReason reason
) {
4935 caret
.on
= !caret
.on
;
4942 ButtonMove(ptMouseLast
);
4946 FineTickerCancel(tickWiden
);
4949 if ((!HaveMouseCapture()) &&
4950 (ptMouseLast
.y
>= 0)) {
4952 NotifyDwelling(ptMouseLast
, dwelling
);
4954 FineTickerCancel(tickDwell
);
4957 // tickPlatform handled by subclass
4962 bool Editor::FineTickerAvailable() {
4966 // FineTickerStart is be overridden by subclasses that support fine ticking so
4967 // this method should never be called.
4968 bool Editor::FineTickerRunning(TickReason
) {
4973 // FineTickerStart is be overridden by subclasses that support fine ticking so
4974 // this method should never be called.
4975 void Editor::FineTickerStart(TickReason
, int, int) {
4979 // FineTickerCancel is be overridden by subclasses that support fine ticking so
4980 // this method should never be called.
4981 void Editor::FineTickerCancel(TickReason
) {
4985 void Editor::SetFocusState(bool focusState
) {
4986 hasFocus
= focusState
;
4987 NotifyFocus(hasFocus
);
4991 ShowCaretAtCurrentPosition();
4994 int Editor::PositionAfterArea(PRectangle rcArea
) const {
4995 // The start of the document line after the display line after the area
4996 // This often means that the line after a modification is restyled which helps
4997 // detect multiline comment additions and heals single line comments
4998 int lineAfter
= TopLineOfMain() + static_cast<int>(rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
4999 if (lineAfter
< cs
.LinesDisplayed())
5000 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
5002 return pdoc
->Length();
5005 // Style to a position within the view. If this causes a change at end of last line then
5006 // affects later lines so style all the viewed text.
5007 void Editor::StyleToPositionInView(Position pos
) {
5008 int endWindow
= PositionAfterArea(GetClientDrawingRectangle());
5009 if (pos
> endWindow
)
5011 const int styleAtEnd
= pdoc
->StyleIndexAt(pos
-1);
5012 pdoc
->EnsureStyledTo(pos
);
5013 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleIndexAt(pos
-1))) {
5014 // Style at end of line changed so is multi-line change like starting a comment
5015 // so require rest of window to be styled.
5016 DiscardOverdraw(); // Prepared bitmaps may be invalid
5017 // DiscardOverdraw may have truncated client drawing area so recalculate endWindow
5018 endWindow
= PositionAfterArea(GetClientDrawingRectangle());
5019 pdoc
->EnsureStyledTo(endWindow
);
5023 int Editor::PositionAfterMaxStyling(int posMax
, bool scrolling
) const {
5024 if ((idleStyling
== SC_IDLESTYLING_NONE
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5025 // Both states do not limit styling
5029 // Try to keep time taken by styling reasonable so interaction remains smooth.
5030 // When scrolling, allow less time to ensure responsive
5031 const double secondsAllowed
= scrolling
? 0.005 : 0.02;
5033 const int linesToStyle
= Platform::Clamp(static_cast<int>(secondsAllowed
/ pdoc
->durationStyleOneLine
),
5035 const int stylingMaxLine
= std::min(
5036 static_cast<int>(pdoc
->LineFromPosition(pdoc
->GetEndStyled()) + linesToStyle
),
5037 pdoc
->LinesTotal());
5038 return std::min(static_cast<int>(pdoc
->LineStart(stylingMaxLine
)), posMax
);
5041 void Editor::StartIdleStyling(bool truncatedLastStyling
) {
5042 if ((idleStyling
== SC_IDLESTYLING_ALL
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5043 if (pdoc
->GetEndStyled() < pdoc
->Length()) {
5044 // Style remainder of document in idle time
5045 needIdleStyling
= true;
5047 } else if (truncatedLastStyling
) {
5048 needIdleStyling
= true;
5051 if (needIdleStyling
) {
5056 // Style for an area but bound the amount of styling to remain responsive
5057 void Editor::StyleAreaBounded(PRectangle rcArea
, bool scrolling
) {
5058 const int posAfterArea
= PositionAfterArea(rcArea
);
5059 const int posAfterMax
= PositionAfterMaxStyling(posAfterArea
, scrolling
);
5060 if (posAfterMax
< posAfterArea
) {
5061 // Idle styling may be performed before current visible area
5062 // Style a bit now then style further in idle time
5063 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5065 // Can style all wanted now.
5066 StyleToPositionInView(posAfterArea
);
5068 StartIdleStyling(posAfterMax
< posAfterArea
);
5071 void Editor::IdleStyling() {
5072 const int posAfterArea
= PositionAfterArea(GetClientRectangle());
5073 const int endGoal
= (idleStyling
>= SC_IDLESTYLING_AFTERVISIBLE
) ?
5074 pdoc
->Length() : posAfterArea
;
5075 const int posAfterMax
= PositionAfterMaxStyling(endGoal
, false);
5076 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5077 if (pdoc
->GetEndStyled() >= endGoal
) {
5078 needIdleStyling
= false;
5082 void Editor::IdleWork() {
5083 // Style the line after the modification as this allows modifications that change just the
5084 // line of the modification to heal instead of propagating to the rest of the window.
5085 if (workNeeded
.items
& WorkNeeded::workStyle
) {
5086 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(workNeeded
.upTo
) + 2));
5092 void Editor::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
5093 workNeeded
.Need(items
, upTo
);
5096 bool Editor::PaintContains(PRectangle rc
) {
5100 return rcPaint
.Contains(rc
);
5104 bool Editor::PaintContainsMargin() {
5105 if (wMargin
.GetID()) {
5106 // With separate margin view, paint of text view
5107 // never contains margin.
5110 PRectangle rcSelMargin
= GetClientRectangle();
5111 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
);
5112 return PaintContains(rcSelMargin
);
5115 void Editor::CheckForChangeOutsidePaint(Range r
) {
5116 if (paintState
== painting
&& !paintingAllText
) {
5117 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5121 PRectangle rcRange
= RectangleFromRange(r
, 0);
5122 PRectangle rcText
= GetTextRectangle();
5123 if (rcRange
.top
< rcText
.top
) {
5124 rcRange
.top
= rcText
.top
;
5126 if (rcRange
.bottom
> rcText
.bottom
) {
5127 rcRange
.bottom
= rcText
.bottom
;
5130 if (!PaintContains(rcRange
)) {
5132 paintAbandonedByStyling
= true;
5137 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5138 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5139 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5140 CheckForChangeOutsidePaint(Range(braces
[0]));
5141 CheckForChangeOutsidePaint(Range(pos0
));
5144 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5145 CheckForChangeOutsidePaint(Range(braces
[1]));
5146 CheckForChangeOutsidePaint(Range(pos1
));
5149 bracesMatchStyle
= matchStyle
;
5150 if (paintState
== notPainting
) {
5156 void Editor::SetAnnotationHeights(int start
, int end
) {
5157 if (vs
.annotationVisible
) {
5159 bool changedHeight
= false;
5160 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
5161 int linesWrapped
= 1;
5163 AutoSurface
surface(this);
5164 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5165 if (surface
&& ll
) {
5166 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5167 linesWrapped
= ll
->lines
;
5170 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
5171 changedHeight
= true;
5173 if (changedHeight
) {
5179 void Editor::SetDocPointer(Document
*document
) {
5180 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5181 pdoc
->RemoveWatcher(this, 0);
5183 if (document
== NULL
) {
5184 pdoc
= new Document();
5190 // Ensure all positions within document
5195 braces
[0] = invalidPosition
;
5196 braces
[1] = invalidPosition
;
5198 vs
.ReleaseAllExtendedStyles();
5200 SetRepresentations();
5202 // Reset the contraction state to fully shown.
5204 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5205 SetAnnotationHeights(0, pdoc
->LinesTotal());
5206 view
.llc
.Deallocate();
5209 hotspot
= Range(invalidPosition
);
5210 hoverIndicatorPos
= invalidPosition
;
5212 view
.ClearAllTabstops();
5214 pdoc
->AddWatcher(this, 0);
5219 void Editor::SetAnnotationVisible(int visible
) {
5220 if (vs
.annotationVisible
!= visible
) {
5221 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
5222 vs
.annotationVisible
= visible
;
5223 if (changedFromOrToHidden
) {
5224 int dir
= vs
.annotationVisible
? 1 : -1;
5225 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
5226 int annotationLines
= pdoc
->AnnotationLines(line
);
5227 if (annotationLines
> 0) {
5228 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
5237 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5239 int Editor::ExpandLine(int line
) {
5240 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5242 while (line
<= lineMaxSubord
) {
5243 cs
.SetVisible(line
, line
, true);
5244 int level
= pdoc
->GetLevel(line
);
5245 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5246 if (cs
.GetExpanded(line
)) {
5247 line
= ExpandLine(line
);
5249 line
= pdoc
->GetLastChild(line
);
5254 return lineMaxSubord
;
5257 void Editor::SetFoldExpanded(int lineDoc
, bool expanded
) {
5258 if (cs
.SetExpanded(lineDoc
, expanded
)) {
5263 void Editor::FoldLine(int line
, int action
) {
5265 if (action
== SC_FOLDACTION_TOGGLE
) {
5266 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5267 line
= pdoc
->GetFoldParent(line
);
5271 action
= (cs
.GetExpanded(line
)) ? SC_FOLDACTION_CONTRACT
: SC_FOLDACTION_EXPAND
;
5274 if (action
== SC_FOLDACTION_CONTRACT
) {
5275 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5276 if (lineMaxSubord
> line
) {
5277 cs
.SetExpanded(line
, 0);
5278 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5280 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
5281 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5282 // This does not re-expand the fold
5283 EnsureCaretVisible();
5288 if (!(cs
.GetVisible(line
))) {
5289 EnsureLineVisible(line
, false);
5292 cs
.SetExpanded(line
, 1);
5301 void Editor::FoldExpand(int line
, int action
, int level
) {
5302 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5303 if (action
== SC_FOLDACTION_TOGGLE
) {
5304 expanding
= !cs
.GetExpanded(line
);
5306 // Ensure child lines lexed and fold information extracted before
5307 // flipping the state.
5308 pdoc
->GetLastChild(line
, LevelNumber(level
));
5309 SetFoldExpanded(line
, expanding
);
5310 if (expanding
&& (cs
.HiddenLines() == 0))
5313 int lineMaxSubord
= pdoc
->GetLastChild(line
, LevelNumber(level
));
5315 cs
.SetVisible(line
, lineMaxSubord
, expanding
);
5316 while (line
<= lineMaxSubord
) {
5317 int levelLine
= pdoc
->GetLevel(line
);
5318 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5319 SetFoldExpanded(line
, expanding
);
5327 int Editor::ContractedFoldNext(int lineStart
) const {
5328 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
5329 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
5331 line
= cs
.ContractedNext(line
+1);
5340 * Recurse up from this line to find any folds that prevent this line from being visible
5341 * and unfold them all.
5343 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5345 // In case in need of wrapping to ensure DisplayFromDoc works.
5346 if (lineDoc
>= wrapPending
.start
)
5349 if (!cs
.GetVisible(lineDoc
)) {
5350 // Back up to find a non-blank line
5351 int lookLine
= lineDoc
;
5352 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
5353 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
5354 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
5356 int lineParent
= pdoc
->GetFoldParent(lookLine
);
5357 if (lineParent
< 0) {
5358 // Backed up to a top level line, so try to find parent of initial line
5359 lineParent
= pdoc
->GetFoldParent(lineDoc
);
5361 if (lineParent
>= 0) {
5362 if (lineDoc
!= lineParent
)
5363 EnsureLineVisible(lineParent
, enforcePolicy
);
5364 if (!cs
.GetExpanded(lineParent
)) {
5365 cs
.SetExpanded(lineParent
, 1);
5366 ExpandLine(lineParent
);
5372 if (enforcePolicy
) {
5373 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5374 if (visiblePolicy
& VISIBLE_SLOP
) {
5375 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5376 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5377 SetVerticalScrollPos();
5379 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5380 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5381 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5382 SetVerticalScrollPos();
5386 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5387 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5388 SetVerticalScrollPos();
5395 void Editor::FoldAll(int action
) {
5396 pdoc
->EnsureStyledTo(pdoc
->Length());
5397 int maxLine
= pdoc
->LinesTotal();
5398 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5399 if (action
== SC_FOLDACTION_TOGGLE
) {
5400 // Discover current state
5401 for (int lineSeek
= 0; lineSeek
< maxLine
; lineSeek
++) {
5402 if (pdoc
->GetLevel(lineSeek
) & SC_FOLDLEVELHEADERFLAG
) {
5403 expanding
= !cs
.GetExpanded(lineSeek
);
5409 cs
.SetVisible(0, maxLine
-1, true);
5410 for (int line
= 0; line
< maxLine
; line
++) {
5411 int levelLine
= pdoc
->GetLevel(line
);
5412 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5413 SetFoldExpanded(line
, true);
5417 for (int line
= 0; line
< maxLine
; line
++) {
5418 int level
= pdoc
->GetLevel(line
);
5419 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
5420 (SC_FOLDLEVELBASE
== LevelNumber(level
))) {
5421 SetFoldExpanded(line
, false);
5422 int lineMaxSubord
= pdoc
->GetLastChild(line
, -1);
5423 if (lineMaxSubord
> line
) {
5424 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5433 void Editor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
5434 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
5435 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
5436 // Adding a fold point.
5437 if (cs
.SetExpanded(line
, true)) {
5440 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5442 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
5443 const int prevLine
= line
- 1;
5444 const int prevLineLevel
= pdoc
->GetLevel(prevLine
);
5446 // Combining two blocks where the first block is collapsed (e.g. by deleting the line(s) which separate(s) the two blocks)
5447 if ((LevelNumber(prevLineLevel
) == LevelNumber(levelNow
)) && !cs
.GetVisible(prevLine
))
5448 FoldLine(pdoc
->GetFoldParent(prevLine
), SC_FOLDACTION_EXPAND
);
5450 if (!cs
.GetExpanded(line
)) {
5451 // Removing the fold from one that has been contracted so should expand
5452 // otherwise lines are left invisible with no way to make them visible
5453 if (cs
.SetExpanded(line
, true)) {
5456 // Combining two blocks where the second one is collapsed (e.g. by adding characters in the line which separates the two blocks)
5457 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5460 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) &&
5461 (LevelNumber(levelPrev
) > LevelNumber(levelNow
))) {
5462 if (cs
.HiddenLines()) {
5463 // See if should still be hidden
5464 int parentLine
= pdoc
->GetFoldParent(line
);
5465 if ((parentLine
< 0) || (cs
.GetExpanded(parentLine
) && cs
.GetVisible(parentLine
))) {
5466 cs
.SetVisible(line
, line
, true);
5473 // Combining two blocks where the first one is collapsed (e.g. by adding characters in the line which separates the two blocks)
5474 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) && (LevelNumber(levelPrev
) < LevelNumber(levelNow
))) {
5475 if (cs
.HiddenLines()) {
5476 const int parentLine
= pdoc
->GetFoldParent(line
);
5477 if (!cs
.GetExpanded(parentLine
) && cs
.GetExpanded(line
))
5478 FoldLine(parentLine
, SC_FOLDACTION_EXPAND
);
5483 void Editor::NeedShown(int pos
, int len
) {
5484 if (foldAutomatic
& SC_AUTOMATICFOLD_SHOW
) {
5485 int lineStart
= pdoc
->LineFromPosition(pos
);
5486 int lineEnd
= pdoc
->LineFromPosition(pos
+len
);
5487 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
5488 EnsureLineVisible(line
, false);
5491 NotifyNeedShown(pos
, len
);
5495 int Editor::GetTag(char *tagValue
, int tagNumber
) {
5496 const char *text
= 0;
5498 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
5499 char name
[3] = "\\?";
5500 name
[1] = static_cast<char>(tagNumber
+ '0');
5502 text
= pdoc
->SubstituteByPosition(name
, &length
);
5506 memcpy(tagValue
, text
, length
+ 1);
5513 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5516 length
= istrlen(text
);
5517 if (replacePatterns
) {
5518 text
= pdoc
->SubstituteByPosition(text
, &length
);
5523 if (targetStart
!= targetEnd
)
5524 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5525 targetEnd
= targetStart
;
5526 const int lengthInserted
= pdoc
->InsertString(targetStart
, text
, length
);
5527 targetEnd
= targetStart
+ lengthInserted
;
5531 bool Editor::IsUnicodeMode() const {
5532 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5535 int Editor::CodePage() const {
5537 return pdoc
->dbcsCodePage
;
5542 int Editor::WrapCount(int line
) {
5543 AutoSurface
surface(this);
5544 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5546 if (surface
&& ll
) {
5547 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5554 void Editor::AddStyledText(char *buffer
, int appendLength
) {
5555 // The buffer consists of alternating character bytes and style bytes
5556 int textLength
= appendLength
/ 2;
5557 std::string
text(textLength
, '\0');
5559 for (i
= 0; i
< textLength
; i
++) {
5560 text
[i
] = buffer
[i
*2];
5562 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), text
.c_str(), textLength
);
5563 for (i
= 0; i
< textLength
; i
++) {
5564 text
[i
] = buffer
[i
*2+1];
5566 pdoc
->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
5567 pdoc
->SetStyles(textLength
, text
.c_str());
5568 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5571 static bool ValidMargin(uptr_t wParam
) {
5572 return wParam
<= SC_MAX_MARGIN
;
5575 static char *CharPtrFromSPtr(sptr_t lParam
) {
5576 return reinterpret_cast<char *>(lParam
);
5579 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5580 vs
.EnsureStyle(wParam
);
5582 case SCI_STYLESETFORE
:
5583 vs
.styles
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
5585 case SCI_STYLESETBACK
:
5586 vs
.styles
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
5588 case SCI_STYLESETBOLD
:
5589 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
5591 case SCI_STYLESETWEIGHT
:
5592 vs
.styles
[wParam
].weight
= static_cast<int>(lParam
);
5594 case SCI_STYLESETITALIC
:
5595 vs
.styles
[wParam
].italic
= lParam
!= 0;
5597 case SCI_STYLESETEOLFILLED
:
5598 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5600 case SCI_STYLESETSIZE
:
5601 vs
.styles
[wParam
].size
= static_cast<int>(lParam
* SC_FONT_SIZE_MULTIPLIER
);
5603 case SCI_STYLESETSIZEFRACTIONAL
:
5604 vs
.styles
[wParam
].size
= static_cast<int>(lParam
);
5606 case SCI_STYLESETFONT
:
5608 vs
.SetStyleFontName(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5611 case SCI_STYLESETUNDERLINE
:
5612 vs
.styles
[wParam
].underline
= lParam
!= 0;
5614 case SCI_STYLESETCASE
:
5615 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5617 case SCI_STYLESETCHARACTERSET
:
5618 vs
.styles
[wParam
].characterSet
= static_cast<int>(lParam
);
5619 pdoc
->SetCaseFolder(NULL
);
5621 case SCI_STYLESETVISIBLE
:
5622 vs
.styles
[wParam
].visible
= lParam
!= 0;
5624 case SCI_STYLESETCHANGEABLE
:
5625 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5627 case SCI_STYLESETHOTSPOT
:
5628 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5631 InvalidateStyleRedraw();
5634 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5635 vs
.EnsureStyle(wParam
);
5637 case SCI_STYLEGETFORE
:
5638 return vs
.styles
[wParam
].fore
.AsLong();
5639 case SCI_STYLEGETBACK
:
5640 return vs
.styles
[wParam
].back
.AsLong();
5641 case SCI_STYLEGETBOLD
:
5642 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
5643 case SCI_STYLEGETWEIGHT
:
5644 return vs
.styles
[wParam
].weight
;
5645 case SCI_STYLEGETITALIC
:
5646 return vs
.styles
[wParam
].italic
? 1 : 0;
5647 case SCI_STYLEGETEOLFILLED
:
5648 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5649 case SCI_STYLEGETSIZE
:
5650 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
5651 case SCI_STYLEGETSIZEFRACTIONAL
:
5652 return vs
.styles
[wParam
].size
;
5653 case SCI_STYLEGETFONT
:
5654 return StringResult(lParam
, vs
.styles
[wParam
].fontName
);
5655 case SCI_STYLEGETUNDERLINE
:
5656 return vs
.styles
[wParam
].underline
? 1 : 0;
5657 case SCI_STYLEGETCASE
:
5658 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5659 case SCI_STYLEGETCHARACTERSET
:
5660 return vs
.styles
[wParam
].characterSet
;
5661 case SCI_STYLEGETVISIBLE
:
5662 return vs
.styles
[wParam
].visible
? 1 : 0;
5663 case SCI_STYLEGETCHANGEABLE
:
5664 return vs
.styles
[wParam
].changeable
? 1 : 0;
5665 case SCI_STYLEGETHOTSPOT
:
5666 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5671 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
5672 const size_t len
= val
? strlen(val
) : 0;
5674 char *ptr
= CharPtrFromSPtr(lParam
);
5676 memcpy(ptr
, val
, len
+1);
5680 return len
; // Not including NUL
5683 sptr_t
Editor::BytesResult(sptr_t lParam
, const unsigned char *val
, size_t len
) {
5684 // No NUL termination: len is number of valid/displayed bytes
5685 if ((lParam
) && (len
> 0)) {
5686 char *ptr
= CharPtrFromSPtr(lParam
);
5688 memcpy(ptr
, val
, len
);
5692 return val
? len
: 0;
5695 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5696 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5698 // Optional macro recording hook
5700 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5706 return pdoc
->Length() + 1;
5709 char *ptr
= CharPtrFromSPtr(lParam
);
5710 unsigned int iChar
= 0;
5711 for (; iChar
< wParam
- 1; iChar
++)
5712 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5721 pdoc
->DeleteChars(0, pdoc
->Length());
5722 SetEmptySelection(0);
5723 const char *text
= CharPtrFromSPtr(lParam
);
5724 pdoc
->InsertString(0, text
, istrlen(text
));
5728 case SCI_GETTEXTLENGTH
:
5729 return pdoc
->Length();
5740 case SCI_COPYALLOWLINE
:
5744 case SCI_VERTICALCENTRECARET
:
5745 VerticalCentreCaret();
5748 case SCI_MOVESELECTEDLINESUP
:
5749 MoveSelectedLinesUp();
5752 case SCI_MOVESELECTEDLINESDOWN
:
5753 MoveSelectedLinesDown();
5757 CopyRangeToClipboard(static_cast<int>(wParam
), static_cast<int>(lParam
));
5761 CopyText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5766 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5769 EnsureCaretVisible();
5775 EnsureCaretVisible();
5784 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5786 case SCI_EMPTYUNDOBUFFER
:
5787 pdoc
->DeleteUndoHistory();
5790 case SCI_GETFIRSTVISIBLELINE
:
5793 case SCI_SETFIRSTVISIBLELINE
:
5794 ScrollTo(static_cast<int>(wParam
));
5797 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5798 int lineStart
= pdoc
->LineStart(static_cast<int>(wParam
));
5799 int lineEnd
= pdoc
->LineStart(static_cast<int>(wParam
+ 1));
5801 return lineEnd
- lineStart
;
5803 char *ptr
= CharPtrFromSPtr(lParam
);
5805 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5806 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5811 case SCI_GETLINECOUNT
:
5812 if (pdoc
->LinesTotal() == 0)
5815 return pdoc
->LinesTotal();
5818 return !pdoc
->IsSavePoint();
5821 int nStart
= static_cast<int>(wParam
);
5822 int nEnd
= static_cast<int>(lParam
);
5824 nEnd
= pdoc
->Length();
5826 nStart
= nEnd
; // Remove selection
5827 InvalidateSelection(SelectionRange(nStart
, nEnd
));
5829 sel
.selType
= Selection::selStream
;
5830 SetSelection(nEnd
, nStart
);
5831 EnsureCaretVisible();
5835 case SCI_GETSELTEXT
: {
5836 SelectionText selectedText
;
5837 CopySelectionRange(&selectedText
);
5839 return selectedText
.LengthWithTerminator();
5841 char *ptr
= CharPtrFromSPtr(lParam
);
5842 unsigned int iChar
= 0;
5843 if (selectedText
.Length()) {
5844 for (; iChar
< selectedText
.LengthWithTerminator(); iChar
++)
5845 ptr
[iChar
] = selectedText
.Data()[iChar
];
5853 case SCI_LINEFROMPOSITION
:
5854 if (static_cast<int>(wParam
) < 0)
5856 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
5858 case SCI_POSITIONFROMLINE
:
5859 if (static_cast<int>(wParam
) < 0)
5860 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
5862 return 0; // Even if there is no text, there is a first line that starts at 0
5863 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5865 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5867 return pdoc
->LineStart(static_cast<int>(wParam
));
5869 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5870 case SCI_LINELENGTH
:
5871 if ((static_cast<int>(wParam
) < 0) ||
5872 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5874 return pdoc
->LineStart(static_cast<int>(wParam
) + 1) - pdoc
->LineStart(static_cast<int>(wParam
));
5876 case SCI_REPLACESEL
: {
5881 char *replacement
= CharPtrFromSPtr(lParam
);
5882 const int lengthInserted
= pdoc
->InsertString(
5883 sel
.MainCaret(), replacement
, istrlen(replacement
));
5884 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5885 EnsureCaretVisible();
5889 case SCI_SETTARGETSTART
:
5890 targetStart
= static_cast<int>(wParam
);
5893 case SCI_GETTARGETSTART
:
5896 case SCI_SETTARGETEND
:
5897 targetEnd
= static_cast<int>(wParam
);
5900 case SCI_GETTARGETEND
:
5903 case SCI_SETTARGETRANGE
:
5904 targetStart
= static_cast<int>(wParam
);
5905 targetEnd
= static_cast<int>(lParam
);
5908 case SCI_TARGETWHOLEDOCUMENT
:
5910 targetEnd
= pdoc
->Length();
5913 case SCI_TARGETFROMSELECTION
:
5914 if (sel
.MainCaret() < sel
.MainAnchor()) {
5915 targetStart
= sel
.MainCaret();
5916 targetEnd
= sel
.MainAnchor();
5918 targetStart
= sel
.MainAnchor();
5919 targetEnd
= sel
.MainCaret();
5923 case SCI_GETTARGETTEXT
: {
5924 std::string text
= RangeText(targetStart
, targetEnd
);
5925 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(text
.c_str()), text
.length());
5928 case SCI_REPLACETARGET
:
5929 PLATFORM_ASSERT(lParam
);
5930 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5932 case SCI_REPLACETARGETRE
:
5933 PLATFORM_ASSERT(lParam
);
5934 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5936 case SCI_SEARCHINTARGET
:
5937 PLATFORM_ASSERT(lParam
);
5938 return SearchInTarget(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5940 case SCI_SETSEARCHFLAGS
:
5941 searchFlags
= static_cast<int>(wParam
);
5944 case SCI_GETSEARCHFLAGS
:
5948 return GetTag(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5950 case SCI_POSITIONBEFORE
:
5951 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) - 1, -1, true);
5953 case SCI_POSITIONAFTER
:
5954 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) + 1, 1, true);
5956 case SCI_POSITIONRELATIVE
:
5957 return Platform::Clamp(pdoc
->GetRelativePosition(static_cast<int>(wParam
), static_cast<int>(lParam
)), 0, pdoc
->Length());
5959 case SCI_LINESCROLL
:
5960 ScrollTo(topLine
+ static_cast<int>(lParam
));
5961 HorizontalScrollTo(xOffset
+ static_cast<int>(wParam
)* static_cast<int>(vs
.spaceWidth
));
5964 case SCI_SETXOFFSET
:
5965 xOffset
= static_cast<int>(wParam
);
5966 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
5967 SetHorizontalScrollPos();
5971 case SCI_GETXOFFSET
:
5974 case SCI_CHOOSECARETX
:
5978 case SCI_SCROLLCARET
:
5979 EnsureCaretVisible();
5982 case SCI_SETREADONLY
:
5983 pdoc
->SetReadOnly(wParam
!= 0);
5986 case SCI_GETREADONLY
:
5987 return pdoc
->IsReadOnly();
5992 case SCI_POINTXFROMPOSITION
:
5996 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5997 // Convert to view-relative
5998 return static_cast<int>(pt
.x
) - vs
.textStart
+ vs
.fixedColumnWidth
;
6001 case SCI_POINTYFROMPOSITION
:
6005 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
6006 return static_cast<int>(pt
.y
);
6010 return FindText(wParam
, lParam
);
6012 case SCI_GETTEXTRANGE
: {
6015 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6016 int cpMax
= static_cast<int>(tr
->chrg
.cpMax
);
6018 cpMax
= pdoc
->Length();
6019 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
6020 int len
= static_cast<int>(cpMax
- tr
->chrg
.cpMin
); // No -1 as cpMin and cpMax are referring to inter character positions
6021 pdoc
->GetCharRange(tr
->lpstrText
, static_cast<int>(tr
->chrg
.cpMin
), len
);
6022 // Spec says copied text is terminated with a NUL
6023 tr
->lpstrText
[len
] = '\0';
6024 return len
; // Not including NUL
6027 case SCI_HIDESELECTION
:
6028 view
.hideSelection
= wParam
!= 0;
6032 case SCI_FORMATRANGE
:
6033 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
6035 case SCI_GETMARGINLEFT
:
6036 return vs
.leftMarginWidth
;
6038 case SCI_GETMARGINRIGHT
:
6039 return vs
.rightMarginWidth
;
6041 case SCI_SETMARGINLEFT
:
6042 lastXChosen
+= static_cast<int>(lParam
) - vs
.leftMarginWidth
;
6043 vs
.leftMarginWidth
= static_cast<int>(lParam
);
6044 InvalidateStyleRedraw();
6047 case SCI_SETMARGINRIGHT
:
6048 vs
.rightMarginWidth
= static_cast<int>(lParam
);
6049 InvalidateStyleRedraw();
6052 // Control specific mesages
6057 const int lengthInserted
= pdoc
->InsertString(
6058 CurrentPosition(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6059 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
6063 case SCI_ADDSTYLEDTEXT
:
6065 AddStyledText(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6068 case SCI_INSERTTEXT
: {
6071 int insertPos
= static_cast<int>(wParam
);
6072 if (static_cast<int>(wParam
) == -1)
6073 insertPos
= CurrentPosition();
6074 int newCurrent
= CurrentPosition();
6075 char *sz
= CharPtrFromSPtr(lParam
);
6076 const int lengthInserted
= pdoc
->InsertString(insertPos
, sz
, istrlen(sz
));
6077 if (newCurrent
> insertPos
)
6078 newCurrent
+= lengthInserted
;
6079 SetEmptySelection(newCurrent
);
6083 case SCI_CHANGEINSERTION
:
6084 PLATFORM_ASSERT(lParam
);
6085 pdoc
->ChangeInsertion(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6088 case SCI_APPENDTEXT
:
6089 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6096 case SCI_DELETERANGE
:
6097 pdoc
->DeleteChars(static_cast<int>(wParam
), static_cast<int>(lParam
));
6100 case SCI_CLEARDOCUMENTSTYLE
:
6101 ClearDocumentStyle();
6104 case SCI_SETUNDOCOLLECTION
:
6105 pdoc
->SetUndoCollection(wParam
!= 0);
6108 case SCI_GETUNDOCOLLECTION
:
6109 return pdoc
->IsCollectingUndo();
6111 case SCI_BEGINUNDOACTION
:
6112 pdoc
->BeginUndoAction();
6115 case SCI_ENDUNDOACTION
:
6116 pdoc
->EndUndoAction();
6119 case SCI_GETCARETPERIOD
:
6120 return caret
.period
;
6122 case SCI_SETCARETPERIOD
:
6123 CaretSetPeriod(static_cast<int>(wParam
));
6126 case SCI_GETWORDCHARS
:
6127 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
6129 case SCI_SETWORDCHARS
: {
6130 pdoc
->SetDefaultCharClasses(false);
6133 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6137 case SCI_GETWHITESPACECHARS
:
6138 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
6140 case SCI_SETWHITESPACECHARS
: {
6143 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6147 case SCI_GETPUNCTUATIONCHARS
:
6148 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
6150 case SCI_SETPUNCTUATIONCHARS
: {
6153 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
6157 case SCI_SETCHARSDEFAULT
:
6158 pdoc
->SetDefaultCharClasses(true);
6162 return pdoc
->Length();
6165 pdoc
->Allocate(static_cast<int>(wParam
));
6169 return pdoc
->CharAt(static_cast<int>(wParam
));
6171 case SCI_SETCURRENTPOS
:
6172 if (sel
.IsRectangular()) {
6173 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
6174 SetRectangularRange();
6177 SetSelection(static_cast<int>(wParam
), sel
.MainAnchor());
6181 case SCI_GETCURRENTPOS
:
6182 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
6185 if (sel
.IsRectangular()) {
6186 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
6187 SetRectangularRange();
6190 SetSelection(sel
.MainCaret(), static_cast<int>(wParam
));
6195 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
6197 case SCI_SETSELECTIONSTART
:
6198 SetSelection(Platform::Maximum(sel
.MainCaret(), static_cast<int>(wParam
)), static_cast<int>(wParam
));
6201 case SCI_GETSELECTIONSTART
:
6202 return sel
.LimitsForRectangularElseMain().start
.Position();
6204 case SCI_SETSELECTIONEND
:
6205 SetSelection(static_cast<int>(wParam
), Platform::Minimum(sel
.MainAnchor(), static_cast<int>(wParam
)));
6208 case SCI_GETSELECTIONEND
:
6209 return sel
.LimitsForRectangularElseMain().end
.Position();
6211 case SCI_SETEMPTYSELECTION
:
6212 SetEmptySelection(static_cast<int>(wParam
));
6215 case SCI_SETPRINTMAGNIFICATION
:
6216 view
.printParameters
.magnification
= static_cast<int>(wParam
);
6219 case SCI_GETPRINTMAGNIFICATION
:
6220 return view
.printParameters
.magnification
;
6222 case SCI_SETPRINTCOLOURMODE
:
6223 view
.printParameters
.colourMode
= static_cast<int>(wParam
);
6226 case SCI_GETPRINTCOLOURMODE
:
6227 return view
.printParameters
.colourMode
;
6229 case SCI_SETPRINTWRAPMODE
:
6230 view
.printParameters
.wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6233 case SCI_GETPRINTWRAPMODE
:
6234 return view
.printParameters
.wrapState
;
6236 case SCI_GETSTYLEAT
:
6237 if (static_cast<int>(wParam
) >= pdoc
->Length())
6240 return pdoc
->StyleAt(static_cast<int>(wParam
));
6250 case SCI_SETSAVEPOINT
:
6251 pdoc
->SetSavePoint();
6254 case SCI_GETSTYLEDTEXT
: {
6257 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6259 for (long iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6260 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(static_cast<int>(iChar
));
6261 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(static_cast<int>(iChar
));
6263 tr
->lpstrText
[iPlace
] = '\0';
6264 tr
->lpstrText
[iPlace
+ 1] = '\0';
6269 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6271 case SCI_MARKERLINEFROMHANDLE
:
6272 return pdoc
->LineFromHandle(static_cast<int>(wParam
));
6274 case SCI_MARKERDELETEHANDLE
:
6275 pdoc
->DeleteMarkFromHandle(static_cast<int>(wParam
));
6279 return vs
.viewWhitespace
;
6282 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6286 case SCI_GETWHITESPACESIZE
:
6287 return vs
.whitespaceSize
;
6289 case SCI_SETWHITESPACESIZE
:
6290 vs
.whitespaceSize
= static_cast<int>(wParam
);
6294 case SCI_POSITIONFROMPOINT
:
6295 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6298 case SCI_POSITIONFROMPOINTCLOSE
:
6299 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6302 case SCI_CHARPOSITIONFROMPOINT
:
6303 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6306 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
6307 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6311 GoToLine(static_cast<int>(wParam
));
6315 SetEmptySelection(static_cast<int>(wParam
));
6316 EnsureCaretVisible();
6319 case SCI_GETCURLINE
: {
6320 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
6321 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6322 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6324 return 1 + lineEnd
- lineStart
;
6326 PLATFORM_ASSERT(wParam
> 0);
6327 char *ptr
= CharPtrFromSPtr(lParam
);
6328 unsigned int iPlace
= 0;
6329 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6330 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6333 return sel
.MainCaret() - lineStart
;
6336 case SCI_GETENDSTYLED
:
6337 return pdoc
->GetEndStyled();
6339 case SCI_GETEOLMODE
:
6340 return pdoc
->eolMode
;
6342 case SCI_SETEOLMODE
:
6343 pdoc
->eolMode
= static_cast<int>(wParam
);
6346 case SCI_SETLINEENDTYPESALLOWED
:
6347 if (pdoc
->SetLineEndTypesAllowed(static_cast<int>(wParam
))) {
6349 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6350 SetAnnotationHeights(0, pdoc
->LinesTotal());
6351 InvalidateStyleRedraw();
6355 case SCI_GETLINEENDTYPESALLOWED
:
6356 return pdoc
->GetLineEndTypesAllowed();
6358 case SCI_GETLINEENDTYPESACTIVE
:
6359 return pdoc
->GetLineEndTypesActive();
6361 case SCI_STARTSTYLING
:
6362 pdoc
->StartStyling(static_cast<int>(wParam
), static_cast<char>(lParam
));
6365 case SCI_SETSTYLING
:
6366 if (static_cast<int>(wParam
) < 0)
6367 errorStatus
= SC_STATUS_FAILURE
;
6369 pdoc
->SetStyleFor(static_cast<int>(wParam
), static_cast<char>(lParam
));
6372 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6375 pdoc
->SetStyles(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6378 case SCI_SETBUFFEREDDRAW
:
6379 view
.bufferedDraw
= wParam
!= 0;
6382 case SCI_GETBUFFEREDDRAW
:
6383 return view
.bufferedDraw
;
6385 case SCI_GETTWOPHASEDRAW
:
6386 return view
.phasesDraw
== EditView::phasesTwo
;
6388 case SCI_SETTWOPHASEDRAW
:
6389 if (view
.SetTwoPhaseDraw(wParam
!= 0))
6390 InvalidateStyleRedraw();
6393 case SCI_GETPHASESDRAW
:
6394 return view
.phasesDraw
;
6396 case SCI_SETPHASESDRAW
:
6397 if (view
.SetPhasesDraw(static_cast<int>(wParam
)))
6398 InvalidateStyleRedraw();
6401 case SCI_SETFONTQUALITY
:
6402 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
6403 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
6404 InvalidateStyleRedraw();
6407 case SCI_GETFONTQUALITY
:
6408 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
6410 case SCI_SETTABWIDTH
:
6412 pdoc
->tabInChars
= static_cast<int>(wParam
);
6413 if (pdoc
->indentInChars
== 0)
6414 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6416 InvalidateStyleRedraw();
6419 case SCI_GETTABWIDTH
:
6420 return pdoc
->tabInChars
;
6422 case SCI_CLEARTABSTOPS
:
6423 if (view
.ClearTabstops(static_cast<int>(wParam
))) {
6424 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6425 NotifyModified(pdoc
, mh
, NULL
);
6429 case SCI_ADDTABSTOP
:
6430 if (view
.AddTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
))) {
6431 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6432 NotifyModified(pdoc
, mh
, NULL
);
6436 case SCI_GETNEXTTABSTOP
:
6437 return view
.GetNextTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
));
6440 pdoc
->indentInChars
= static_cast<int>(wParam
);
6441 if (pdoc
->indentInChars
!= 0)
6442 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6444 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6445 InvalidateStyleRedraw();
6449 return pdoc
->indentInChars
;
6451 case SCI_SETUSETABS
:
6452 pdoc
->useTabs
= wParam
!= 0;
6453 InvalidateStyleRedraw();
6456 case SCI_GETUSETABS
:
6457 return pdoc
->useTabs
;
6459 case SCI_SETLINEINDENTATION
:
6460 pdoc
->SetLineIndentation(static_cast<int>(wParam
), static_cast<int>(lParam
));
6463 case SCI_GETLINEINDENTATION
:
6464 return pdoc
->GetLineIndentation(static_cast<int>(wParam
));
6466 case SCI_GETLINEINDENTPOSITION
:
6467 return pdoc
->GetLineIndentPosition(static_cast<int>(wParam
));
6469 case SCI_SETTABINDENTS
:
6470 pdoc
->tabIndents
= wParam
!= 0;
6473 case SCI_GETTABINDENTS
:
6474 return pdoc
->tabIndents
;
6476 case SCI_SETBACKSPACEUNINDENTS
:
6477 pdoc
->backspaceUnindents
= wParam
!= 0;
6480 case SCI_GETBACKSPACEUNINDENTS
:
6481 return pdoc
->backspaceUnindents
;
6483 case SCI_SETMOUSEDWELLTIME
:
6484 dwellDelay
= static_cast<int>(wParam
);
6485 ticksToDwell
= dwellDelay
;
6488 case SCI_GETMOUSEDWELLTIME
:
6491 case SCI_WORDSTARTPOSITION
:
6492 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), -1, lParam
!= 0);
6494 case SCI_WORDENDPOSITION
:
6495 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), 1, lParam
!= 0);
6497 case SCI_ISRANGEWORD
:
6498 return pdoc
->IsWordAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
6500 case SCI_SETIDLESTYLING
:
6501 idleStyling
= static_cast<int>(wParam
);
6504 case SCI_GETIDLESTYLING
:
6507 case SCI_SETWRAPMODE
:
6508 if (vs
.SetWrapState(static_cast<int>(wParam
))) {
6510 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6511 InvalidateStyleRedraw();
6512 ReconfigureScrollBars();
6516 case SCI_GETWRAPMODE
:
6517 return vs
.wrapState
;
6519 case SCI_SETWRAPVISUALFLAGS
:
6520 if (vs
.SetWrapVisualFlags(static_cast<int>(wParam
))) {
6521 InvalidateStyleRedraw();
6522 ReconfigureScrollBars();
6526 case SCI_GETWRAPVISUALFLAGS
:
6527 return vs
.wrapVisualFlags
;
6529 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6530 if (vs
.SetWrapVisualFlagsLocation(static_cast<int>(wParam
))) {
6531 InvalidateStyleRedraw();
6535 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6536 return vs
.wrapVisualFlagsLocation
;
6538 case SCI_SETWRAPSTARTINDENT
:
6539 if (vs
.SetWrapVisualStartIndent(static_cast<int>(wParam
))) {
6540 InvalidateStyleRedraw();
6541 ReconfigureScrollBars();
6545 case SCI_GETWRAPSTARTINDENT
:
6546 return vs
.wrapVisualStartIndent
;
6548 case SCI_SETWRAPINDENTMODE
:
6549 if (vs
.SetWrapIndentMode(static_cast<int>(wParam
))) {
6550 InvalidateStyleRedraw();
6551 ReconfigureScrollBars();
6555 case SCI_GETWRAPINDENTMODE
:
6556 return vs
.wrapIndentMode
;
6558 case SCI_SETLAYOUTCACHE
:
6559 view
.llc
.SetLevel(static_cast<int>(wParam
));
6562 case SCI_GETLAYOUTCACHE
:
6563 return view
.llc
.GetLevel();
6565 case SCI_SETPOSITIONCACHE
:
6566 view
.posCache
.SetSize(wParam
);
6569 case SCI_GETPOSITIONCACHE
:
6570 return view
.posCache
.GetSize();
6572 case SCI_SETSCROLLWIDTH
:
6573 PLATFORM_ASSERT(wParam
> 0);
6574 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6575 view
.lineWidthMaxSeen
= 0;
6576 scrollWidth
= static_cast<int>(wParam
);
6581 case SCI_GETSCROLLWIDTH
:
6584 case SCI_SETSCROLLWIDTHTRACKING
:
6585 trackLineWidth
= wParam
!= 0;
6588 case SCI_GETSCROLLWIDTHTRACKING
:
6589 return trackLineWidth
;
6595 case SCI_LINESSPLIT
:
6596 LinesSplit(static_cast<int>(wParam
));
6600 PLATFORM_ASSERT(wParam
< vs
.styles
.size());
6601 PLATFORM_ASSERT(lParam
);
6602 return TextWidth(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6604 case SCI_TEXTHEIGHT
:
6606 return vs
.lineHeight
;
6608 case SCI_SETENDATLASTLINE
:
6609 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6610 if (endAtLastLine
!= (wParam
!= 0)) {
6611 endAtLastLine
= wParam
!= 0;
6616 case SCI_GETENDATLASTLINE
:
6617 return endAtLastLine
;
6619 case SCI_SETCARETSTICKY
:
6620 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
6621 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
6622 caretSticky
= static_cast<int>(wParam
);
6626 case SCI_GETCARETSTICKY
:
6629 case SCI_TOGGLECARETSTICKY
:
6630 caretSticky
= !caretSticky
;
6634 return pdoc
->GetColumn(static_cast<int>(wParam
));
6636 case SCI_FINDCOLUMN
:
6637 return pdoc
->FindColumn(static_cast<int>(wParam
), static_cast<int>(lParam
));
6639 case SCI_SETHSCROLLBAR
:
6640 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6641 horizontalScrollBarVisible
= wParam
!= 0;
6643 ReconfigureScrollBars();
6647 case SCI_GETHSCROLLBAR
:
6648 return horizontalScrollBarVisible
;
6650 case SCI_SETVSCROLLBAR
:
6651 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6652 verticalScrollBarVisible
= wParam
!= 0;
6654 ReconfigureScrollBars();
6655 if (verticalScrollBarVisible
)
6656 SetVerticalScrollPos();
6660 case SCI_GETVSCROLLBAR
:
6661 return verticalScrollBarVisible
;
6663 case SCI_SETINDENTATIONGUIDES
:
6664 vs
.viewIndentationGuides
= IndentView(wParam
);
6668 case SCI_GETINDENTATIONGUIDES
:
6669 return vs
.viewIndentationGuides
;
6671 case SCI_SETHIGHLIGHTGUIDE
:
6672 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6673 highlightGuideColumn
= static_cast<int>(wParam
);
6678 case SCI_GETHIGHLIGHTGUIDE
:
6679 return highlightGuideColumn
;
6681 case SCI_GETLINEENDPOSITION
:
6682 return pdoc
->LineEnd(static_cast<int>(wParam
));
6684 case SCI_SETCODEPAGE
:
6685 if (ValidCodePage(static_cast<int>(wParam
))) {
6686 if (pdoc
->SetDBCSCodePage(static_cast<int>(wParam
))) {
6688 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6689 SetAnnotationHeights(0, pdoc
->LinesTotal());
6690 InvalidateStyleRedraw();
6691 SetRepresentations();
6696 case SCI_GETCODEPAGE
:
6697 return pdoc
->dbcsCodePage
;
6699 case SCI_SETIMEINTERACTION
:
6700 imeInteraction
= static_cast<EditModel::IMEInteraction
>(wParam
);
6703 case SCI_GETIMEINTERACTION
:
6704 return imeInteraction
;
6706 #ifdef INCLUDE_DEPRECATED_FEATURES
6707 case SCI_SETUSEPALETTE
:
6708 InvalidateStyleRedraw();
6711 case SCI_GETUSEPALETTE
:
6715 // Marker definition and setting
6716 case SCI_MARKERDEFINE
:
6717 if (wParam
<= MARKER_MAX
) {
6718 vs
.markers
[wParam
].markType
= static_cast<int>(lParam
);
6719 vs
.CalcLargestMarkerHeight();
6721 InvalidateStyleData();
6725 case SCI_MARKERSYMBOLDEFINED
:
6726 if (wParam
<= MARKER_MAX
)
6727 return vs
.markers
[wParam
].markType
;
6731 case SCI_MARKERSETFORE
:
6732 if (wParam
<= MARKER_MAX
)
6733 vs
.markers
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6734 InvalidateStyleData();
6737 case SCI_MARKERSETBACKSELECTED
:
6738 if (wParam
<= MARKER_MAX
)
6739 vs
.markers
[wParam
].backSelected
= ColourDesired(static_cast<long>(lParam
));
6740 InvalidateStyleData();
6743 case SCI_MARKERENABLEHIGHLIGHT
:
6744 marginView
.highlightDelimiter
.isEnabled
= wParam
== 1;
6747 case SCI_MARKERSETBACK
:
6748 if (wParam
<= MARKER_MAX
)
6749 vs
.markers
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6750 InvalidateStyleData();
6753 case SCI_MARKERSETALPHA
:
6754 if (wParam
<= MARKER_MAX
)
6755 vs
.markers
[wParam
].alpha
= static_cast<int>(lParam
);
6756 InvalidateStyleRedraw();
6758 case SCI_MARKERADD
: {
6759 int markerID
= pdoc
->AddMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6762 case SCI_MARKERADDSET
:
6764 pdoc
->AddMarkSet(static_cast<int>(wParam
), static_cast<int>(lParam
));
6767 case SCI_MARKERDELETE
:
6768 pdoc
->DeleteMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6771 case SCI_MARKERDELETEALL
:
6772 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6776 return pdoc
->GetMark(static_cast<int>(wParam
));
6778 case SCI_MARKERNEXT
:
6779 return pdoc
->MarkerNext(static_cast<int>(wParam
), static_cast<int>(lParam
));
6781 case SCI_MARKERPREVIOUS
: {
6782 for (int iLine
= static_cast<int>(wParam
); iLine
>= 0; iLine
--) {
6783 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6789 case SCI_MARKERDEFINEPIXMAP
:
6790 if (wParam
<= MARKER_MAX
) {
6791 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6792 vs
.CalcLargestMarkerHeight();
6794 InvalidateStyleData();
6798 case SCI_RGBAIMAGESETWIDTH
:
6799 sizeRGBAImage
.x
= static_cast<XYPOSITION
>(wParam
);
6802 case SCI_RGBAIMAGESETHEIGHT
:
6803 sizeRGBAImage
.y
= static_cast<XYPOSITION
>(wParam
);
6806 case SCI_RGBAIMAGESETSCALE
:
6807 scaleRGBAImage
= static_cast<float>(wParam
);
6810 case SCI_MARKERDEFINERGBAIMAGE
:
6811 if (wParam
<= MARKER_MAX
) {
6812 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0f
, reinterpret_cast<unsigned char *>(lParam
));
6813 vs
.CalcLargestMarkerHeight();
6815 InvalidateStyleData();
6819 case SCI_SETMARGINTYPEN
:
6820 if (ValidMargin(wParam
)) {
6821 vs
.ms
[wParam
].style
= static_cast<int>(lParam
);
6822 InvalidateStyleRedraw();
6826 case SCI_GETMARGINTYPEN
:
6827 if (ValidMargin(wParam
))
6828 return vs
.ms
[wParam
].style
;
6832 case SCI_SETMARGINWIDTHN
:
6833 if (ValidMargin(wParam
)) {
6834 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6835 if (vs
.ms
[wParam
].width
!= lParam
) {
6836 lastXChosen
+= static_cast<int>(lParam
) - vs
.ms
[wParam
].width
;
6837 vs
.ms
[wParam
].width
= static_cast<int>(lParam
);
6838 InvalidateStyleRedraw();
6843 case SCI_GETMARGINWIDTHN
:
6844 if (ValidMargin(wParam
))
6845 return vs
.ms
[wParam
].width
;
6849 case SCI_SETMARGINMASKN
:
6850 if (ValidMargin(wParam
)) {
6851 vs
.ms
[wParam
].mask
= static_cast<int>(lParam
);
6852 InvalidateStyleRedraw();
6856 case SCI_GETMARGINMASKN
:
6857 if (ValidMargin(wParam
))
6858 return vs
.ms
[wParam
].mask
;
6862 case SCI_SETMARGINSENSITIVEN
:
6863 if (ValidMargin(wParam
)) {
6864 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6865 InvalidateStyleRedraw();
6869 case SCI_GETMARGINSENSITIVEN
:
6870 if (ValidMargin(wParam
))
6871 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6875 case SCI_SETMARGINCURSORN
:
6876 if (ValidMargin(wParam
))
6877 vs
.ms
[wParam
].cursor
= static_cast<int>(lParam
);
6880 case SCI_GETMARGINCURSORN
:
6881 if (ValidMargin(wParam
))
6882 return vs
.ms
[wParam
].cursor
;
6886 case SCI_STYLECLEARALL
:
6888 InvalidateStyleRedraw();
6891 case SCI_STYLESETFORE
:
6892 case SCI_STYLESETBACK
:
6893 case SCI_STYLESETBOLD
:
6894 case SCI_STYLESETWEIGHT
:
6895 case SCI_STYLESETITALIC
:
6896 case SCI_STYLESETEOLFILLED
:
6897 case SCI_STYLESETSIZE
:
6898 case SCI_STYLESETSIZEFRACTIONAL
:
6899 case SCI_STYLESETFONT
:
6900 case SCI_STYLESETUNDERLINE
:
6901 case SCI_STYLESETCASE
:
6902 case SCI_STYLESETCHARACTERSET
:
6903 case SCI_STYLESETVISIBLE
:
6904 case SCI_STYLESETCHANGEABLE
:
6905 case SCI_STYLESETHOTSPOT
:
6906 StyleSetMessage(iMessage
, wParam
, lParam
);
6909 case SCI_STYLEGETFORE
:
6910 case SCI_STYLEGETBACK
:
6911 case SCI_STYLEGETBOLD
:
6912 case SCI_STYLEGETWEIGHT
:
6913 case SCI_STYLEGETITALIC
:
6914 case SCI_STYLEGETEOLFILLED
:
6915 case SCI_STYLEGETSIZE
:
6916 case SCI_STYLEGETSIZEFRACTIONAL
:
6917 case SCI_STYLEGETFONT
:
6918 case SCI_STYLEGETUNDERLINE
:
6919 case SCI_STYLEGETCASE
:
6920 case SCI_STYLEGETCHARACTERSET
:
6921 case SCI_STYLEGETVISIBLE
:
6922 case SCI_STYLEGETCHANGEABLE
:
6923 case SCI_STYLEGETHOTSPOT
:
6924 return StyleGetMessage(iMessage
, wParam
, lParam
);
6926 case SCI_STYLERESETDEFAULT
:
6927 vs
.ResetDefaultStyle();
6928 InvalidateStyleRedraw();
6930 case SCI_SETSTYLEBITS
:
6931 vs
.EnsureStyle(0xff);
6934 case SCI_GETSTYLEBITS
:
6937 case SCI_SETLINESTATE
:
6938 return pdoc
->SetLineState(static_cast<int>(wParam
), static_cast<int>(lParam
));
6940 case SCI_GETLINESTATE
:
6941 return pdoc
->GetLineState(static_cast<int>(wParam
));
6943 case SCI_GETMAXLINESTATE
:
6944 return pdoc
->GetMaxLineState();
6946 case SCI_GETCARETLINEVISIBLE
:
6947 return vs
.showCaretLineBackground
;
6948 case SCI_SETCARETLINEVISIBLE
:
6949 vs
.showCaretLineBackground
= wParam
!= 0;
6950 InvalidateStyleRedraw();
6952 case SCI_GETCARETLINEVISIBLEALWAYS
:
6953 return vs
.alwaysShowCaretLineBackground
;
6954 case SCI_SETCARETLINEVISIBLEALWAYS
:
6955 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
6956 InvalidateStyleRedraw();
6959 case SCI_GETCARETLINEBACK
:
6960 return vs
.caretLineBackground
.AsLong();
6961 case SCI_SETCARETLINEBACK
:
6962 vs
.caretLineBackground
= static_cast<int>(wParam
);
6963 InvalidateStyleRedraw();
6965 case SCI_GETCARETLINEBACKALPHA
:
6966 return vs
.caretLineAlpha
;
6967 case SCI_SETCARETLINEBACKALPHA
:
6968 vs
.caretLineAlpha
= static_cast<int>(wParam
);
6969 InvalidateStyleRedraw();
6974 case SCI_VISIBLEFROMDOCLINE
:
6975 return cs
.DisplayFromDoc(static_cast<int>(wParam
));
6977 case SCI_DOCLINEFROMVISIBLE
:
6978 return cs
.DocFromDisplay(static_cast<int>(wParam
));
6981 return WrapCount(static_cast<int>(wParam
));
6983 case SCI_SETFOLDLEVEL
: {
6984 int prev
= pdoc
->SetLevel(static_cast<int>(wParam
), static_cast<int>(lParam
));
6985 if (prev
!= static_cast<int>(lParam
))
6990 case SCI_GETFOLDLEVEL
:
6991 return pdoc
->GetLevel(static_cast<int>(wParam
));
6993 case SCI_GETLASTCHILD
:
6994 return pdoc
->GetLastChild(static_cast<int>(wParam
), static_cast<int>(lParam
));
6996 case SCI_GETFOLDPARENT
:
6997 return pdoc
->GetFoldParent(static_cast<int>(wParam
));
7000 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), true);
7007 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), false);
7012 case SCI_GETLINEVISIBLE
:
7013 return cs
.GetVisible(static_cast<int>(wParam
));
7015 case SCI_GETALLLINESVISIBLE
:
7016 return cs
.HiddenLines() ? 0 : 1;
7018 case SCI_SETFOLDEXPANDED
:
7019 SetFoldExpanded(static_cast<int>(wParam
), lParam
!= 0);
7022 case SCI_GETFOLDEXPANDED
:
7023 return cs
.GetExpanded(static_cast<int>(wParam
));
7025 case SCI_SETAUTOMATICFOLD
:
7026 foldAutomatic
= static_cast<int>(wParam
);
7029 case SCI_GETAUTOMATICFOLD
:
7030 return foldAutomatic
;
7032 case SCI_SETFOLDFLAGS
:
7033 foldFlags
= static_cast<int>(wParam
);
7037 case SCI_TOGGLEFOLD
:
7038 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
7042 FoldLine(static_cast<int>(wParam
), static_cast<int>(lParam
));
7045 case SCI_FOLDCHILDREN
:
7046 FoldExpand(static_cast<int>(wParam
), static_cast<int>(lParam
), pdoc
->GetLevel(static_cast<int>(wParam
)));
7050 FoldAll(static_cast<int>(wParam
));
7053 case SCI_EXPANDCHILDREN
:
7054 FoldExpand(static_cast<int>(wParam
), SC_FOLDACTION_EXPAND
, static_cast<int>(lParam
));
7057 case SCI_CONTRACTEDFOLDNEXT
:
7058 return ContractedFoldNext(static_cast<int>(wParam
));
7060 case SCI_ENSUREVISIBLE
:
7061 EnsureLineVisible(static_cast<int>(wParam
), false);
7064 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
7065 EnsureLineVisible(static_cast<int>(wParam
), true);
7068 case SCI_SCROLLRANGE
:
7069 ScrollRange(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7072 case SCI_SEARCHANCHOR
:
7076 case SCI_SEARCHNEXT
:
7077 case SCI_SEARCHPREV
:
7078 return SearchText(iMessage
, wParam
, lParam
);
7080 case SCI_SETXCARETPOLICY
:
7081 caretXPolicy
= static_cast<int>(wParam
);
7082 caretXSlop
= static_cast<int>(lParam
);
7085 case SCI_SETYCARETPOLICY
:
7086 caretYPolicy
= static_cast<int>(wParam
);
7087 caretYSlop
= static_cast<int>(lParam
);
7090 case SCI_SETVISIBLEPOLICY
:
7091 visiblePolicy
= static_cast<int>(wParam
);
7092 visibleSlop
= static_cast<int>(lParam
);
7095 case SCI_LINESONSCREEN
:
7096 return LinesOnScreen();
7098 case SCI_SETSELFORE
:
7099 vs
.selColours
.fore
= ColourOptional(wParam
, lParam
);
7100 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(lParam
));
7101 InvalidateStyleRedraw();
7104 case SCI_SETSELBACK
:
7105 vs
.selColours
.back
= ColourOptional(wParam
, lParam
);
7106 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(lParam
));
7107 InvalidateStyleRedraw();
7110 case SCI_SETSELALPHA
:
7111 vs
.selAlpha
= static_cast<int>(wParam
);
7112 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7113 InvalidateStyleRedraw();
7116 case SCI_GETSELALPHA
:
7119 case SCI_GETSELEOLFILLED
:
7120 return vs
.selEOLFilled
;
7122 case SCI_SETSELEOLFILLED
:
7123 vs
.selEOLFilled
= wParam
!= 0;
7124 InvalidateStyleRedraw();
7127 case SCI_SETWHITESPACEFORE
:
7128 vs
.whitespaceColours
.fore
= ColourOptional(wParam
, lParam
);
7129 InvalidateStyleRedraw();
7132 case SCI_SETWHITESPACEBACK
:
7133 vs
.whitespaceColours
.back
= ColourOptional(wParam
, lParam
);
7134 InvalidateStyleRedraw();
7137 case SCI_SETCARETFORE
:
7138 vs
.caretcolour
= ColourDesired(static_cast<long>(wParam
));
7139 InvalidateStyleRedraw();
7142 case SCI_GETCARETFORE
:
7143 return vs
.caretcolour
.AsLong();
7145 case SCI_SETCARETSTYLE
:
7146 if (wParam
<= CARETSTYLE_BLOCK
)
7147 vs
.caretStyle
= static_cast<int>(wParam
);
7149 /* Default to the line caret */
7150 vs
.caretStyle
= CARETSTYLE_LINE
;
7151 InvalidateStyleRedraw();
7154 case SCI_GETCARETSTYLE
:
7155 return vs
.caretStyle
;
7157 case SCI_SETCARETWIDTH
:
7158 if (static_cast<int>(wParam
) <= 0)
7160 else if (wParam
>= 3)
7163 vs
.caretWidth
= static_cast<int>(wParam
);
7164 InvalidateStyleRedraw();
7167 case SCI_GETCARETWIDTH
:
7168 return vs
.caretWidth
;
7170 case SCI_ASSIGNCMDKEY
:
7171 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7172 Platform::HighShortFromLong(static_cast<long>(wParam
)), static_cast<unsigned int>(lParam
));
7175 case SCI_CLEARCMDKEY
:
7176 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7177 Platform::HighShortFromLong(static_cast<long>(wParam
)), SCI_NULL
);
7180 case SCI_CLEARALLCMDKEYS
:
7184 case SCI_INDICSETSTYLE
:
7185 if (wParam
<= INDIC_MAX
) {
7186 vs
.indicators
[wParam
].sacNormal
.style
= static_cast<int>(lParam
);
7187 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7188 InvalidateStyleRedraw();
7192 case SCI_INDICGETSTYLE
:
7193 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.style
: 0;
7195 case SCI_INDICSETFORE
:
7196 if (wParam
<= INDIC_MAX
) {
7197 vs
.indicators
[wParam
].sacNormal
.fore
= ColourDesired(static_cast<long>(lParam
));
7198 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7199 InvalidateStyleRedraw();
7203 case SCI_INDICGETFORE
:
7204 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.fore
.AsLong() : 0;
7206 case SCI_INDICSETHOVERSTYLE
:
7207 if (wParam
<= INDIC_MAX
) {
7208 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7209 InvalidateStyleRedraw();
7213 case SCI_INDICGETHOVERSTYLE
:
7214 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.style
: 0;
7216 case SCI_INDICSETHOVERFORE
:
7217 if (wParam
<= INDIC_MAX
) {
7218 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7219 InvalidateStyleRedraw();
7223 case SCI_INDICGETHOVERFORE
:
7224 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.fore
.AsLong() : 0;
7226 case SCI_INDICSETFLAGS
:
7227 if (wParam
<= INDIC_MAX
) {
7228 vs
.indicators
[wParam
].SetFlags(static_cast<int>(lParam
));
7229 InvalidateStyleRedraw();
7233 case SCI_INDICGETFLAGS
:
7234 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].Flags() : 0;
7236 case SCI_INDICSETUNDER
:
7237 if (wParam
<= INDIC_MAX
) {
7238 vs
.indicators
[wParam
].under
= lParam
!= 0;
7239 InvalidateStyleRedraw();
7243 case SCI_INDICGETUNDER
:
7244 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
7246 case SCI_INDICSETALPHA
:
7247 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7248 vs
.indicators
[wParam
].fillAlpha
= static_cast<int>(lParam
);
7249 InvalidateStyleRedraw();
7253 case SCI_INDICGETALPHA
:
7254 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
7256 case SCI_INDICSETOUTLINEALPHA
:
7257 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7258 vs
.indicators
[wParam
].outlineAlpha
= static_cast<int>(lParam
);
7259 InvalidateStyleRedraw();
7263 case SCI_INDICGETOUTLINEALPHA
:
7264 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
7266 case SCI_SETINDICATORCURRENT
:
7267 pdoc
->decorations
.SetCurrentIndicator(static_cast<int>(wParam
));
7269 case SCI_GETINDICATORCURRENT
:
7270 return pdoc
->decorations
.GetCurrentIndicator();
7271 case SCI_SETINDICATORVALUE
:
7272 pdoc
->decorations
.SetCurrentValue(static_cast<int>(wParam
));
7274 case SCI_GETINDICATORVALUE
:
7275 return pdoc
->decorations
.GetCurrentValue();
7277 case SCI_INDICATORFILLRANGE
:
7278 pdoc
->DecorationFillRange(static_cast<int>(wParam
), pdoc
->decorations
.GetCurrentValue(), static_cast<int>(lParam
));
7281 case SCI_INDICATORCLEARRANGE
:
7282 pdoc
->DecorationFillRange(static_cast<int>(wParam
), 0, static_cast<int>(lParam
));
7285 case SCI_INDICATORALLONFOR
:
7286 return pdoc
->decorations
.AllOnFor(static_cast<int>(wParam
));
7288 case SCI_INDICATORVALUEAT
:
7289 return pdoc
->decorations
.ValueAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
7291 case SCI_INDICATORSTART
:
7292 return pdoc
->decorations
.Start(static_cast<int>(wParam
), static_cast<int>(lParam
));
7294 case SCI_INDICATOREND
:
7295 return pdoc
->decorations
.End(static_cast<int>(wParam
), static_cast<int>(lParam
));
7298 case SCI_LINEDOWNEXTEND
:
7300 case SCI_PARADOWNEXTEND
:
7302 case SCI_LINEUPEXTEND
:
7304 case SCI_PARAUPEXTEND
:
7306 case SCI_CHARLEFTEXTEND
:
7308 case SCI_CHARRIGHTEXTEND
:
7310 case SCI_WORDLEFTEXTEND
:
7312 case SCI_WORDRIGHTEXTEND
:
7313 case SCI_WORDLEFTEND
:
7314 case SCI_WORDLEFTENDEXTEND
:
7315 case SCI_WORDRIGHTEND
:
7316 case SCI_WORDRIGHTENDEXTEND
:
7318 case SCI_HOMEEXTEND
:
7320 case SCI_LINEENDEXTEND
:
7322 case SCI_HOMEWRAPEXTEND
:
7323 case SCI_LINEENDWRAP
:
7324 case SCI_LINEENDWRAPEXTEND
:
7325 case SCI_DOCUMENTSTART
:
7326 case SCI_DOCUMENTSTARTEXTEND
:
7327 case SCI_DOCUMENTEND
:
7328 case SCI_DOCUMENTENDEXTEND
:
7329 case SCI_SCROLLTOSTART
:
7330 case SCI_SCROLLTOEND
:
7332 case SCI_STUTTEREDPAGEUP
:
7333 case SCI_STUTTEREDPAGEUPEXTEND
:
7334 case SCI_STUTTEREDPAGEDOWN
:
7335 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7338 case SCI_PAGEUPEXTEND
:
7340 case SCI_PAGEDOWNEXTEND
:
7341 case SCI_EDITTOGGLEOVERTYPE
:
7343 case SCI_DELETEBACK
:
7349 case SCI_VCHOMEEXTEND
:
7350 case SCI_VCHOMEWRAP
:
7351 case SCI_VCHOMEWRAPEXTEND
:
7352 case SCI_VCHOMEDISPLAY
:
7353 case SCI_VCHOMEDISPLAYEXTEND
:
7356 case SCI_DELWORDLEFT
:
7357 case SCI_DELWORDRIGHT
:
7358 case SCI_DELWORDRIGHTEND
:
7359 case SCI_DELLINELEFT
:
7360 case SCI_DELLINERIGHT
:
7363 case SCI_LINEDELETE
:
7364 case SCI_LINETRANSPOSE
:
7365 case SCI_LINEDUPLICATE
:
7368 case SCI_LINESCROLLDOWN
:
7369 case SCI_LINESCROLLUP
:
7370 case SCI_WORDPARTLEFT
:
7371 case SCI_WORDPARTLEFTEXTEND
:
7372 case SCI_WORDPARTRIGHT
:
7373 case SCI_WORDPARTRIGHTEXTEND
:
7374 case SCI_DELETEBACKNOTLINE
:
7375 case SCI_HOMEDISPLAY
:
7376 case SCI_HOMEDISPLAYEXTEND
:
7377 case SCI_LINEENDDISPLAY
:
7378 case SCI_LINEENDDISPLAYEXTEND
:
7379 case SCI_LINEDOWNRECTEXTEND
:
7380 case SCI_LINEUPRECTEXTEND
:
7381 case SCI_CHARLEFTRECTEXTEND
:
7382 case SCI_CHARRIGHTRECTEXTEND
:
7383 case SCI_HOMERECTEXTEND
:
7384 case SCI_VCHOMERECTEXTEND
:
7385 case SCI_LINEENDRECTEXTEND
:
7386 case SCI_PAGEUPRECTEXTEND
:
7387 case SCI_PAGEDOWNRECTEXTEND
:
7388 case SCI_SELECTIONDUPLICATE
:
7389 return KeyCommand(iMessage
);
7391 case SCI_BRACEHIGHLIGHT
:
7392 SetBraceHighlight(static_cast<int>(wParam
), static_cast<int>(lParam
), STYLE_BRACELIGHT
);
7395 case SCI_BRACEHIGHLIGHTINDICATOR
:
7396 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7397 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
7398 vs
.braceHighlightIndicator
= static_cast<int>(lParam
);
7402 case SCI_BRACEBADLIGHT
:
7403 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7406 case SCI_BRACEBADLIGHTINDICATOR
:
7407 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7408 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
7409 vs
.braceBadLightIndicator
= static_cast<int>(lParam
);
7413 case SCI_BRACEMATCH
:
7414 // wParam is position of char to find brace for,
7415 // lParam is maximum amount of text to restyle to find it
7416 return pdoc
->BraceMatch(static_cast<int>(wParam
), static_cast<int>(lParam
));
7418 case SCI_GETVIEWEOL
:
7421 case SCI_SETVIEWEOL
:
7422 vs
.viewEOL
= wParam
!= 0;
7423 InvalidateStyleRedraw();
7427 vs
.zoomLevel
= static_cast<int>(wParam
);
7428 InvalidateStyleRedraw();
7433 return vs
.zoomLevel
;
7435 case SCI_GETEDGECOLUMN
:
7438 case SCI_SETEDGECOLUMN
:
7439 vs
.theEdge
= static_cast<int>(wParam
);
7440 InvalidateStyleRedraw();
7443 case SCI_GETEDGEMODE
:
7444 return vs
.edgeState
;
7446 case SCI_SETEDGEMODE
:
7447 vs
.edgeState
= static_cast<int>(wParam
);
7448 InvalidateStyleRedraw();
7451 case SCI_GETEDGECOLOUR
:
7452 return vs
.edgecolour
.AsLong();
7454 case SCI_SETEDGECOLOUR
:
7455 vs
.edgecolour
= ColourDesired(static_cast<long>(wParam
));
7456 InvalidateStyleRedraw();
7459 case SCI_GETDOCPOINTER
:
7460 return reinterpret_cast<sptr_t
>(pdoc
);
7462 case SCI_SETDOCPOINTER
:
7464 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7467 case SCI_CREATEDOCUMENT
: {
7468 Document
*doc
= new Document();
7470 return reinterpret_cast<sptr_t
>(doc
);
7473 case SCI_ADDREFDOCUMENT
:
7474 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7477 case SCI_RELEASEDOCUMENT
:
7478 (reinterpret_cast<Document
*>(lParam
))->Release();
7481 case SCI_CREATELOADER
: {
7482 Document
*doc
= new Document();
7484 doc
->Allocate(static_cast<int>(wParam
));
7485 doc
->SetUndoCollection(false);
7486 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
7489 case SCI_SETMODEVENTMASK
:
7490 modEventMask
= static_cast<int>(wParam
);
7493 case SCI_GETMODEVENTMASK
:
7494 return modEventMask
;
7496 case SCI_CONVERTEOLS
:
7497 pdoc
->ConvertLineEnds(static_cast<int>(wParam
));
7498 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7501 case SCI_SETLENGTHFORENCODE
:
7502 lengthForEncode
= static_cast<int>(wParam
);
7505 case SCI_SELECTIONISRECTANGLE
:
7506 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7508 case SCI_SETSELECTIONMODE
: {
7511 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7512 sel
.selType
= Selection::selStream
;
7514 case SC_SEL_RECTANGLE
:
7515 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7516 sel
.selType
= Selection::selRectangle
;
7519 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7520 sel
.selType
= Selection::selLines
;
7523 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7524 sel
.selType
= Selection::selThin
;
7527 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7528 sel
.selType
= Selection::selStream
;
7530 InvalidateWholeSelection();
7533 case SCI_GETSELECTIONMODE
:
7534 switch (sel
.selType
) {
7535 case Selection::selStream
:
7536 return SC_SEL_STREAM
;
7537 case Selection::selRectangle
:
7538 return SC_SEL_RECTANGLE
;
7539 case Selection::selLines
:
7540 return SC_SEL_LINES
;
7541 case Selection::selThin
:
7544 return SC_SEL_STREAM
;
7546 case SCI_GETLINESELSTARTPOSITION
:
7547 case SCI_GETLINESELENDPOSITION
: {
7548 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(static_cast<int>(wParam
))),
7549 SelectionPosition(pdoc
->LineEnd(static_cast<int>(wParam
))));
7550 for (size_t r
=0; r
<sel
.Count(); r
++) {
7551 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7552 if (portion
.start
.IsValid()) {
7553 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
7556 return INVALID_POSITION
;
7559 case SCI_SETOVERTYPE
:
7560 inOverstrike
= wParam
!= 0;
7563 case SCI_GETOVERTYPE
:
7564 return inOverstrike
? 1 : 0;
7567 SetFocusState(wParam
!= 0);
7574 errorStatus
= static_cast<int>(wParam
);
7580 case SCI_SETMOUSEDOWNCAPTURES
:
7581 mouseDownCaptures
= wParam
!= 0;
7584 case SCI_GETMOUSEDOWNCAPTURES
:
7585 return mouseDownCaptures
;
7588 cursorMode
= static_cast<int>(wParam
);
7589 DisplayCursor(Window::cursorText
);
7595 case SCI_SETCONTROLCHARSYMBOL
:
7596 vs
.controlCharSymbol
= static_cast<int>(wParam
);
7597 InvalidateStyleRedraw();
7600 case SCI_GETCONTROLCHARSYMBOL
:
7601 return vs
.controlCharSymbol
;
7603 case SCI_SETREPRESENTATION
:
7604 reprs
.SetRepresentation(reinterpret_cast<const char *>(wParam
), CharPtrFromSPtr(lParam
));
7607 case SCI_GETREPRESENTATION
: {
7608 const Representation
*repr
= reprs
.RepresentationFromCharacter(
7609 reinterpret_cast<const char *>(wParam
), UTF8MaxBytes
);
7611 return StringResult(lParam
, repr
->stringRep
.c_str());
7616 case SCI_CLEARREPRESENTATION
:
7617 reprs
.ClearRepresentation(reinterpret_cast<const char *>(wParam
));
7620 case SCI_STARTRECORD
:
7621 recordingMacro
= true;
7624 case SCI_STOPRECORD
:
7625 recordingMacro
= false;
7628 case SCI_MOVECARETINSIDEVIEW
:
7629 MoveCaretInsideView();
7632 case SCI_SETFOLDMARGINCOLOUR
:
7633 vs
.foldmarginColour
= ColourOptional(wParam
, lParam
);
7634 InvalidateStyleRedraw();
7637 case SCI_SETFOLDMARGINHICOLOUR
:
7638 vs
.foldmarginHighlightColour
= ColourOptional(wParam
, lParam
);
7639 InvalidateStyleRedraw();
7642 case SCI_SETHOTSPOTACTIVEFORE
:
7643 vs
.hotspotColours
.fore
= ColourOptional(wParam
, lParam
);
7644 InvalidateStyleRedraw();
7647 case SCI_GETHOTSPOTACTIVEFORE
:
7648 return vs
.hotspotColours
.fore
.AsLong();
7650 case SCI_SETHOTSPOTACTIVEBACK
:
7651 vs
.hotspotColours
.back
= ColourOptional(wParam
, lParam
);
7652 InvalidateStyleRedraw();
7655 case SCI_GETHOTSPOTACTIVEBACK
:
7656 return vs
.hotspotColours
.back
.AsLong();
7658 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7659 vs
.hotspotUnderline
= wParam
!= 0;
7660 InvalidateStyleRedraw();
7663 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7664 return vs
.hotspotUnderline
? 1 : 0;
7666 case SCI_SETHOTSPOTSINGLELINE
:
7667 vs
.hotspotSingleLine
= wParam
!= 0;
7668 InvalidateStyleRedraw();
7671 case SCI_GETHOTSPOTSINGLELINE
:
7672 return vs
.hotspotSingleLine
? 1 : 0;
7674 case SCI_SETPASTECONVERTENDINGS
:
7675 convertPastes
= wParam
!= 0;
7678 case SCI_GETPASTECONVERTENDINGS
:
7679 return convertPastes
? 1 : 0;
7681 case SCI_GETCHARACTERPOINTER
:
7682 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
7684 case SCI_GETRANGEPOINTER
:
7685 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7687 case SCI_GETGAPPOSITION
:
7688 return pdoc
->GapPosition();
7690 case SCI_SETEXTRAASCENT
:
7691 vs
.extraAscent
= static_cast<int>(wParam
);
7692 InvalidateStyleRedraw();
7695 case SCI_GETEXTRAASCENT
:
7696 return vs
.extraAscent
;
7698 case SCI_SETEXTRADESCENT
:
7699 vs
.extraDescent
= static_cast<int>(wParam
);
7700 InvalidateStyleRedraw();
7703 case SCI_GETEXTRADESCENT
:
7704 return vs
.extraDescent
;
7706 case SCI_MARGINSETSTYLEOFFSET
:
7707 vs
.marginStyleOffset
= static_cast<int>(wParam
);
7708 InvalidateStyleRedraw();
7711 case SCI_MARGINGETSTYLEOFFSET
:
7712 return vs
.marginStyleOffset
;
7714 case SCI_SETMARGINOPTIONS
:
7715 marginOptions
= static_cast<int>(wParam
);
7718 case SCI_GETMARGINOPTIONS
:
7719 return marginOptions
;
7721 case SCI_MARGINSETTEXT
:
7722 pdoc
->MarginSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7725 case SCI_MARGINGETTEXT
: {
7726 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7727 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7730 case SCI_MARGINSETSTYLE
:
7731 pdoc
->MarginSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7734 case SCI_MARGINGETSTYLE
: {
7735 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7739 case SCI_MARGINSETSTYLES
:
7740 pdoc
->MarginSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7743 case SCI_MARGINGETSTYLES
: {
7744 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7745 return BytesResult(lParam
, st
.styles
, st
.length
);
7748 case SCI_MARGINTEXTCLEARALL
:
7749 pdoc
->MarginClearAll();
7752 case SCI_ANNOTATIONSETTEXT
:
7753 pdoc
->AnnotationSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7756 case SCI_ANNOTATIONGETTEXT
: {
7757 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7758 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7761 case SCI_ANNOTATIONGETSTYLE
: {
7762 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7766 case SCI_ANNOTATIONSETSTYLE
:
7767 pdoc
->AnnotationSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7770 case SCI_ANNOTATIONSETSTYLES
:
7771 pdoc
->AnnotationSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7774 case SCI_ANNOTATIONGETSTYLES
: {
7775 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7776 return BytesResult(lParam
, st
.styles
, st
.length
);
7779 case SCI_ANNOTATIONGETLINES
:
7780 return pdoc
->AnnotationLines(static_cast<int>(wParam
));
7782 case SCI_ANNOTATIONCLEARALL
:
7783 pdoc
->AnnotationClearAll();
7786 case SCI_ANNOTATIONSETVISIBLE
:
7787 SetAnnotationVisible(static_cast<int>(wParam
));
7790 case SCI_ANNOTATIONGETVISIBLE
:
7791 return vs
.annotationVisible
;
7793 case SCI_ANNOTATIONSETSTYLEOFFSET
:
7794 vs
.annotationStyleOffset
= static_cast<int>(wParam
);
7795 InvalidateStyleRedraw();
7798 case SCI_ANNOTATIONGETSTYLEOFFSET
:
7799 return vs
.annotationStyleOffset
;
7801 case SCI_RELEASEALLEXTENDEDSTYLES
:
7802 vs
.ReleaseAllExtendedStyles();
7805 case SCI_ALLOCATEEXTENDEDSTYLES
:
7806 return vs
.AllocateExtendedStyles(static_cast<int>(wParam
));
7808 case SCI_ADDUNDOACTION
:
7809 pdoc
->AddUndoAction(static_cast<int>(wParam
), lParam
& UNDO_MAY_COALESCE
);
7812 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH
:
7813 mouseSelectionRectangularSwitch
= wParam
!= 0;
7816 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH
:
7817 return mouseSelectionRectangularSwitch
;
7819 case SCI_SETMULTIPLESELECTION
:
7820 multipleSelection
= wParam
!= 0;
7824 case SCI_GETMULTIPLESELECTION
:
7825 return multipleSelection
;
7827 case SCI_SETADDITIONALSELECTIONTYPING
:
7828 additionalSelectionTyping
= wParam
!= 0;
7832 case SCI_GETADDITIONALSELECTIONTYPING
:
7833 return additionalSelectionTyping
;
7835 case SCI_SETMULTIPASTE
:
7836 multiPasteMode
= static_cast<int>(wParam
);
7839 case SCI_GETMULTIPASTE
:
7840 return multiPasteMode
;
7842 case SCI_SETADDITIONALCARETSBLINK
:
7843 view
.additionalCaretsBlink
= wParam
!= 0;
7847 case SCI_GETADDITIONALCARETSBLINK
:
7848 return view
.additionalCaretsBlink
;
7850 case SCI_SETADDITIONALCARETSVISIBLE
:
7851 view
.additionalCaretsVisible
= wParam
!= 0;
7855 case SCI_GETADDITIONALCARETSVISIBLE
:
7856 return view
.additionalCaretsVisible
;
7858 case SCI_GETSELECTIONS
:
7861 case SCI_GETSELECTIONEMPTY
:
7864 case SCI_CLEARSELECTIONS
:
7866 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7870 case SCI_SETSELECTION
:
7871 sel
.SetSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7875 case SCI_ADDSELECTION
:
7876 sel
.AddSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7877 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7881 case SCI_DROPSELECTIONN
:
7882 sel
.DropSelection(static_cast<int>(wParam
));
7883 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7887 case SCI_SETMAINSELECTION
:
7888 sel
.SetMain(static_cast<int>(wParam
));
7889 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7893 case SCI_GETMAINSELECTION
:
7896 case SCI_SETSELECTIONNCARET
:
7897 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7898 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7902 case SCI_GETSELECTIONNCARET
:
7903 return sel
.Range(wParam
).caret
.Position();
7905 case SCI_SETSELECTIONNANCHOR
:
7906 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7907 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7910 case SCI_GETSELECTIONNANCHOR
:
7911 return sel
.Range(wParam
).anchor
.Position();
7913 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
7914 sel
.Range(wParam
).caret
.SetVirtualSpace(static_cast<int>(lParam
));
7915 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7919 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
7920 return sel
.Range(wParam
).caret
.VirtualSpace();
7922 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
7923 sel
.Range(wParam
).anchor
.SetVirtualSpace(static_cast<int>(lParam
));
7924 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7928 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
7929 return sel
.Range(wParam
).anchor
.VirtualSpace();
7931 case SCI_SETSELECTIONNSTART
:
7932 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7933 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7937 case SCI_GETSELECTIONNSTART
:
7938 return sel
.Range(wParam
).Start().Position();
7940 case SCI_SETSELECTIONNEND
:
7941 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7942 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7946 case SCI_GETSELECTIONNEND
:
7947 return sel
.Range(wParam
).End().Position();
7949 case SCI_SETRECTANGULARSELECTIONCARET
:
7950 if (!sel
.IsRectangular())
7952 sel
.selType
= Selection::selRectangle
;
7953 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
7954 SetRectangularRange();
7958 case SCI_GETRECTANGULARSELECTIONCARET
:
7959 return sel
.Rectangular().caret
.Position();
7961 case SCI_SETRECTANGULARSELECTIONANCHOR
:
7962 if (!sel
.IsRectangular())
7964 sel
.selType
= Selection::selRectangle
;
7965 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
7966 SetRectangularRange();
7970 case SCI_GETRECTANGULARSELECTIONANCHOR
:
7971 return sel
.Rectangular().anchor
.Position();
7973 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7974 if (!sel
.IsRectangular())
7976 sel
.selType
= Selection::selRectangle
;
7977 sel
.Rectangular().caret
.SetVirtualSpace(static_cast<int>(wParam
));
7978 SetRectangularRange();
7982 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7983 return sel
.Rectangular().caret
.VirtualSpace();
7985 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7986 if (!sel
.IsRectangular())
7988 sel
.selType
= Selection::selRectangle
;
7989 sel
.Rectangular().anchor
.SetVirtualSpace(static_cast<int>(wParam
));
7990 SetRectangularRange();
7994 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7995 return sel
.Rectangular().anchor
.VirtualSpace();
7997 case SCI_SETVIRTUALSPACEOPTIONS
:
7998 virtualSpaceOptions
= static_cast<int>(wParam
);
8001 case SCI_GETVIRTUALSPACEOPTIONS
:
8002 return virtualSpaceOptions
;
8004 case SCI_SETADDITIONALSELFORE
:
8005 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(wParam
));
8006 InvalidateStyleRedraw();
8009 case SCI_SETADDITIONALSELBACK
:
8010 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(wParam
));
8011 InvalidateStyleRedraw();
8014 case SCI_SETADDITIONALSELALPHA
:
8015 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
8016 InvalidateStyleRedraw();
8019 case SCI_GETADDITIONALSELALPHA
:
8020 return vs
.selAdditionalAlpha
;
8022 case SCI_SETADDITIONALCARETFORE
:
8023 vs
.additionalCaretColour
= ColourDesired(static_cast<long>(wParam
));
8024 InvalidateStyleRedraw();
8027 case SCI_GETADDITIONALCARETFORE
:
8028 return vs
.additionalCaretColour
.AsLong();
8030 case SCI_ROTATESELECTION
:
8032 InvalidateWholeSelection();
8035 case SCI_SWAPMAINANCHORCARET
:
8036 InvalidateSelection(sel
.RangeMain());
8037 sel
.RangeMain().Swap();
8040 case SCI_MULTIPLESELECTADDNEXT
:
8041 MultipleSelectAdd(addOne
);
8044 case SCI_MULTIPLESELECTADDEACH
:
8045 MultipleSelectAdd(addEach
);
8048 case SCI_CHANGELEXERSTATE
:
8049 pdoc
->ChangeLexerState(static_cast<int>(wParam
), static_cast<int>(lParam
));
8052 case SCI_SETIDENTIFIER
:
8053 SetCtrlID(static_cast<int>(wParam
));
8056 case SCI_GETIDENTIFIER
:
8059 case SCI_SETTECHNOLOGY
:
8060 // No action by default
8063 case SCI_GETTECHNOLOGY
:
8066 case SCI_COUNTCHARACTERS
:
8067 return pdoc
->CountCharacters(static_cast<int>(wParam
), static_cast<int>(lParam
));
8070 return DefWndProc(iMessage
, wParam
, lParam
);
8072 //Platform::DebugPrintf("end wnd proc\n");