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"
28 #include "SplitVector.h"
29 #include "Partitioning.h"
30 #include "RunStyles.h"
31 #include "ContractionState.h"
32 #include "CellBuffer.h"
35 #include "Indicator.h"
37 #include "LineMarker.h"
39 #include "ViewStyle.h"
40 #include "CharClassify.h"
41 #include "Decoration.h"
42 #include "CaseFolder.h"
44 #include "UniConversion.h"
45 #include "Selection.h"
46 #include "PositionCache.h"
47 #include "EditModel.h"
48 #include "MarginView.h"
53 using namespace Scintilla
;
57 return whether this modification represents an operation that
58 may reasonably be deferred (not done now OR [possibly] at all)
60 static bool CanDeferToLastStep(const DocModification
&mh
) {
61 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
62 return true; // CAN skip
63 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
64 return false; // MUST do
65 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
66 return true; // CAN skip
67 return false; // PRESUMABLY must do
70 static bool CanEliminate(const DocModification
&mh
) {
72 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
76 return whether this modification represents the FINAL step
77 in a [possibly lengthy] multi-step Undo/Redo sequence
79 static bool IsLastStep(const DocModification
&mh
) {
81 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
82 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
83 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
84 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
88 ticking(false), ticksToWait(0), tickerID(0) {}
91 state(false), idlerID(0) {}
93 static inline bool IsAllSpacesOrTabs(const char *s
, unsigned int len
) {
94 for (unsigned int i
= 0; i
< len
; i
++) {
95 // This is safe because IsSpaceOrTab() will return false for null terminators
96 if (!IsSpaceOrTab(s
[i
]))
106 technology
= SC_TECHNOLOGY_DEFAULT
;
107 scaleRGBAImage
= 100.0f
;
109 cursorMode
= SC_CURSORNORMAL
;
113 mouseDownCaptures
= true;
116 doubleClickCloseThreshold
= Point(3, 3);
117 dwellDelay
= SC_TIME_FOREVER
;
118 ticksToDwell
= SC_TIME_FOREVER
;
123 dropWentOutside
= false;
124 posDrop
= SelectionPosition(invalidPosition
);
125 hotSpotClickPos
= INVALID_POSITION
;
126 selectionType
= selChar
;
130 originalAnchorPos
= 0;
131 wordSelectAnchorStartPos
= 0;
132 wordSelectAnchorEndPos
= 0;
133 wordSelectInitialCaretPos
= -1;
135 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
138 caretYPolicy
= CARET_EVEN
;
147 horizontalScrollBarVisible
= true;
149 verticalScrollBarVisible
= true;
150 endAtLastLine
= true;
151 caretSticky
= SC_CARETSTICKY_OFF
;
152 marginOptions
= SC_MARGINOPTION_NONE
;
153 mouseSelectionRectangularSwitch
= false;
154 multipleSelection
= false;
155 additionalSelectionTyping
= false;
156 multiPasteMode
= SC_MULTIPASTE_ONCE
;
157 virtualSpaceOptions
= SCVS_NONE
;
166 lengthForEncode
= -1;
169 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
171 paintState
= notPainting
;
172 paintAbandonedByStyling
= false;
173 paintingAllText
= false;
174 willRedrawAll
= false;
176 modEventMask
= SC_MODEVENTMASKALL
;
178 pdoc
->AddWatcher(this, 0);
180 recordingMacro
= false;
183 convertPastes
= true;
185 SetRepresentations();
189 pdoc
->RemoveWatcher(this, 0);
193 void Editor::Finalise() {
198 void Editor::SetRepresentations() {
202 const char *reps
[] = {
203 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
204 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
205 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
206 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
208 for (size_t j
=0; j
< ELEMENTS(reps
); j
++) {
209 char c
[2] = { static_cast<char>(j
), 0 };
210 reprs
.SetRepresentation(c
, reps
[j
]);
214 // As well as Unicode mode, ISO-8859-1 should use these
215 if (IsUnicodeMode()) {
216 const char *repsC1
[] = {
217 "PAD", "HOP", "BPH", "NBH", "IND", "NEL", "SSA", "ESA",
218 "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
219 "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
220 "SOS", "SGCI", "SCI", "CSI", "ST", "OSC", "PM", "APC"
222 for (size_t j
=0; j
< ELEMENTS(repsC1
); j
++) {
223 char c1
[3] = { '\xc2', static_cast<char>(0x80+j
), 0 };
224 reprs
.SetRepresentation(c1
, repsC1
[j
]);
226 reprs
.SetRepresentation("\xe2\x80\xa8", "LS");
227 reprs
.SetRepresentation("\xe2\x80\xa9", "PS");
230 // UTF-8 invalid bytes
231 if (IsUnicodeMode()) {
232 for (int k
=0x80; k
< 0x100; k
++) {
233 char hiByte
[2] = { static_cast<char>(k
), 0 };
235 sprintf(hexits
, "x%2X", k
);
236 reprs
.SetRepresentation(hiByte
, hexits
);
241 void Editor::DropGraphics(bool freeObjects
) {
242 marginView
.DropGraphics(freeObjects
);
243 view
.DropGraphics(freeObjects
);
246 void Editor::AllocateGraphics() {
247 marginView
.AllocateGraphics(vs
);
248 view
.AllocateGraphics(vs
);
251 void Editor::InvalidateStyleData() {
253 vs
.technology
= technology
;
256 view
.llc
.Invalidate(LineLayout::llInvalid
);
257 view
.posCache
.Clear();
260 void Editor::InvalidateStyleRedraw() {
262 InvalidateStyleData();
266 void Editor::RefreshStyleData() {
269 AutoSurface
surface(this);
271 vs
.Refresh(*surface
, pdoc
->tabInChars
);
274 SetRectangularRange();
278 Point
Editor::GetVisibleOriginInMain() const {
282 Point
Editor::DocumentPointFromView(Point ptView
) const {
283 Point ptDocument
= ptView
;
284 if (wMargin
.GetID()) {
285 Point ptOrigin
= GetVisibleOriginInMain();
286 ptDocument
.x
+= ptOrigin
.x
;
287 ptDocument
.y
+= ptOrigin
.y
;
289 ptDocument
.x
+= xOffset
;
290 ptDocument
.y
+= topLine
* vs
.lineHeight
;
295 int Editor::TopLineOfMain() const {
302 PRectangle
Editor::GetClientRectangle() const {
303 Window
&win
= const_cast<Window
&>(wMain
);
304 return win
.GetClientPosition();
307 PRectangle
Editor::GetClientDrawingRectangle() {
308 return GetClientRectangle();
311 PRectangle
Editor::GetTextRectangle() const {
312 PRectangle rc
= GetClientRectangle();
313 rc
.left
+= vs
.textStart
;
314 rc
.right
-= vs
.rightMarginWidth
;
318 int Editor::LinesOnScreen() const {
319 PRectangle rcClient
= GetClientRectangle();
320 int htClient
= static_cast<int>(rcClient
.bottom
- rcClient
.top
);
321 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
322 return htClient
/ vs
.lineHeight
;
325 int Editor::LinesToScroll() const {
326 int retVal
= LinesOnScreen() - 1;
333 int Editor::MaxScrollPos() const {
334 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
335 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
336 int retVal
= cs
.LinesDisplayed();
338 retVal
-= LinesOnScreen();
349 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
350 if (sp
.Position() < 0) {
351 return SelectionPosition(0);
352 } else if (sp
.Position() > pdoc
->Length()) {
353 return SelectionPosition(pdoc
->Length());
355 // If not at end of line then set offset to 0
356 if (!pdoc
->IsLineEndPosition(sp
.Position()))
357 sp
.SetVirtualSpace(0);
362 Point
Editor::LocationFromPosition(SelectionPosition pos
) {
364 AutoSurface
surface(this);
365 return view
.LocationFromPosition(surface
, *this, pos
, topLine
, vs
);
368 Point
Editor::LocationFromPosition(int pos
) {
369 return LocationFromPosition(SelectionPosition(pos
));
372 int Editor::XFromPosition(int pos
) {
373 Point pt
= LocationFromPosition(pos
);
374 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
377 int Editor::XFromPosition(SelectionPosition sp
) {
378 Point pt
= LocationFromPosition(sp
);
379 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
382 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
384 AutoSurface
surface(this);
386 if (canReturnInvalid
) {
387 PRectangle rcClient
= GetTextRectangle();
388 // May be in scroll view coordinates so translate back to main view
389 Point ptOrigin
= GetVisibleOriginInMain();
390 rcClient
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
391 if (!rcClient
.Contains(pt
))
392 return SelectionPosition(INVALID_POSITION
);
393 if (pt
.x
< vs
.textStart
)
394 return SelectionPosition(INVALID_POSITION
);
396 return SelectionPosition(INVALID_POSITION
);
398 pt
= DocumentPointFromView(pt
);
399 return view
.SPositionFromLocation(surface
, *this, pt
, canReturnInvalid
, charPosition
, virtualSpace
, vs
);
402 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
403 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
407 * Find the document position corresponding to an x coordinate on a particular document line.
408 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
409 * This method is used for rectangular selections and does not work on wrapped lines.
411 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
413 if (lineDoc
>= pdoc
->LinesTotal())
414 return SelectionPosition(pdoc
->Length());
415 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
416 AutoSurface
surface(this);
417 return view
.SPositionFromLineX(surface
, *this, lineDoc
, x
, vs
);
420 int Editor::PositionFromLineX(int lineDoc
, int x
) {
421 return SPositionFromLineX(lineDoc
, x
).Position();
424 int Editor::LineFromLocation(Point pt
) const {
425 return cs
.DocFromDisplay(static_cast<int>(pt
.y
) / vs
.lineHeight
+ topLine
);
428 void Editor::SetTopLine(int topLineNew
) {
429 if ((topLine
!= topLineNew
) && (topLineNew
>= 0)) {
430 topLine
= topLineNew
;
431 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
433 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
437 * If painting then abandon the painting because a wider redraw is needed.
438 * @return true if calling code should stop drawing.
440 bool Editor::AbandonPaint() {
441 if ((paintState
== painting
) && !paintingAllText
) {
442 paintState
= paintAbandoned
;
444 return paintState
== paintAbandoned
;
447 void Editor::RedrawRect(PRectangle rc
) {
448 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
450 // Clip the redraw rectangle into the client area
451 PRectangle rcClient
= GetClientRectangle();
452 if (rc
.top
< rcClient
.top
)
453 rc
.top
= rcClient
.top
;
454 if (rc
.bottom
> rcClient
.bottom
)
455 rc
.bottom
= rcClient
.bottom
;
456 if (rc
.left
< rcClient
.left
)
457 rc
.left
= rcClient
.left
;
458 if (rc
.right
> rcClient
.right
)
459 rc
.right
= rcClient
.right
;
461 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
462 wMain
.InvalidateRectangle(rc
);
466 void Editor::DiscardOverdraw() {
467 // Overridden on platforms that may draw outside visible area.
470 void Editor::Redraw() {
471 //Platform::DebugPrintf("Redraw all\n");
472 PRectangle rcClient
= GetClientRectangle();
473 wMain
.InvalidateRectangle(rcClient
);
475 wMargin
.InvalidateAll();
476 //wMain.InvalidateAll();
479 void Editor::RedrawSelMargin(int line
, bool allAfter
) {
480 bool abandonDraw
= false;
481 if (!wMargin
.GetID()) // Margin in main window so may need to abandon and retry
482 abandonDraw
= AbandonPaint();
487 PRectangle rcSelMargin
= GetClientRectangle();
488 rcSelMargin
.right
= rcSelMargin
.left
+ vs
.fixedColumnWidth
;
490 PRectangle rcLine
= RectangleFromRange(Range(pdoc
->LineStart(line
)), 0);
492 // Inflate line rectangle if there are image markers with height larger than line height
493 if (vs
.largestMarkerHeight
> vs
.lineHeight
) {
494 int delta
= (vs
.largestMarkerHeight
- vs
.lineHeight
+ 1) / 2;
496 rcLine
.bottom
+= delta
;
497 if (rcLine
.top
< rcSelMargin
.top
)
498 rcLine
.top
= rcSelMargin
.top
;
499 if (rcLine
.bottom
> rcSelMargin
.bottom
)
500 rcLine
.bottom
= rcSelMargin
.bottom
;
503 rcSelMargin
.top
= rcLine
.top
;
505 rcSelMargin
.bottom
= rcLine
.bottom
;
506 if (rcSelMargin
.Empty())
509 if (wMargin
.GetID()) {
510 Point ptOrigin
= GetVisibleOriginInMain();
511 rcSelMargin
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
512 wMargin
.InvalidateRectangle(rcSelMargin
);
514 wMain
.InvalidateRectangle(rcSelMargin
);
520 PRectangle
Editor::RectangleFromRange(Range r
, int overlap
) {
521 const int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.First()));
522 const int maxLine
= cs
.DisplayLastFromDoc(pdoc
->LineFromPosition(r
.Last()));
523 const PRectangle rcClientDrawing
= GetClientDrawingRectangle();
525 const int leftTextOverlap
= ((xOffset
== 0) && (vs
.leftMarginWidth
> 0)) ? 1 : 0;
526 rc
.left
= static_cast<XYPOSITION
>(vs
.textStart
- leftTextOverlap
);
527 rc
.top
= static_cast<XYPOSITION
>((minLine
- TopLineOfMain()) * vs
.lineHeight
- overlap
);
528 if (rc
.top
< rcClientDrawing
.top
)
529 rc
.top
= rcClientDrawing
.top
;
530 // Extend to right of prepared area if any to prevent artifacts from caret line highlight
531 rc
.right
= rcClientDrawing
.right
;
532 rc
.bottom
= static_cast<XYPOSITION
>((maxLine
- TopLineOfMain() + 1) * vs
.lineHeight
+ overlap
);
537 void Editor::InvalidateRange(int start
, int end
) {
538 RedrawRect(RectangleFromRange(Range(start
, end
), view
.LinesOverlap() ? vs
.lineOverlap
: 0));
541 int Editor::CurrentPosition() const {
542 return sel
.MainCaret();
545 bool Editor::SelectionEmpty() const {
549 SelectionPosition
Editor::SelectionStart() {
550 return sel
.RangeMain().Start();
553 SelectionPosition
Editor::SelectionEnd() {
554 return sel
.RangeMain().End();
557 void Editor::SetRectangularRange() {
558 if (sel
.IsRectangular()) {
559 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
560 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
561 if (sel
.selType
== Selection::selThin
) {
564 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
565 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
566 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
567 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
568 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
569 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
570 range
.ClearVirtualSpace();
571 if (line
== lineAnchorRect
)
572 sel
.SetSelection(range
);
574 sel
.AddSelectionWithoutTrim(range
);
579 void Editor::ThinRectangularRange() {
580 if (sel
.IsRectangular()) {
581 sel
.selType
= Selection::selThin
;
582 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
583 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
585 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
587 SetRectangularRange();
591 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
592 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
593 invalidateWholeSelection
= true;
595 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
596 // +1 for lastAffected ensures caret repainted
597 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
598 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
599 if (invalidateWholeSelection
) {
600 for (size_t r
=0; r
<sel
.Count(); r
++) {
601 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
602 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
603 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
604 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
607 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
608 InvalidateRange(firstAffected
, lastAffected
);
611 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
612 currentPos_
= ClampPositionIntoDocument(currentPos_
);
613 anchor_
= ClampPositionIntoDocument(anchor_
);
614 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
615 /* For Line selection - ensure the anchor and caret are always
616 at the beginning and end of the region lines. */
617 if (sel
.selType
== Selection::selLines
) {
618 if (currentPos_
> anchor_
) {
619 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
620 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
622 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
623 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
626 SelectionRange
rangeNew(currentPos_
, anchor_
);
627 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
628 InvalidateSelection(rangeNew
);
630 sel
.RangeMain() = rangeNew
;
631 SetRectangularRange();
633 SetHoverIndicatorPosition(sel
.MainCaret());
635 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
638 QueueIdleWork(WorkNeeded::workUpdateUI
);
641 void Editor::SetSelection(int currentPos_
, int anchor_
) {
642 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
645 // Just move the caret on the main selection
646 void Editor::SetSelection(SelectionPosition currentPos_
) {
647 currentPos_
= ClampPositionIntoDocument(currentPos_
);
648 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
649 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
650 InvalidateSelection(SelectionRange(currentPos_
));
652 if (sel
.IsRectangular()) {
654 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
655 SetRectangularRange();
658 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
661 SetHoverIndicatorPosition(sel
.MainCaret());
663 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
666 QueueIdleWork(WorkNeeded::workUpdateUI
);
669 void Editor::SetSelection(int currentPos_
) {
670 SetSelection(SelectionPosition(currentPos_
));
673 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
674 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
675 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
676 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
677 InvalidateSelection(rangeNew
);
680 sel
.RangeMain() = rangeNew
;
681 SetRectangularRange();
683 SetHoverIndicatorPosition(sel
.MainCaret());
685 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
688 QueueIdleWork(WorkNeeded::workUpdateUI
);
691 void Editor::SetEmptySelection(int currentPos_
) {
692 SetEmptySelection(SelectionPosition(currentPos_
));
695 bool Editor::RangeContainsProtected(int start
, int end
) const {
696 if (vs
.ProtectionActive()) {
702 for (int pos
= start
; pos
< end
; pos
++) {
703 if (vs
.styles
[pdoc
->StyleAt(pos
)].IsProtected())
710 bool Editor::SelectionContainsProtected() {
711 for (size_t r
=0; r
<sel
.Count(); r
++) {
712 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
713 sel
.Range(r
).End().Position())) {
721 * Asks document to find a good position and then moves out of any invisible positions.
723 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
724 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
727 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
728 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
729 if (posMoved
!= pos
.Position())
730 pos
.SetPosition(posMoved
);
731 if (vs
.ProtectionActive()) {
733 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1)].IsProtected()) {
734 while ((pos
.Position() < pdoc
->Length()) &&
735 (vs
.styles
[pdoc
->StyleAt(pos
.Position())].IsProtected()))
738 } else if (moveDir
< 0) {
739 if (vs
.styles
[pdoc
->StyleAt(pos
.Position())].IsProtected()) {
740 while ((pos
.Position() > 0) &&
741 (vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1)].IsProtected()))
749 int Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
750 bool simpleCaret
= (sel
.Count() == 1) && sel
.Empty();
751 SelectionPosition spCaret
= sel
.Last();
753 int delta
= newPos
.Position() - sel
.MainCaret();
754 newPos
= ClampPositionIntoDocument(newPos
);
755 newPos
= MovePositionOutsideChar(newPos
, delta
);
756 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
757 // Can't turn into multiple selection so clear additional selections
758 InvalidateSelection(SelectionRange(newPos
), true);
759 SelectionRange rangeMain
= sel
.RangeMain();
760 sel
.SetSelection(rangeMain
);
762 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
763 // Switching to rectangular
764 InvalidateSelection(sel
.RangeMain(), false);
765 SelectionRange rangeMain
= sel
.RangeMain();
767 sel
.Rectangular() = rangeMain
;
769 if (selt
!= Selection::noSel
) {
772 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
773 SetSelection(newPos
);
775 SetEmptySelection(newPos
);
777 ShowCaretAtCurrentPosition();
779 int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
781 // In case in need of wrapping to ensure DisplayFromDoc works.
782 if (currentLine
>= wrapPending
.start
)
784 XYScrollPosition newXY
= XYScrollToMakeVisible(
785 SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
), xysDefault
);
786 if (simpleCaret
&& (newXY
.xOffset
== xOffset
)) {
787 // simple vertical scroll then invalidate
788 ScrollTo(newXY
.topLine
);
789 InvalidateSelection(SelectionRange(spCaret
), true);
795 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
801 int Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
802 return MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
805 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
806 pos
= ClampPositionIntoDocument(pos
);
807 pos
= MovePositionOutsideChar(pos
, moveDir
);
808 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
809 if (cs
.GetVisible(lineDoc
)) {
812 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
814 // lineDisplay is already line before fold as lines in fold use display line of line after fold
815 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
816 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
818 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
819 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
824 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
825 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
828 Point
Editor::PointMainCaret() {
829 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
833 * Choose the x position that the caret will try to stick to
834 * as it moves up and down.
836 void Editor::SetLastXChosen() {
837 Point pt
= PointMainCaret();
838 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
841 void Editor::ScrollTo(int line
, bool moveThumb
) {
842 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
843 if (topLineNew
!= topLine
) {
844 // Try to optimise small scrolls
846 int linesToMove
= topLine
- topLineNew
;
847 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
848 willRedrawAll
= !performBlit
;
850 SetTopLine(topLineNew
);
851 // Optimize by styling the view as this will invalidate any needed area
852 // which could abort the initial paint if discovered later.
853 StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
855 // Perform redraw rather than scroll if many lines would be redrawn anyway.
857 ScrollText(linesToMove
);
861 willRedrawAll
= false;
866 SetVerticalScrollPos();
871 void Editor::ScrollText(int /* linesToMove */) {
872 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
876 void Editor::HorizontalScrollTo(int xPos
) {
877 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
880 if (!Wrapping() && (xOffset
!= xPos
)) {
882 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
883 SetHorizontalScrollPos();
884 RedrawRect(GetClientRectangle());
888 void Editor::VerticalCentreCaret() {
889 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
890 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
891 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
892 if (topLine
!= newTop
) {
893 SetTopLine(newTop
> 0 ? newTop
: 0);
894 RedrawRect(GetClientRectangle());
898 // Avoid 64 bit compiler warnings.
899 // Scintilla does not support text buffers larger than 2**31
900 static int istrlen(const char *s
) {
901 return static_cast<int>(s
? strlen(s
) : 0);
904 void Editor::MoveSelectedLines(int lineDelta
) {
906 // if selection doesn't start at the beginning of the line, set the new start
907 int selectionStart
= SelectionStart().Position();
908 int startLine
= pdoc
->LineFromPosition(selectionStart
);
909 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
910 selectionStart
= beginningOfStartLine
;
912 // if selection doesn't end at the beginning of a line greater than that of the start,
913 // then set it at the beginning of the next one
914 int selectionEnd
= SelectionEnd().Position();
915 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
916 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
917 bool appendEol
= false;
918 if (selectionEnd
> beginningOfEndLine
919 || selectionStart
== selectionEnd
) {
920 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
921 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
924 // if there's nowhere for the selection to move
925 // (i.e. at the beginning going up or at the end going down),
926 // stop it right there!
927 if ((selectionStart
== 0 && lineDelta
< 0)
928 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
929 || selectionStart
== selectionEnd
) {
935 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
936 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
938 selectionEnd
= CurrentPosition();
940 SetSelection(selectionStart
, selectionEnd
);
942 SelectionText selectedText
;
943 CopySelectionRange(&selectedText
);
945 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
946 Point currentLocation
= LocationFromPosition(CurrentPosition());
947 int currentLine
= LineFromLocation(currentLocation
);
950 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
953 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
954 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
955 pdoc
->InsertString(pdoc
->Length(), eol
, istrlen(eol
));
956 GoToLine(currentLine
+ lineDelta
);
958 selectionLength
= pdoc
->InsertString(CurrentPosition(), selectedText
.Data(), selectionLength
);
960 const int lengthInserted
= pdoc
->InsertString(CurrentPosition() + selectionLength
, eol
, istrlen(eol
));
961 selectionLength
+= lengthInserted
;
963 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
966 void Editor::MoveSelectedLinesUp() {
967 MoveSelectedLines(-1);
970 void Editor::MoveSelectedLinesDown() {
971 MoveSelectedLines(1);
974 void Editor::MoveCaretInsideView(bool ensureVisible
) {
975 PRectangle rcClient
= GetTextRectangle();
976 Point pt
= PointMainCaret();
977 if (pt
.y
< rcClient
.top
) {
978 MovePositionTo(SPositionFromLocation(
979 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
)),
980 false, false, UserVirtualSpace()),
981 Selection::noSel
, ensureVisible
);
982 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
983 int yOfLastLineFullyDisplayed
= static_cast<int>(rcClient
.top
) + (LinesOnScreen() - 1) * vs
.lineHeight
;
984 MovePositionTo(SPositionFromLocation(
985 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
) + yOfLastLineFullyDisplayed
),
986 false, false, UserVirtualSpace()),
987 Selection::noSel
, ensureVisible
);
991 int Editor::DisplayFromPosition(int pos
) {
992 AutoSurface
surface(this);
993 return view
.DisplayFromPosition(surface
, *this, pos
, vs
);
997 * Ensure the caret is reasonably visible in context.
999 Caret policy in SciTE
1001 If slop is set, we can define a slop value.
1002 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1003 This zone is defined as a number of pixels near the vertical margins,
1004 and as a number of lines near the horizontal margins.
1005 By keeping the caret away from the edges, it is seen within its context,
1006 so it is likely that the identifier that the caret is on can be completely seen,
1007 and that the current line is seen with some of the lines following it which are
1008 often dependent on that line.
1010 If strict is set, the policy is enforced... strictly.
1011 The caret is centred on the display if slop is not set,
1012 and cannot go in the UZ if slop is set.
1014 If jumps is set, the display is moved more energetically
1015 so the caret can move in the same direction longer before the policy is applied again.
1016 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1018 If even is not set, instead of having symmetrical UZs,
1019 the left and bottom UZs are extended up to right and top UZs respectively.
1020 This way, we favour the displaying of useful information: the beginning of lines,
1021 where most code reside, and the lines after the caret, eg. the body of a function.
1024 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1025 | | | | | visibility or going into the UZ) display is...
1026 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1027 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1028 0 | 0 | 0 | 1 | Yes | moved by one position
1029 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1030 0 | 0 | 1 | 1 | Yes | centred on the caret
1031 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1032 0 | 1 | - | 1 | No, caret is always centred | -
1033 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1034 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1035 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1036 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1037 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1038 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1039 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1042 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const SelectionRange
&range
, const XYScrollOptions options
) {
1043 PRectangle rcClient
= GetTextRectangle();
1044 Point pt
= LocationFromPosition(range
.caret
);
1045 Point ptAnchor
= LocationFromPosition(range
.anchor
);
1046 const Point ptOrigin
= GetVisibleOriginInMain();
1049 ptAnchor
.x
+= ptOrigin
.x
;
1050 ptAnchor
.y
+= ptOrigin
.y
;
1051 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1053 XYScrollPosition
newXY(xOffset
, topLine
);
1054 if (rcClient
.Empty()) {
1058 // Vertical positioning
1059 if ((options
& xysVertical
) && (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1060 const int lineCaret
= DisplayFromPosition(range
.caret
.Position());
1061 const int linesOnScreen
= LinesOnScreen();
1062 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1063 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1064 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1065 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1066 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1068 // It should be possible to scroll the window to show the caret,
1069 // but this fails to remove the caret on GTK+
1070 if (bSlop
) { // A margin is defined
1073 int yMarginT
, yMarginB
;
1074 if (!(options
& xysUseMargin
)) {
1075 // In drag mode, avoid moves
1076 // otherwise, a double click will select several lines.
1077 yMarginT
= yMarginB
= 0;
1079 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1080 // a maximum of slightly less than half the heigth of the text area.
1081 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1083 yMarginB
= yMarginT
;
1085 yMarginB
= linesOnScreen
- yMarginT
- 1;
1091 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1095 yMoveB
= linesOnScreen
- yMoveT
- 1;
1097 if (lineCaret
< topLine
+ yMarginT
) {
1098 // Caret goes too high
1099 newXY
.topLine
= lineCaret
- yMoveT
;
1100 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1101 // Caret goes too low
1102 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1104 } else { // Not strict
1105 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1106 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1110 yMoveB
= linesOnScreen
- yMoveT
- 1;
1112 if (lineCaret
< topLine
) {
1113 // Caret goes too high
1114 newXY
.topLine
= lineCaret
- yMoveT
;
1115 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1116 // Caret goes too low
1117 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1121 if (!bStrict
&& !bJump
) {
1123 if (lineCaret
< topLine
) {
1124 // Caret goes too high
1125 newXY
.topLine
= lineCaret
;
1126 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1127 // Caret goes too low
1129 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1131 newXY
.topLine
= lineCaret
;
1134 } else { // Strict or going out of display
1136 // Always center caret
1137 newXY
.topLine
= lineCaret
- halfScreen
;
1139 // Always put caret on top of display
1140 newXY
.topLine
= lineCaret
;
1144 if (!(range
.caret
== range
.anchor
)) {
1145 const int lineAnchor
= DisplayFromPosition(range
.anchor
.Position());
1146 if (lineAnchor
< lineCaret
) {
1147 // Shift up to show anchor or as much of range as possible
1148 newXY
.topLine
= std::min(newXY
.topLine
, lineAnchor
);
1149 newXY
.topLine
= std::max(newXY
.topLine
, lineCaret
- LinesOnScreen());
1151 // Shift down to show anchor or as much of range as possible
1152 newXY
.topLine
= std::max(newXY
.topLine
, lineAnchor
- LinesOnScreen());
1153 newXY
.topLine
= std::min(newXY
.topLine
, lineCaret
);
1156 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1159 // Horizontal positioning
1160 if ((options
& xysHorizontal
) && !Wrapping()) {
1161 const int halfScreen
= Platform::Maximum(static_cast<int>(rcClient
.Width()) - 4, 4) / 2;
1162 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1163 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1164 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1165 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1167 if (bSlop
) { // A margin is defined
1170 int xMarginL
, xMarginR
;
1171 if (!(options
& xysUseMargin
)) {
1172 // In drag mode, avoid moves unless very near of the margin
1173 // otherwise, a simple click will select text.
1174 xMarginL
= xMarginR
= 2;
1176 // xMargin must equal to caretXSlop, with a minimum of 2 and
1177 // a maximum of slightly less than half the width of the text area.
1178 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1180 xMarginL
= xMarginR
;
1182 xMarginL
= static_cast<int>(rcClient
.Width()) - xMarginR
- 4;
1185 if (bJump
&& bEven
) {
1186 // Jump is used only in even mode
1187 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1189 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1191 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1192 // Caret is on the left of the display
1193 if (bJump
&& bEven
) {
1194 newXY
.xOffset
-= xMoveL
;
1196 // Move just enough to allow to display the caret
1197 newXY
.xOffset
-= static_cast<int>((rcClient
.left
+ xMarginL
) - pt
.x
);
1199 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1200 // Caret is on the right of the display
1201 if (bJump
&& bEven
) {
1202 newXY
.xOffset
+= xMoveR
;
1204 // Move just enough to allow to display the caret
1205 newXY
.xOffset
+= static_cast<int>(pt
.x
- (rcClient
.right
- xMarginR
) + 1);
1208 } else { // Not strict
1209 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1210 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1214 xMoveL
= static_cast<int>(rcClient
.Width()) - xMoveR
- 4;
1216 if (pt
.x
< rcClient
.left
) {
1217 // Caret is on the left of the display
1218 newXY
.xOffset
-= xMoveL
;
1219 } else if (pt
.x
>= rcClient
.right
) {
1220 // Caret is on the right of the display
1221 newXY
.xOffset
+= xMoveR
;
1226 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1227 // Strict or going out of display
1230 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.left
- halfScreen
);
1232 // Put caret on right
1233 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
+ 1);
1236 // Move just enough to allow to display the caret
1237 if (pt
.x
< rcClient
.left
) {
1238 // Caret is on the left of the display
1240 newXY
.xOffset
-= static_cast<int>(rcClient
.left
- pt
.x
);
1242 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1244 } else if (pt
.x
>= rcClient
.right
) {
1245 // Caret is on the right of the display
1246 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1250 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1251 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1252 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 2;
1253 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1254 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 2;
1255 if ((vs
.caretStyle
== CARETSTYLE_BLOCK
) || view
.imeCaretBlockOverride
) {
1256 // Ensure we can see a good portion of the block caret
1257 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1260 if (!(range
.caret
== range
.anchor
)) {
1261 if (ptAnchor
.x
< pt
.x
) {
1262 // Shift to left to show anchor or as much of range as possible
1263 int maxOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.left
) - 1;
1264 int minOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 1;
1265 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1266 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1268 // Shift to right to show anchor or as much of range as possible
1269 int minOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.right
) + 1;
1270 int maxOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 1;
1271 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1272 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1275 if (newXY
.xOffset
< 0) {
1283 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1284 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1285 if (newXY
.topLine
!= topLine
) {
1286 SetTopLine(newXY
.topLine
);
1287 SetVerticalScrollPos();
1289 if (newXY
.xOffset
!= xOffset
) {
1290 xOffset
= newXY
.xOffset
;
1291 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1292 if (newXY
.xOffset
> 0) {
1293 PRectangle rcText
= GetTextRectangle();
1294 if (horizontalScrollBarVisible
&&
1295 rcText
.Width() + xOffset
> scrollWidth
) {
1296 scrollWidth
= xOffset
+ static_cast<int>(rcText
.Width());
1300 SetHorizontalScrollPos();
1303 UpdateSystemCaret();
1307 void Editor::ScrollRange(SelectionRange range
) {
1308 SetXYScroll(XYScrollToMakeVisible(range
, xysDefault
));
1311 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1312 SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
),
1313 static_cast<XYScrollOptions
>((useMargin
?xysUseMargin
:0)|(vert
?xysVertical
:0)|(horiz
?xysHorizontal
:0))));
1316 void Editor::ShowCaretAtCurrentPosition() {
1318 caret
.active
= true;
1320 if (FineTickerAvailable()) {
1321 FineTickerCancel(tickCaret
);
1322 if (caret
.period
> 0)
1323 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1328 caret
.active
= false;
1330 if (FineTickerAvailable()) {
1331 FineTickerCancel(tickCaret
);
1337 void Editor::DropCaret() {
1338 caret
.active
= false;
1339 if (FineTickerAvailable()) {
1340 FineTickerCancel(tickCaret
);
1345 void Editor::CaretSetPeriod(int period
) {
1346 if (caret
.period
!= period
) {
1347 caret
.period
= period
;
1349 if (FineTickerAvailable()) {
1350 FineTickerCancel(tickCaret
);
1351 if ((caret
.active
) && (caret
.period
> 0))
1352 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1358 void Editor::InvalidateCaret() {
1359 if (posDrag
.IsValid()) {
1360 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1362 for (size_t r
=0; r
<sel
.Count(); r
++) {
1363 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1366 UpdateSystemCaret();
1369 void Editor::UpdateSystemCaret() {
1372 bool Editor::Wrapping() const {
1373 return vs
.wrapState
!= eWrapNone
;
1376 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1377 //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd);
1378 if (wrapPending
.AddRange(docLineStart
, docLineEnd
)) {
1379 view
.llc
.Invalidate(LineLayout::llPositions
);
1381 // Wrap lines during idle.
1382 if (Wrapping() && wrapPending
.NeedsWrap()) {
1387 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1388 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(lineToWrap
, *this));
1389 int linesWrapped
= 1;
1391 view
.LayoutLine(*this, lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1392 linesWrapped
= ll
->lines
;
1394 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1395 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1398 // Perform wrapping for a subset of the lines needing wrapping.
1399 // wsAll: wrap all lines which need wrapping in this single call
1400 // wsVisible: wrap currently visible lines
1401 // wsIdle: wrap one page + 100 lines
1402 // Return true if wrapping occurred.
1403 bool Editor::WrapLines(enum wrapScope ws
) {
1404 int goodTopLine
= topLine
;
1405 bool wrapOccurred
= false;
1407 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1408 wrapWidth
= LineLayout::wrapWidthInfinite
;
1409 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1410 cs
.SetHeight(lineDoc
, 1 +
1411 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1413 wrapOccurred
= true;
1415 wrapPending
.Reset();
1417 } else if (wrapPending
.NeedsWrap()) {
1418 wrapPending
.start
= std::min(wrapPending
.start
, pdoc
->LinesTotal());
1419 if (!SetIdle(true)) {
1420 // Idle processing not supported so full wrap required.
1423 // Decide where to start wrapping
1424 int lineToWrap
= wrapPending
.start
;
1425 int lineToWrapEnd
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1426 const int lineDocTop
= cs
.DocFromDisplay(topLine
);
1427 const int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1428 if (ws
== wsVisible
) {
1429 lineToWrap
= Platform::Clamp(lineDocTop
-5, wrapPending
.start
, pdoc
->LinesTotal());
1430 // Priority wrap to just after visible area.
1431 // Since wrapping could reduce display lines, treat each
1432 // as taking only one display line.
1433 lineToWrapEnd
= lineDocTop
;
1434 int lines
= LinesOnScreen() + 1;
1435 while ((lineToWrapEnd
< cs
.LinesInDoc()) && (lines
>0)) {
1436 if (cs
.GetVisible(lineToWrapEnd
))
1440 // .. and if the paint window is outside pending wraps
1441 if ((lineToWrap
> wrapPending
.end
) || (lineToWrapEnd
< wrapPending
.start
)) {
1442 // Currently visible text does not need wrapping
1445 } else if (ws
== wsIdle
) {
1446 lineToWrapEnd
= lineToWrap
+ LinesOnScreen() + 100;
1448 const int lineEndNeedWrap
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1449 lineToWrapEnd
= std::min(lineToWrapEnd
, lineEndNeedWrap
);
1451 // Ensure all lines being wrapped are styled.
1452 pdoc
->EnsureStyledTo(pdoc
->LineStart(lineToWrapEnd
));
1454 if (lineToWrap
< lineToWrapEnd
) {
1456 PRectangle rcTextArea
= GetClientRectangle();
1457 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1458 rcTextArea
.right
-= vs
.rightMarginWidth
;
1459 wrapWidth
= static_cast<int>(rcTextArea
.Width());
1461 AutoSurface
surface(this);
1463 //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd);
1465 while (lineToWrap
< lineToWrapEnd
) {
1466 if (WrapOneLine(surface
, lineToWrap
)) {
1467 wrapOccurred
= true;
1469 wrapPending
.Wrapped(lineToWrap
);
1473 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
) + std::min(subLineTop
, cs
.GetHeight(lineDocTop
)-1);
1477 // If wrapping is done, bring it to resting position
1478 if (wrapPending
.start
>= lineEndNeedWrap
) {
1479 wrapPending
.Reset();
1485 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1486 SetVerticalScrollPos();
1489 return wrapOccurred
;
1492 void Editor::LinesJoin() {
1493 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1495 bool prevNonWS
= true;
1496 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1497 if (pdoc
->IsPositionInLineEnd(pos
)) {
1498 targetEnd
-= pdoc
->LenChar(pos
);
1501 // Ensure at least one space separating previous lines
1502 const int lengthInserted
= pdoc
->InsertString(pos
, " ", 1);
1503 targetEnd
+= lengthInserted
;
1506 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1512 const char *Editor::StringFromEOLMode(int eolMode
) {
1513 if (eolMode
== SC_EOL_CRLF
) {
1515 } else if (eolMode
== SC_EOL_CR
) {
1522 void Editor::LinesSplit(int pixelWidth
) {
1523 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1524 if (pixelWidth
== 0) {
1525 PRectangle rcText
= GetTextRectangle();
1526 pixelWidth
= static_cast<int>(rcText
.Width());
1528 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1529 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1530 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1532 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1533 AutoSurface
surface(this);
1534 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
1535 if (surface
&& ll
) {
1536 unsigned int posLineStart
= pdoc
->LineStart(line
);
1537 view
.LayoutLine(*this, line
, surface
, vs
, ll
, pixelWidth
);
1538 int lengthInsertedTotal
= 0;
1539 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1540 const int lengthInserted
= pdoc
->InsertString(
1541 static_cast<int>(posLineStart
+ lengthInsertedTotal
+
1542 ll
->LineStart(subLine
)),
1544 targetEnd
+= lengthInserted
;
1545 lengthInsertedTotal
+= lengthInserted
;
1548 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1553 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1554 if (vs
.fixedColumnWidth
== 0)
1559 RefreshPixMaps(surfWindow
);
1561 // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished
1562 // at this point. The Initialised call checks for this case and sets the status
1563 // to be bad which avoids crashes in following calls.
1564 if (!surfWindow
->Initialised()) {
1568 PRectangle rcMargin
= GetClientRectangle();
1569 Point ptOrigin
= GetVisibleOriginInMain();
1570 rcMargin
.Move(0, -ptOrigin
.y
);
1572 rcMargin
.right
= static_cast<XYPOSITION
>(vs
.fixedColumnWidth
);
1574 if (!rc
.Intersects(rcMargin
))
1578 if (view
.bufferedDraw
) {
1579 surface
= marginView
.pixmapSelMargin
;
1581 surface
= surfWindow
;
1584 // Clip vertically to paint area to avoid drawing line numbers
1585 if (rcMargin
.bottom
> rc
.bottom
)
1586 rcMargin
.bottom
= rc
.bottom
;
1587 if (rcMargin
.top
< rc
.top
)
1588 rcMargin
.top
= rc
.top
;
1590 marginView
.PaintMargin(surface
, topLine
, rc
, rcMargin
, *this, vs
);
1592 if (view
.bufferedDraw
) {
1593 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *marginView
.pixmapSelMargin
);
1597 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
1598 view
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1599 marginView
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1600 if (view
.bufferedDraw
) {
1601 PRectangle rcClient
= GetClientRectangle();
1602 if (!view
.pixmapLine
->Initialised()) {
1604 view
.pixmapLine
->InitPixMap(static_cast<int>(rcClient
.Width()), vs
.lineHeight
,
1605 surfaceWindow
, wMain
.GetID());
1607 if (!marginView
.pixmapSelMargin
->Initialised()) {
1608 marginView
.pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1609 static_cast<int>(rcClient
.Height()), surfaceWindow
, wMain
.GetID());
1614 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1615 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1616 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1620 if (paintState
== paintAbandoned
)
1621 return; // Scroll bars may have changed so need redraw
1622 RefreshPixMaps(surfaceWindow
);
1624 paintAbandonedByStyling
= false;
1626 StyleToPositionInView(PositionAfterArea(rcArea
));
1628 PRectangle rcClient
= GetClientRectangle();
1629 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1630 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1632 if (NotifyUpdateUI()) {
1634 RefreshPixMaps(surfaceWindow
);
1637 // Wrap the visible lines if needed.
1638 if (WrapLines(wsVisible
)) {
1639 // The wrapping process has changed the height of some lines so
1640 // abandon this paint for a complete repaint.
1641 if (AbandonPaint()) {
1644 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
1646 PLATFORM_ASSERT(marginView
.pixmapSelPattern
->Initialised());
1648 if (!view
.bufferedDraw
)
1649 surfaceWindow
->SetClip(rcArea
);
1651 if (paintState
!= paintAbandoned
) {
1652 if (vs
.marginInside
) {
1653 PaintSelMargin(surfaceWindow
, rcArea
);
1654 PRectangle rcRightMargin
= rcClient
;
1655 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1656 if (rcArea
.Intersects(rcRightMargin
)) {
1657 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1659 } else { // Else separate view so separate paint event but leftMargin included to allow overlap
1660 PRectangle rcLeftMargin
= rcArea
;
1661 rcLeftMargin
.left
= 0;
1662 rcLeftMargin
.right
= rcLeftMargin
.left
+ vs
.leftMarginWidth
;
1663 if (rcArea
.Intersects(rcLeftMargin
)) {
1664 surfaceWindow
->FillRectangle(rcLeftMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1669 if (paintState
== paintAbandoned
) {
1670 // Either styling or NotifyUpdateUI noticed that painting is needed
1671 // outside the current painting rectangle
1672 //Platform::DebugPrintf("Abandoning paint\n");
1674 if (paintAbandonedByStyling
) {
1675 // Styling has spilled over a line end, such as occurs by starting a multiline
1676 // comment. The width of subsequent text may have changed, so rewrap.
1677 NeedWrapping(cs
.DocFromDisplay(topLine
));
1683 view
.PaintText(surfaceWindow
, *this, rcArea
, rcClient
, vs
);
1685 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
1686 if (FineTickerAvailable()) {
1687 scrollWidth
= view
.lineWidthMaxSeen
;
1688 if (!FineTickerRunning(tickWiden
)) {
1689 FineTickerStart(tickWiden
, 50, 5);
1697 // This is mostly copied from the Paint method but with some things omitted
1698 // such as the margin markers, line numbers, selection and caret
1699 // Should be merged back into a combined Draw method.
1700 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
1704 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
1707 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
1708 if (!surfaceMeasure
) {
1711 return view
.FormatRange(draw
, pfr
, surface
, surfaceMeasure
, *this, vs
);
1714 int Editor::TextWidth(int style
, const char *text
) {
1716 AutoSurface
surface(this);
1718 return static_cast<int>(surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
)));
1724 // Empty method is overridden on GTK+ to show / hide scrollbars
1725 void Editor::ReconfigureScrollBars() {}
1727 void Editor::SetScrollBars() {
1730 int nMax
= MaxScrollPos();
1731 int nPage
= LinesOnScreen();
1732 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
1737 // TODO: ensure always showing as many lines as possible
1738 // May not be, if, for example, window made larger
1739 if (topLine
> MaxScrollPos()) {
1740 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1741 SetVerticalScrollPos();
1745 if (!AbandonPaint())
1748 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1751 void Editor::ChangeSize() {
1752 DropGraphics(false);
1755 PRectangle rcTextArea
= GetClientRectangle();
1756 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1757 rcTextArea
.right
-= vs
.rightMarginWidth
;
1758 if (wrapWidth
!= rcTextArea
.Width()) {
1765 int Editor::InsertSpace(int position
, unsigned int spaces
) {
1767 std::string
spaceText(spaces
, ' ');
1768 const int lengthInserted
= pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
1769 position
+= lengthInserted
;
1774 void Editor::AddChar(char ch
) {
1781 void Editor::FilterSelections() {
1782 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
1783 SelectionRange rangeOnly
= sel
.RangeMain();
1784 InvalidateSelection(rangeOnly
, true);
1785 sel
.SetSelection(rangeOnly
);
1789 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
1793 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
1794 void Editor::AddCharUTF(const char *s
, unsigned int len
, bool treatAsDBCS
) {
1797 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1799 // Vector elements point into selection in order to change selection.
1800 std::vector
<SelectionRange
*> selPtrs
;
1801 for (size_t r
= 0; r
< sel
.Count(); r
++) {
1802 selPtrs
.push_back(&sel
.Range(r
));
1804 // Order selections by position in document.
1805 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
1807 // Loop in reverse to avoid disturbing positions of selections yet to be processed.
1808 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
1809 rit
!= selPtrs
.rend(); ++rit
) {
1810 SelectionRange
*currentSel
= *rit
;
1811 if (!RangeContainsProtected(currentSel
->Start().Position(),
1812 currentSel
->End().Position())) {
1813 int positionInsert
= currentSel
->Start().Position();
1814 if (!currentSel
->Empty()) {
1815 if (currentSel
->Length()) {
1816 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
1817 currentSel
->ClearVirtualSpace();
1819 // Range is all virtual so collapse to start of virtual space
1820 currentSel
->MinimizeVirtualSpace();
1822 } else if (inOverstrike
) {
1823 if (positionInsert
< pdoc
->Length()) {
1824 if (!pdoc
->IsPositionInLineEnd(positionInsert
)) {
1825 pdoc
->DelChar(positionInsert
);
1826 currentSel
->ClearVirtualSpace();
1830 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
1831 const int lengthInserted
= pdoc
->InsertString(positionInsert
, s
, len
);
1832 if (lengthInserted
> 0) {
1833 currentSel
->caret
.SetPosition(positionInsert
+ lengthInserted
);
1834 currentSel
->anchor
.SetPosition(positionInsert
+ lengthInserted
);
1836 currentSel
->ClearVirtualSpace();
1837 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1839 AutoSurface
surface(this);
1841 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
1843 SetVerticalScrollPos();
1854 ThinRectangularRange();
1855 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1856 EnsureCaretVisible();
1857 // Avoid blinking during rapid typing:
1858 ShowCaretAtCurrentPosition();
1859 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
1860 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
1865 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
1866 static_cast<unsigned char>(s
[1]));
1867 } else if (len
> 0) {
1868 int byte
= static_cast<unsigned char>(s
[0]);
1869 if ((byte
< 0xC0) || (1 == len
)) {
1870 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1871 // characters when not in UTF-8 mode.
1872 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1873 // characters representing themselves.
1875 unsigned int utf32
[1] = { 0 };
1876 UTF32FromUTF8(s
, len
, utf32
, ELEMENTS(utf32
));
1882 if (recordingMacro
) {
1883 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
1887 void Editor::FillVirtualSpace() {
1888 const bool tmpOverstrike
= inOverstrike
;
1889 inOverstrike
= false; // not allow to be deleted twice.
1891 inOverstrike
= tmpOverstrike
;
1894 void Editor::InsertPaste(const char *text
, int len
) {
1895 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
1896 SelectionPosition selStart
= sel
.Start();
1897 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
1898 const int lengthInserted
= pdoc
->InsertString(selStart
.Position(), text
, len
);
1899 if (lengthInserted
> 0) {
1900 SetEmptySelection(selStart
.Position() + lengthInserted
);
1903 // SC_MULTIPASTE_EACH
1904 for (size_t r
=0; r
<sel
.Count(); r
++) {
1905 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1906 sel
.Range(r
).End().Position())) {
1907 int positionInsert
= sel
.Range(r
).Start().Position();
1908 if (!sel
.Range(r
).Empty()) {
1909 if (sel
.Range(r
).Length()) {
1910 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1911 sel
.Range(r
).ClearVirtualSpace();
1913 // Range is all virtual so collapse to start of virtual space
1914 sel
.Range(r
).MinimizeVirtualSpace();
1917 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
1918 const int lengthInserted
= pdoc
->InsertString(positionInsert
, text
, len
);
1919 if (lengthInserted
> 0) {
1920 sel
.Range(r
).caret
.SetPosition(positionInsert
+ lengthInserted
);
1921 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ lengthInserted
);
1923 sel
.Range(r
).ClearVirtualSpace();
1929 void Editor::InsertPasteShape(const char *text
, int len
, PasteShape shape
) {
1930 std::string convertedText
;
1931 if (convertPastes
) {
1932 // Convert line endings of the paste into our local line-endings mode
1933 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
1934 len
= static_cast<int>(convertedText
.length());
1935 text
= convertedText
.c_str();
1937 if (shape
== pasteRectangular
) {
1938 PasteRectangular(sel
.Start(), text
, len
);
1940 if (shape
== pasteLine
) {
1941 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
1942 int lengthInserted
= pdoc
->InsertString(insertPos
, text
, len
);
1943 // add the newline if necessary
1944 if ((len
> 0) && (text
[len
- 1] != '\n' && text
[len
- 1] != '\r')) {
1945 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
1946 int length
= static_cast<int>(strlen(endline
));
1947 lengthInserted
+= pdoc
->InsertString(insertPos
+ lengthInserted
, endline
, length
);
1949 if (sel
.MainCaret() == insertPos
) {
1950 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
1953 InsertPaste(text
, len
);
1958 void Editor::ClearSelection(bool retainMultipleSelections
) {
1959 if (!sel
.IsRectangular() && !retainMultipleSelections
)
1962 for (size_t r
=0; r
<sel
.Count(); r
++) {
1963 if (!sel
.Range(r
).Empty()) {
1964 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1965 sel
.Range(r
).End().Position())) {
1966 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
1967 sel
.Range(r
).Length());
1968 sel
.Range(r
) = SelectionRange(sel
.Range(r
).Start());
1972 ThinRectangularRange();
1973 sel
.RemoveDuplicates();
1975 SetHoverIndicatorPosition(sel
.MainCaret());
1978 void Editor::ClearAll() {
1981 if (0 != pdoc
->Length()) {
1982 pdoc
->DeleteChars(0, pdoc
->Length());
1984 if (!pdoc
->IsReadOnly()) {
1986 pdoc
->AnnotationClearAll();
1987 pdoc
->MarginClearAll();
1991 view
.ClearAllTabstops();
1995 SetVerticalScrollPos();
1996 InvalidateStyleRedraw();
1999 void Editor::ClearDocumentStyle() {
2000 Decoration
*deco
= pdoc
->decorations
.root
;
2002 // Save next in case deco deleted
2003 Decoration
*decoNext
= deco
->next
;
2004 if (deco
->indicator
< INDIC_CONTAINER
) {
2005 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
2006 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
2010 pdoc
->StartStyling(0, '\377');
2011 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2013 SetAnnotationHeights(0, pdoc
->LinesTotal());
2014 pdoc
->ClearLevels();
2017 void Editor::CopyAllowLine() {
2018 SelectionText selectedText
;
2019 CopySelectionRange(&selectedText
, true);
2020 CopyToClipboard(selectedText
);
2023 void Editor::Cut() {
2024 pdoc
->CheckReadOnly();
2025 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2031 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
2032 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2036 sel
.RangeMain() = SelectionRange(pos
);
2037 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2039 sel
.RangeMain().caret
= SelectionPosition(
2040 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
2041 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
2042 bool prevCr
= false;
2043 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
2045 for (int i
= 0; i
< len
; i
++) {
2046 if (IsEOLChar(ptr
[i
])) {
2047 if ((ptr
[i
] == '\r') || (!prevCr
))
2049 if (line
>= pdoc
->LinesTotal()) {
2050 if (pdoc
->eolMode
!= SC_EOL_LF
)
2051 pdoc
->InsertString(pdoc
->Length(), "\r", 1);
2052 if (pdoc
->eolMode
!= SC_EOL_CR
)
2053 pdoc
->InsertString(pdoc
->Length(), "\n", 1);
2055 // Pad the end of lines with spaces if required
2056 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
2057 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
2058 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
2060 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), " ", 1);
2061 sel
.RangeMain().caret
.Add(lengthInserted
);
2064 prevCr
= ptr
[i
] == '\r';
2066 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
2067 sel
.RangeMain().caret
.Add(lengthInserted
);
2071 SetEmptySelection(pos
);
2074 bool Editor::CanPaste() {
2075 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
2078 void Editor::Clear() {
2079 // If multiple selections, don't delete EOLS
2081 bool singleVirtual
= false;
2082 if ((sel
.Count() == 1) &&
2083 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
2084 sel
.RangeMain().Start().VirtualSpace()) {
2085 singleVirtual
= true;
2087 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
2088 for (size_t r
=0; r
<sel
.Count(); r
++) {
2089 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
2090 if (sel
.Range(r
).Start().VirtualSpace()) {
2091 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
2092 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
2094 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
2096 if ((sel
.Count() == 1) || !pdoc
->IsPositionInLineEnd(sel
.Range(r
).caret
.Position())) {
2097 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
2098 sel
.Range(r
).ClearVirtualSpace();
2099 } // else multiple selection so don't eat line ends
2101 sel
.Range(r
).ClearVirtualSpace();
2107 sel
.RemoveDuplicates();
2108 ShowCaretAtCurrentPosition(); // Avoid blinking
2111 void Editor::SelectAll() {
2113 SetSelection(0, pdoc
->Length());
2117 void Editor::Undo() {
2118 if (pdoc
->CanUndo()) {
2120 int newPos
= pdoc
->Undo();
2122 SetEmptySelection(newPos
);
2123 EnsureCaretVisible();
2127 void Editor::Redo() {
2128 if (pdoc
->CanRedo()) {
2129 int newPos
= pdoc
->Redo();
2131 SetEmptySelection(newPos
);
2132 EnsureCaretVisible();
2136 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2138 if (!sel
.IsRectangular())
2140 if (sel
.IsRectangular())
2141 allowLineStartDeletion
= false;
2142 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
2144 for (size_t r
=0; r
<sel
.Count(); r
++) {
2145 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
2146 if (sel
.Range(r
).caret
.VirtualSpace()) {
2147 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
2148 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
2150 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2151 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
2152 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2153 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
2154 UndoGroup
ugInner(pdoc
, !ug
.Needed());
2155 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2156 int indentationStep
= pdoc
->IndentSize();
2157 int indentationChange
= indentation
% indentationStep
;
2158 if (indentationChange
== 0)
2159 indentationChange
= indentationStep
;
2160 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationChange
);
2161 // SetEmptySelection
2162 sel
.Range(r
) = SelectionRange(posSelect
);
2164 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
2169 sel
.Range(r
).ClearVirtualSpace();
2172 ThinRectangularRange();
2176 sel
.RemoveDuplicates();
2177 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
2178 // Avoid blinking during rapid typing:
2179 ShowCaretAtCurrentPosition();
2182 int Editor::ModifierFlags(bool shift
, bool ctrl
, bool alt
, bool meta
) {
2184 (shift
? SCI_SHIFT
: 0) |
2185 (ctrl
? SCI_CTRL
: 0) |
2186 (alt
? SCI_ALT
: 0) |
2187 (meta
? SCI_META
: 0);
2190 void Editor::NotifyFocus(bool focus
) {
2191 SCNotification scn
= {};
2192 scn
.nmhdr
.code
= focus
? SCN_FOCUSIN
: SCN_FOCUSOUT
;
2196 void Editor::SetCtrlID(int identifier
) {
2197 ctrlID
= identifier
;
2200 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2201 SCNotification scn
= {};
2202 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2203 scn
.position
= endStyleNeeded
;
2207 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2208 NotifyStyleToNeeded(endStyleNeeded
);
2211 void Editor::NotifyLexerChanged(Document
*, void *) {
2214 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
2215 errorStatus
= status
;
2218 void Editor::NotifyChar(int ch
) {
2219 SCNotification scn
= {};
2220 scn
.nmhdr
.code
= SCN_CHARADDED
;
2225 void Editor::NotifySavePoint(bool isSavePoint
) {
2226 SCNotification scn
= {};
2228 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2230 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2235 void Editor::NotifyModifyAttempt() {
2236 SCNotification scn
= {};
2237 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2241 void Editor::NotifyDoubleClick(Point pt
, int modifiers
) {
2242 SCNotification scn
= {};
2243 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2244 scn
.line
= LineFromLocation(pt
);
2245 scn
.position
= PositionFromLocation(pt
, true);
2246 scn
.modifiers
= modifiers
;
2250 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2251 NotifyDoubleClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2254 void Editor::NotifyHotSpotDoubleClicked(int position
, int modifiers
) {
2255 SCNotification scn
= {};
2256 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
2257 scn
.position
= position
;
2258 scn
.modifiers
= modifiers
;
2262 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2263 NotifyHotSpotDoubleClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2266 void Editor::NotifyHotSpotClicked(int position
, int modifiers
) {
2267 SCNotification scn
= {};
2268 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
2269 scn
.position
= position
;
2270 scn
.modifiers
= modifiers
;
2274 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2275 NotifyHotSpotClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2278 void Editor::NotifyHotSpotReleaseClick(int position
, int modifiers
) {
2279 SCNotification scn
= {};
2280 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
2281 scn
.position
= position
;
2282 scn
.modifiers
= modifiers
;
2286 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
2287 NotifyHotSpotReleaseClick(position
, ModifierFlags(shift
, ctrl
, alt
));
2290 bool Editor::NotifyUpdateUI() {
2292 SCNotification scn
= {};
2293 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2294 scn
.updated
= needUpdateUI
;
2302 void Editor::NotifyPainted() {
2303 SCNotification scn
= {};
2304 scn
.nmhdr
.code
= SCN_PAINTED
;
2308 void Editor::NotifyIndicatorClick(bool click
, int position
, int modifiers
) {
2309 int mask
= pdoc
->decorations
.AllOnFor(position
);
2310 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
2311 SCNotification scn
= {};
2312 pdoc
->decorations
.clickNotified
= click
;
2313 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
2314 scn
.modifiers
= modifiers
;
2315 scn
.position
= position
;
2320 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
2321 NotifyIndicatorClick(click
, position
, ModifierFlags(shift
, ctrl
, alt
));
2324 bool Editor::NotifyMarginClick(Point pt
, int modifiers
) {
2325 int marginClicked
= -1;
2326 int x
= vs
.textStart
- vs
.fixedColumnWidth
;
2327 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
2328 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2329 marginClicked
= margin
;
2330 x
+= vs
.ms
[margin
].width
;
2332 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2333 int position
= pdoc
->LineStart(LineFromLocation(pt
));
2334 if ((vs
.ms
[marginClicked
].mask
& SC_MASK_FOLDERS
) && (foldAutomatic
& SC_AUTOMATICFOLD_CLICK
)) {
2335 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
2336 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
2337 int lineClick
= pdoc
->LineFromPosition(position
);
2338 if (shift
&& ctrl
) {
2339 FoldAll(SC_FOLDACTION_TOGGLE
);
2341 int levelClick
= pdoc
->GetLevel(lineClick
);
2342 if (levelClick
& SC_FOLDLEVELHEADERFLAG
) {
2344 // Ensure all children visible
2345 FoldExpand(lineClick
, SC_FOLDACTION_EXPAND
, levelClick
);
2347 FoldExpand(lineClick
, SC_FOLDACTION_TOGGLE
, levelClick
);
2350 FoldLine(lineClick
, SC_FOLDACTION_TOGGLE
);
2356 SCNotification scn
= {};
2357 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2358 scn
.modifiers
= modifiers
;
2359 scn
.position
= position
;
2360 scn
.margin
= marginClicked
;
2368 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2369 return NotifyMarginClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2372 void Editor::NotifyNeedShown(int pos
, int len
) {
2373 SCNotification scn
= {};
2374 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2380 void Editor::NotifyDwelling(Point pt
, bool state
) {
2381 SCNotification scn
= {};
2382 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2383 scn
.position
= PositionFromLocation(pt
, true);
2384 scn
.x
= static_cast<int>(pt
.x
+ vs
.ExternalMarginWidth());
2385 scn
.y
= static_cast<int>(pt
.y
);
2389 void Editor::NotifyZoom() {
2390 SCNotification scn
= {};
2391 scn
.nmhdr
.code
= SCN_ZOOM
;
2395 // Notifications from document
2396 void Editor::NotifyModifyAttempt(Document
*, void *) {
2397 //Platform::DebugPrintf("** Modify Attempt\n");
2398 NotifyModifyAttempt();
2401 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2402 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2403 NotifySavePoint(atSavePoint
);
2406 void Editor::CheckModificationForWrap(DocModification mh
) {
2407 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
2408 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2409 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2410 int lines
= Platform::Maximum(0, mh
.linesAdded
);
2412 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
2415 // Fix up annotation heights
2416 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
2420 // Move a position so it is still after the same character as before the insertion.
2421 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2422 if (position
> startInsertion
) {
2423 return position
+ length
;
2428 // Move a position so it is still after the same character as before the deletion if that
2429 // character is still present else after the previous surviving character.
2430 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2431 if (position
> startDeletion
) {
2432 int endDeletion
= startDeletion
+ length
;
2433 if (position
> endDeletion
) {
2434 return position
- length
;
2436 return startDeletion
;
2443 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2444 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
2445 if (paintState
== painting
) {
2446 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2448 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
2449 if (paintState
== painting
) {
2450 CheckForChangeOutsidePaint(
2451 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
2453 // Could check that change is before last visible line.
2457 if (mh
.modificationType
& SC_MOD_CHANGETABSTOPS
) {
2460 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
2461 if (paintState
== painting
) {
2462 CheckForChangeOutsidePaint(
2463 Range(mh
.position
, mh
.position
+ mh
.length
));
2468 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
2469 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2470 pdoc
->IncrementStyleClock();
2472 if (paintState
== notPainting
) {
2473 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2474 // Styling performed before this view
2477 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2480 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2481 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2484 // Move selection and brace highlights
2485 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2486 sel
.MovePositions(true, mh
.position
, mh
.length
);
2487 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2488 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2489 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2490 sel
.MovePositions(false, mh
.position
, mh
.length
);
2491 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2492 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2494 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
2495 // Some lines are hidden so may need shown.
2496 // TODO: check if the modified area is hidden.
2497 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2498 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2499 bool insertingNewLine
= false;
2500 for (int i
=0; i
< mh
.length
; i
++) {
2501 if ((mh
.text
[i
] == '\n') || (mh
.text
[i
] == '\r'))
2502 insertingNewLine
= true;
2504 if (insertingNewLine
&& (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
2505 NeedShown(mh
.position
, pdoc
->LineStart(lineOfPos
+1) - mh
.position
);
2507 NeedShown(mh
.position
, 0);
2508 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2509 NeedShown(mh
.position
, mh
.length
);
2512 if (mh
.linesAdded
!= 0) {
2513 // Update contraction state for inserted and removed lines
2514 // lineOfPos should be calculated in context of state before modification, shouldn't it
2515 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2516 if (mh
.position
> pdoc
->LineStart(lineOfPos
))
2517 lineOfPos
++; // Affecting subsequent lines
2518 if (mh
.linesAdded
> 0) {
2519 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2521 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2523 view
.LinesAddedOrRemoved(lineOfPos
, mh
.linesAdded
);
2525 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
2526 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2527 if (vs
.annotationVisible
) {
2528 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
2532 CheckModificationForWrap(mh
);
2533 if (mh
.linesAdded
!= 0) {
2534 // Avoid scrolling of display if change before current display
2535 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
2536 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2537 if (newTop
!= topLine
) {
2539 SetVerticalScrollPos();
2543 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
2544 QueueIdleWork(WorkNeeded::workStyle
, pdoc
->Length());
2548 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
2549 QueueIdleWork(WorkNeeded::workStyle
, mh
.position
+ mh
.length
);
2550 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2555 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
2559 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
2560 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
2561 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
2562 // Fold changes can affect the drawing of following lines so redraw whole margin
2563 RedrawSelMargin(marginView
.highlightDelimiter
.isEnabled
? -1 : mh
.line
- 1, true);
2565 RedrawSelMargin(mh
.line
);
2569 if ((mh
.modificationType
& SC_MOD_CHANGEFOLD
) && (foldAutomatic
& SC_AUTOMATICFOLD_CHANGE
)) {
2570 FoldChanged(mh
.line
, mh
.foldLevelNow
, mh
.foldLevelPrev
);
2573 // NOW pay the piper WRT "deferred" visual updates
2574 if (IsLastStep(mh
)) {
2579 // If client wants to see this modification
2580 if (mh
.modificationType
& modEventMask
) {
2581 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
2582 // Real modification made to text of document.
2583 NotifyChange(); // Send EN_CHANGE
2586 SCNotification scn
= {};
2587 scn
.nmhdr
.code
= SCN_MODIFIED
;
2588 scn
.position
= mh
.position
;
2589 scn
.modificationType
= mh
.modificationType
;
2591 scn
.length
= mh
.length
;
2592 scn
.linesAdded
= mh
.linesAdded
;
2594 scn
.foldLevelNow
= mh
.foldLevelNow
;
2595 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2596 scn
.token
= mh
.token
;
2597 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
2602 void Editor::NotifyDeleted(Document
*, void *) {
2606 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2608 // Enumerates all macroable messages
2614 case SCI_REPLACESEL
:
2616 case SCI_INSERTTEXT
:
2617 case SCI_APPENDTEXT
:
2622 case SCI_SEARCHANCHOR
:
2623 case SCI_SEARCHNEXT
:
2624 case SCI_SEARCHPREV
:
2626 case SCI_LINEDOWNEXTEND
:
2628 case SCI_PARADOWNEXTEND
:
2630 case SCI_LINEUPEXTEND
:
2632 case SCI_PARAUPEXTEND
:
2634 case SCI_CHARLEFTEXTEND
:
2636 case SCI_CHARRIGHTEXTEND
:
2638 case SCI_WORDLEFTEXTEND
:
2640 case SCI_WORDRIGHTEXTEND
:
2641 case SCI_WORDPARTLEFT
:
2642 case SCI_WORDPARTLEFTEXTEND
:
2643 case SCI_WORDPARTRIGHT
:
2644 case SCI_WORDPARTRIGHTEXTEND
:
2645 case SCI_WORDLEFTEND
:
2646 case SCI_WORDLEFTENDEXTEND
:
2647 case SCI_WORDRIGHTEND
:
2648 case SCI_WORDRIGHTENDEXTEND
:
2650 case SCI_HOMEEXTEND
:
2652 case SCI_LINEENDEXTEND
:
2654 case SCI_HOMEWRAPEXTEND
:
2655 case SCI_LINEENDWRAP
:
2656 case SCI_LINEENDWRAPEXTEND
:
2657 case SCI_DOCUMENTSTART
:
2658 case SCI_DOCUMENTSTARTEXTEND
:
2659 case SCI_DOCUMENTEND
:
2660 case SCI_DOCUMENTENDEXTEND
:
2661 case SCI_STUTTEREDPAGEUP
:
2662 case SCI_STUTTEREDPAGEUPEXTEND
:
2663 case SCI_STUTTEREDPAGEDOWN
:
2664 case SCI_STUTTEREDPAGEDOWNEXTEND
:
2666 case SCI_PAGEUPEXTEND
:
2668 case SCI_PAGEDOWNEXTEND
:
2669 case SCI_EDITTOGGLEOVERTYPE
:
2671 case SCI_DELETEBACK
:
2676 case SCI_VCHOMEEXTEND
:
2677 case SCI_VCHOMEWRAP
:
2678 case SCI_VCHOMEWRAPEXTEND
:
2679 case SCI_VCHOMEDISPLAY
:
2680 case SCI_VCHOMEDISPLAYEXTEND
:
2681 case SCI_DELWORDLEFT
:
2682 case SCI_DELWORDRIGHT
:
2683 case SCI_DELWORDRIGHTEND
:
2684 case SCI_DELLINELEFT
:
2685 case SCI_DELLINERIGHT
:
2688 case SCI_LINEDELETE
:
2689 case SCI_LINETRANSPOSE
:
2690 case SCI_LINEDUPLICATE
:
2693 case SCI_LINESCROLLDOWN
:
2694 case SCI_LINESCROLLUP
:
2695 case SCI_DELETEBACKNOTLINE
:
2696 case SCI_HOMEDISPLAY
:
2697 case SCI_HOMEDISPLAYEXTEND
:
2698 case SCI_LINEENDDISPLAY
:
2699 case SCI_LINEENDDISPLAYEXTEND
:
2700 case SCI_SETSELECTIONMODE
:
2701 case SCI_LINEDOWNRECTEXTEND
:
2702 case SCI_LINEUPRECTEXTEND
:
2703 case SCI_CHARLEFTRECTEXTEND
:
2704 case SCI_CHARRIGHTRECTEXTEND
:
2705 case SCI_HOMERECTEXTEND
:
2706 case SCI_VCHOMERECTEXTEND
:
2707 case SCI_LINEENDRECTEXTEND
:
2708 case SCI_PAGEUPRECTEXTEND
:
2709 case SCI_PAGEDOWNRECTEXTEND
:
2710 case SCI_SELECTIONDUPLICATE
:
2711 case SCI_COPYALLOWLINE
:
2712 case SCI_VERTICALCENTRECARET
:
2713 case SCI_MOVESELECTEDLINESUP
:
2714 case SCI_MOVESELECTEDLINESDOWN
:
2715 case SCI_SCROLLTOSTART
:
2716 case SCI_SCROLLTOEND
:
2719 // Filter out all others like display changes. Also, newlines are redundant
2720 // with char insert messages.
2723 // printf("Filtered out %ld of macro recording\n", iMessage);
2727 // Send notification
2728 SCNotification scn
= {};
2729 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2730 scn
.message
= iMessage
;
2731 scn
.wParam
= wParam
;
2732 scn
.lParam
= lParam
;
2736 // Something has changed that the container should know about
2737 void Editor::ContainerNeedsUpdate(int flags
) {
2738 needUpdateUI
|= flags
;
2742 * Force scroll and keep position relative to top of window.
2744 * If stuttered = true and not already at first/last row, move to first/last row of window.
2745 * If stuttered = true and already at first/last row, scroll as normal.
2747 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
2749 SelectionPosition newPos
;
2751 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
2752 int topStutterLine
= topLine
+ caretYSlop
;
2753 int bottomStutterLine
=
2754 pdoc
->LineFromPosition(PositionFromLocation(
2755 Point::FromInts(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
2758 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
2759 topLineNew
= topLine
;
2760 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
2761 false, false, UserVirtualSpace());
2763 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
2764 topLineNew
= topLine
;
2765 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
2766 false, false, UserVirtualSpace());
2769 Point pt
= LocationFromPosition(sel
.MainCaret());
2771 topLineNew
= Platform::Clamp(
2772 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2773 newPos
= SPositionFromLocation(
2774 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(pt
.y
) + direction
* (vs
.lineHeight
* LinesToScroll())),
2775 false, false, UserVirtualSpace());
2778 if (topLineNew
!= topLine
) {
2779 SetTopLine(topLineNew
);
2780 MovePositionTo(newPos
, selt
);
2782 SetVerticalScrollPos();
2784 MovePositionTo(newPos
, selt
);
2788 void Editor::ChangeCaseOfSelection(int caseMapping
) {
2790 for (size_t r
=0; r
<sel
.Count(); r
++) {
2791 SelectionRange current
= sel
.Range(r
);
2792 SelectionRange currentNoVS
= current
;
2793 currentNoVS
.ClearVirtualSpace();
2794 size_t rangeBytes
= currentNoVS
.Length();
2795 if (rangeBytes
> 0) {
2796 std::string sText
= RangeText(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
2798 std::string sMapped
= CaseMapString(sText
, caseMapping
);
2800 if (sMapped
!= sText
) {
2801 size_t firstDifference
= 0;
2802 while (sMapped
[firstDifference
] == sText
[firstDifference
])
2804 size_t lastDifferenceText
= sText
.size() - 1;
2805 size_t lastDifferenceMapped
= sMapped
.size() - 1;
2806 while (sMapped
[lastDifferenceMapped
] == sText
[lastDifferenceText
]) {
2807 lastDifferenceText
--;
2808 lastDifferenceMapped
--;
2810 size_t endDifferenceText
= sText
.size() - 1 - lastDifferenceText
;
2812 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2813 static_cast<int>(rangeBytes
- firstDifference
- endDifferenceText
));
2814 const int lengthChange
= static_cast<int>(lastDifferenceMapped
- firstDifference
+ 1);
2815 const int lengthInserted
= pdoc
->InsertString(
2816 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2817 sMapped
.c_str() + firstDifference
,
2819 // Automatic movement changes selection so reset to exactly the same as it was.
2820 int diffSizes
= static_cast<int>(sMapped
.size() - sText
.size()) + lengthInserted
- lengthChange
;
2821 if (diffSizes
!= 0) {
2822 if (current
.anchor
> current
.caret
)
2823 current
.anchor
.Add(diffSizes
);
2825 current
.caret
.Add(diffSizes
);
2827 sel
.Range(r
) = current
;
2833 void Editor::LineTranspose() {
2834 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2838 const int startPrevious
= pdoc
->LineStart(line
- 1);
2839 const std::string linePrevious
= RangeText(startPrevious
, pdoc
->LineEnd(line
- 1));
2841 int startCurrent
= pdoc
->LineStart(line
);
2842 const std::string lineCurrent
= RangeText(startCurrent
, pdoc
->LineEnd(line
));
2844 pdoc
->DeleteChars(startCurrent
, static_cast<int>(lineCurrent
.length()));
2845 pdoc
->DeleteChars(startPrevious
, static_cast<int>(linePrevious
.length()));
2846 startCurrent
-= static_cast<int>(linePrevious
.length());
2848 startCurrent
+= pdoc
->InsertString(startPrevious
, lineCurrent
.c_str(),
2849 static_cast<int>(lineCurrent
.length()));
2850 pdoc
->InsertString(startCurrent
, linePrevious
.c_str(),
2851 static_cast<int>(linePrevious
.length()));
2852 // Move caret to start of current line
2853 MovePositionTo(SelectionPosition(startCurrent
));
2857 void Editor::Duplicate(bool forLine
) {
2862 const char *eol
= "";
2865 eol
= StringFromEOLMode(pdoc
->eolMode
);
2866 eolLen
= istrlen(eol
);
2868 for (size_t r
=0; r
<sel
.Count(); r
++) {
2869 SelectionPosition start
= sel
.Range(r
).Start();
2870 SelectionPosition end
= sel
.Range(r
).End();
2872 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2873 start
= SelectionPosition(pdoc
->LineStart(line
));
2874 end
= SelectionPosition(pdoc
->LineEnd(line
));
2876 std::string text
= RangeText(start
.Position(), end
.Position());
2877 int lengthInserted
= eolLen
;
2879 lengthInserted
= pdoc
->InsertString(end
.Position(), eol
, eolLen
);
2880 pdoc
->InsertString(end
.Position() + lengthInserted
, text
.c_str(), static_cast<int>(text
.length()));
2882 if (sel
.Count() && sel
.IsRectangular()) {
2883 SelectionPosition last
= sel
.Last();
2885 int line
= pdoc
->LineFromPosition(last
.Position());
2886 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
2888 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
2889 sel
.Rectangular().anchor
= last
;
2891 sel
.Rectangular().caret
= last
;
2892 SetRectangularRange();
2896 void Editor::CancelModes() {
2897 sel
.SetMoveExtends(false);
2900 void Editor::NewLine() {
2901 // Remove non-main ranges
2902 InvalidateSelection(sel
.RangeMain(), true);
2903 sel
.SetSelection(sel
.RangeMain());
2904 sel
.RangeMain().ClearVirtualSpace();
2906 // Clear main range and insert line end
2907 bool needGroupUndo
= !sel
.Empty();
2909 pdoc
->BeginUndoAction();
2913 const char *eol
= "\n";
2914 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
2916 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
2918 } // else SC_EOL_LF -> "\n" already set
2919 const int insertLength
= pdoc
->InsertString(sel
.MainCaret(), eol
, istrlen(eol
));
2920 // Want to end undo group before NotifyChar as applications often modify text here
2922 pdoc
->EndUndoAction();
2923 if (insertLength
> 0) {
2924 SetEmptySelection(sel
.MainCaret() + insertLength
);
2927 if (recordingMacro
) {
2931 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
2938 EnsureCaretVisible();
2939 // Avoid blinking during rapid typing:
2940 ShowCaretAtCurrentPosition();
2943 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
2944 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
2945 if (sel
.IsRectangular()) {
2946 if (selt
== Selection::noSel
) {
2947 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
2949 caretToUse
= sel
.Rectangular().caret
;
2953 Point pt
= LocationFromPosition(caretToUse
);
2956 if (vs
.annotationVisible
) {
2957 int lineDoc
= pdoc
->LineFromPosition(caretToUse
.Position());
2958 Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
2959 int subLine
= static_cast<int>(pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
2961 if (direction
< 0 && subLine
== 0) {
2962 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
2963 if (lineDisplay
> 0) {
2964 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
2966 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
2967 skipLines
= pdoc
->AnnotationLines(lineDoc
);
2971 int newY
= static_cast<int>(pt
.y
) + (1 + skipLines
) * direction
* vs
.lineHeight
;
2972 SelectionPosition posNew
= SPositionFromLocation(
2973 Point::FromInts(lastXChosen
- xOffset
, newY
), false, false, UserVirtualSpace());
2975 if (direction
< 0) {
2976 // Line wrapping may lead to a location on the same line, so
2977 // seek back if that is the case.
2978 Point ptNew
= LocationFromPosition(posNew
.Position());
2979 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
2981 posNew
.SetVirtualSpace(0);
2982 ptNew
= LocationFromPosition(posNew
.Position());
2984 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
2985 // There is an equivalent case when moving down which skips
2987 Point ptNew
= LocationFromPosition(posNew
.Position());
2988 while ((posNew
.Position() > caretToUse
.Position()) && (ptNew
.y
> newY
)) {
2990 posNew
.SetVirtualSpace(0);
2991 ptNew
= LocationFromPosition(posNew
.Position());
2995 MovePositionTo(MovePositionSoVisible(posNew
, direction
), selt
);
2998 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
2999 int lineDoc
, savedPos
= sel
.MainCaret();
3001 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
3002 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
3003 if (direction
> 0) {
3004 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
3005 if (selt
== Selection::noSel
) {
3006 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
3011 } while (!cs
.GetVisible(lineDoc
));
3014 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3016 AutoSurface
surface(this);
3017 int posRet
= view
.StartEndDisplayLine(surface
, *this, pos
, start
, vs
);
3018 if (posRet
== INVALID_POSITION
) {
3025 int Editor::KeyCommand(unsigned int iMessage
) {
3030 case SCI_LINEDOWNEXTEND
:
3031 CursorUpOrDown(1, Selection::selStream
);
3033 case SCI_LINEDOWNRECTEXTEND
:
3034 CursorUpOrDown(1, Selection::selRectangle
);
3039 case SCI_PARADOWNEXTEND
:
3040 ParaUpOrDown(1, Selection::selStream
);
3042 case SCI_LINESCROLLDOWN
:
3043 ScrollTo(topLine
+ 1);
3044 MoveCaretInsideView(false);
3049 case SCI_LINEUPEXTEND
:
3050 CursorUpOrDown(-1, Selection::selStream
);
3052 case SCI_LINEUPRECTEXTEND
:
3053 CursorUpOrDown(-1, Selection::selRectangle
);
3058 case SCI_PARAUPEXTEND
:
3059 ParaUpOrDown(-1, Selection::selStream
);
3061 case SCI_LINESCROLLUP
:
3062 ScrollTo(topLine
- 1);
3063 MoveCaretInsideView(false);
3066 if (SelectionEmpty() || sel
.MoveExtends()) {
3067 if ((sel
.Count() == 1) && pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3068 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3069 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3070 MovePositionTo(spCaret
);
3071 } else if (sel
.MoveExtends() && sel
.selType
== Selection::selStream
) {
3072 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1));
3074 MovePositionTo(MovePositionSoVisible(
3075 SelectionPosition((sel
.LimitsForRectangularElseMain().start
).Position() - 1), -1));
3078 MovePositionTo(sel
.LimitsForRectangularElseMain().start
);
3082 case SCI_CHARLEFTEXTEND
:
3083 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3084 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3085 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3086 MovePositionTo(spCaret
, Selection::selStream
);
3088 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selStream
);
3092 case SCI_CHARLEFTRECTEXTEND
:
3093 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3094 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3095 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3096 MovePositionTo(spCaret
, Selection::selRectangle
);
3098 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selRectangle
);
3103 if (SelectionEmpty() || sel
.MoveExtends()) {
3104 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3105 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3106 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3107 MovePositionTo(spCaret
);
3108 } else if (sel
.MoveExtends() && sel
.selType
== Selection::selStream
) {
3109 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1));
3111 MovePositionTo(MovePositionSoVisible(
3112 SelectionPosition((sel
.LimitsForRectangularElseMain().end
).Position() + 1), 1));
3115 MovePositionTo(sel
.LimitsForRectangularElseMain().end
);
3119 case SCI_CHARRIGHTEXTEND
:
3120 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3121 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3122 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3123 MovePositionTo(spCaret
, Selection::selStream
);
3125 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selStream
);
3129 case SCI_CHARRIGHTRECTEXTEND
:
3130 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3131 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3132 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3133 MovePositionTo(spCaret
, Selection::selRectangle
);
3135 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selRectangle
);
3140 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1));
3143 case SCI_WORDLEFTEXTEND
:
3144 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1), Selection::selStream
);
3148 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1));
3151 case SCI_WORDRIGHTEXTEND
:
3152 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1), Selection::selStream
);
3156 case SCI_WORDLEFTEND
:
3157 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1));
3160 case SCI_WORDLEFTENDEXTEND
:
3161 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1), Selection::selStream
);
3164 case SCI_WORDRIGHTEND
:
3165 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1));
3168 case SCI_WORDRIGHTENDEXTEND
:
3169 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1), Selection::selStream
);
3174 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3177 case SCI_HOMEEXTEND
:
3178 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selStream
);
3181 case SCI_HOMERECTEXTEND
:
3182 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selRectangle
);
3186 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()));
3189 case SCI_LINEENDEXTEND
:
3190 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selStream
);
3193 case SCI_LINEENDRECTEXTEND
:
3194 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selRectangle
);
3197 case SCI_HOMEWRAP
: {
3198 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3199 if (sel
.RangeMain().caret
<= homePos
)
3200 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3201 MovePositionTo(homePos
);
3205 case SCI_HOMEWRAPEXTEND
: {
3206 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3207 if (sel
.RangeMain().caret
<= homePos
)
3208 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3209 MovePositionTo(homePos
, Selection::selStream
);
3213 case SCI_LINEENDWRAP
: {
3214 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
3215 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
3216 if (endPos
> realEndPos
// if moved past visible EOLs
3217 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
3218 endPos
= realEndPos
;
3219 MovePositionTo(endPos
);
3223 case SCI_LINEENDWRAPEXTEND
: {
3224 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
3225 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
3226 if (endPos
> realEndPos
// if moved past visible EOLs
3227 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
3228 endPos
= realEndPos
;
3229 MovePositionTo(endPos
, Selection::selStream
);
3233 case SCI_DOCUMENTSTART
:
3237 case SCI_DOCUMENTSTARTEXTEND
:
3238 MovePositionTo(0, Selection::selStream
);
3241 case SCI_DOCUMENTEND
:
3242 MovePositionTo(pdoc
->Length());
3245 case SCI_DOCUMENTENDEXTEND
:
3246 MovePositionTo(pdoc
->Length(), Selection::selStream
);
3249 case SCI_STUTTEREDPAGEUP
:
3250 PageMove(-1, Selection::noSel
, true);
3252 case SCI_STUTTEREDPAGEUPEXTEND
:
3253 PageMove(-1, Selection::selStream
, true);
3255 case SCI_STUTTEREDPAGEDOWN
:
3256 PageMove(1, Selection::noSel
, true);
3258 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3259 PageMove(1, Selection::selStream
, true);
3264 case SCI_PAGEUPEXTEND
:
3265 PageMove(-1, Selection::selStream
);
3267 case SCI_PAGEUPRECTEXTEND
:
3268 PageMove(-1, Selection::selRectangle
);
3273 case SCI_PAGEDOWNEXTEND
:
3274 PageMove(1, Selection::selStream
);
3276 case SCI_PAGEDOWNRECTEXTEND
:
3277 PageMove(1, Selection::selRectangle
);
3279 case SCI_EDITTOGGLEOVERTYPE
:
3280 inOverstrike
= !inOverstrike
;
3281 ShowCaretAtCurrentPosition();
3282 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
3285 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3286 // Also unselect text
3289 case SCI_DELETEBACK
:
3291 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3294 EnsureCaretVisible();
3296 case SCI_DELETEBACKNOTLINE
:
3298 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3301 EnsureCaretVisible();
3305 if (caretSticky
== SC_CARETSTICKY_OFF
) {
3308 EnsureCaretVisible();
3309 ShowCaretAtCurrentPosition(); // Avoid blinking
3313 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3316 EnsureCaretVisible();
3317 ShowCaretAtCurrentPosition(); // Avoid blinking
3326 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()));
3329 case SCI_VCHOMEEXTEND
:
3330 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selStream
);
3333 case SCI_VCHOMERECTEXTEND
:
3334 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selRectangle
);
3337 case SCI_VCHOMEWRAP
: {
3338 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3339 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3340 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
3341 homePos
= viewLineStart
;
3343 MovePositionTo(homePos
);
3347 case SCI_VCHOMEWRAPEXTEND
: {
3348 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3349 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3350 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
3351 homePos
= viewLineStart
;
3353 MovePositionTo(homePos
, Selection::selStream
);
3358 if (vs
.zoomLevel
< 20) {
3360 InvalidateStyleRedraw();
3365 if (vs
.zoomLevel
> -10) {
3367 InvalidateStyleRedraw();
3371 case SCI_DELWORDLEFT
: {
3372 int startWord
= pdoc
->NextWordStart(sel
.MainCaret(), -1);
3373 pdoc
->DeleteChars(startWord
, sel
.MainCaret() - startWord
);
3374 sel
.RangeMain().ClearVirtualSpace();
3378 case SCI_DELWORDRIGHT
: {
3380 InvalidateSelection(sel
.RangeMain(), true);
3381 sel
.RangeMain().caret
= SelectionPosition(
3382 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
3383 sel
.RangeMain().anchor
= sel
.RangeMain().caret
;
3384 int endWord
= pdoc
->NextWordStart(sel
.MainCaret(), 1);
3385 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
3388 case SCI_DELWORDRIGHTEND
: {
3390 InvalidateSelection(sel
.RangeMain(), true);
3391 sel
.RangeMain().caret
= SelectionPosition(
3392 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
3393 int endWord
= pdoc
->NextWordEnd(sel
.MainCaret(), 1);
3394 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
3397 case SCI_DELLINELEFT
: {
3398 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3399 int start
= pdoc
->LineStart(line
);
3400 pdoc
->DeleteChars(start
, sel
.MainCaret() - start
);
3401 sel
.RangeMain().ClearVirtualSpace();
3405 case SCI_DELLINERIGHT
: {
3406 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3407 int end
= pdoc
->LineEnd(line
);
3408 pdoc
->DeleteChars(sel
.MainCaret(), end
- sel
.MainCaret());
3411 case SCI_LINECOPY
: {
3412 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3413 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3414 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3415 pdoc
->LineStart(lineEnd
+ 1));
3419 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3420 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3421 int start
= pdoc
->LineStart(lineStart
);
3422 int end
= pdoc
->LineStart(lineEnd
+ 1);
3423 SetSelection(start
, end
);
3428 case SCI_LINEDELETE
: {
3429 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3430 int start
= pdoc
->LineStart(line
);
3431 int end
= pdoc
->LineStart(line
+ 1);
3432 pdoc
->DeleteChars(start
, end
- start
);
3435 case SCI_LINETRANSPOSE
:
3438 case SCI_LINEDUPLICATE
:
3441 case SCI_SELECTIONDUPLICATE
:
3445 ChangeCaseOfSelection(cmLower
);
3448 ChangeCaseOfSelection(cmUpper
);
3450 case SCI_WORDPARTLEFT
:
3451 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1));
3454 case SCI_WORDPARTLEFTEXTEND
:
3455 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1), Selection::selStream
);
3458 case SCI_WORDPARTRIGHT
:
3459 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1));
3462 case SCI_WORDPARTRIGHTEXTEND
:
3463 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1), Selection::selStream
);
3466 case SCI_HOMEDISPLAY
:
3467 MovePositionTo(MovePositionSoVisible(
3468 StartEndDisplayLine(sel
.MainCaret(), true), -1));
3471 case SCI_VCHOMEDISPLAY
: {
3472 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3473 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3474 if (viewLineStart
> homePos
)
3475 homePos
= viewLineStart
;
3477 MovePositionTo(homePos
);
3481 case SCI_HOMEDISPLAYEXTEND
:
3482 MovePositionTo(MovePositionSoVisible(
3483 StartEndDisplayLine(sel
.MainCaret(), true), -1), Selection::selStream
);
3486 case SCI_VCHOMEDISPLAYEXTEND
: {
3487 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3488 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3489 if (viewLineStart
> homePos
)
3490 homePos
= viewLineStart
;
3492 MovePositionTo(homePos
, Selection::selStream
);
3496 case SCI_LINEENDDISPLAY
:
3497 MovePositionTo(MovePositionSoVisible(
3498 StartEndDisplayLine(sel
.MainCaret(), false), 1));
3501 case SCI_LINEENDDISPLAYEXTEND
:
3502 MovePositionTo(MovePositionSoVisible(
3503 StartEndDisplayLine(sel
.MainCaret(), false), 1), Selection::selStream
);
3506 case SCI_SCROLLTOSTART
:
3509 case SCI_SCROLLTOEND
:
3510 ScrollTo(MaxScrollPos());
3516 int Editor::KeyDefault(int, int) {
3520 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
3522 int msg
= kmap
.Find(key
, modifiers
);
3526 return static_cast<int>(WndProc(msg
, 0, 0));
3530 return KeyDefault(key
, modifiers
);
3534 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3535 return KeyDownWithModifiers(key
, ModifierFlags(shift
, ctrl
, alt
), consumed
);
3538 void Editor::Indent(bool forwards
) {
3540 for (size_t r
=0; r
<sel
.Count(); r
++) {
3541 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
3542 int caretPosition
= sel
.Range(r
).caret
.Position();
3543 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
3544 if (lineOfAnchor
== lineCurrentPos
) {
3546 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
3547 caretPosition
= sel
.Range(r
).caret
.Position();
3548 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3550 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3551 int indentationStep
= pdoc
->IndentSize();
3552 const int posSelect
= pdoc
->SetLineIndentation(
3553 lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
3554 sel
.Range(r
) = SelectionRange(posSelect
);
3556 if (pdoc
->useTabs
) {
3557 const int lengthInserted
= pdoc
->InsertString(caretPosition
, "\t", 1);
3558 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3560 int numSpaces
= (pdoc
->tabInChars
) -
3561 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
3563 numSpaces
= pdoc
->tabInChars
;
3564 const std::string
spaceText(numSpaces
, ' ');
3565 const int lengthInserted
= pdoc
->InsertString(caretPosition
, spaceText
.c_str(),
3566 static_cast<int>(spaceText
.length()));
3567 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3571 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3573 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3574 int indentationStep
= pdoc
->IndentSize();
3575 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3576 sel
.Range(r
) = SelectionRange(posSelect
);
3578 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
3582 int newPos
= caretPosition
;
3583 while (pdoc
->GetColumn(newPos
) > newColumn
)
3585 sel
.Range(r
) = SelectionRange(newPos
);
3588 } else { // Multiline
3589 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
3590 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
3591 // Multiple lines selected so indent / dedent
3592 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3593 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3594 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
3595 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3596 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3597 if (lineOfAnchor
< lineCurrentPos
) {
3598 if (currentPosPosOnLine
== 0)
3599 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3601 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3603 if (anchorPosOnLine
== 0)
3604 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3606 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3610 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
3613 class CaseFolderASCII
: public CaseFolderTable
{
3618 ~CaseFolderASCII() {
3623 CaseFolder
*Editor::CaseFolderForEncoding() {
3624 // Simple default that only maps ASCII upper case to lower case.
3625 return new CaseFolderASCII();
3629 * Search of a text in the document, in the given range.
3630 * @return The position of the found text, -1 if not found.
3632 long Editor::FindText(
3633 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3634 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3635 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3637 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
3638 int lengthFound
= istrlen(ft
->lpstrText
);
3639 if (!pdoc
->HasCaseFolder())
3640 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3642 long pos
= pdoc
->FindText(
3643 static_cast<int>(ft
->chrg
.cpMin
),
3644 static_cast<int>(ft
->chrg
.cpMax
),
3646 (wParam
& SCFIND_MATCHCASE
) != 0,
3647 (wParam
& SCFIND_WHOLEWORD
) != 0,
3648 (wParam
& SCFIND_WORDSTART
) != 0,
3649 (wParam
& SCFIND_REGEXP
) != 0,
3650 static_cast<int>(wParam
),
3653 ft
->chrgText
.cpMin
= pos
;
3654 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3656 return static_cast<int>(pos
);
3657 } catch (RegexError
&) {
3658 errorStatus
= SC_STATUS_WARN_REGEX
;
3664 * Relocatable search support : Searches relative to current selection
3665 * point and sets the selection to the found text range with
3669 * Anchor following searches at current selection start: This allows
3670 * multiple incremental interactive searches to be macro recorded
3671 * while still setting the selection to found text so the find/select
3672 * operation is self-contained.
3674 void Editor::SearchAnchor() {
3675 searchAnchor
= SelectionStart().Position();
3679 * Find text from current search anchor: Must call @c SearchAnchor first.
3680 * Used for next text and previous text requests.
3681 * @return The position of the found text, -1 if not found.
3683 long Editor::SearchText(
3684 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3685 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3686 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3687 sptr_t lParam
) { ///< The text to search for.
3689 const char *txt
= reinterpret_cast<char *>(lParam
);
3691 int lengthFound
= istrlen(txt
);
3692 if (!pdoc
->HasCaseFolder())
3693 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3695 if (iMessage
== SCI_SEARCHNEXT
) {
3696 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3697 (wParam
& SCFIND_MATCHCASE
) != 0,
3698 (wParam
& SCFIND_WHOLEWORD
) != 0,
3699 (wParam
& SCFIND_WORDSTART
) != 0,
3700 (wParam
& SCFIND_REGEXP
) != 0,
3701 static_cast<int>(wParam
),
3704 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3705 (wParam
& SCFIND_MATCHCASE
) != 0,
3706 (wParam
& SCFIND_WHOLEWORD
) != 0,
3707 (wParam
& SCFIND_WORDSTART
) != 0,
3708 (wParam
& SCFIND_REGEXP
) != 0,
3709 static_cast<int>(wParam
),
3712 } catch (RegexError
&) {
3713 errorStatus
= SC_STATUS_WARN_REGEX
;
3717 SetSelection(static_cast<int>(pos
), static_cast<int>(pos
+ lengthFound
));
3723 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
3725 for (size_t i
=0; i
<ret
.size(); i
++) {
3726 switch (caseMapping
) {
3728 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
3729 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
3732 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
3733 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
3741 * Search for text in the target range of the document.
3742 * @return The position of the found text, -1 if not found.
3744 long Editor::SearchInTarget(const char *text
, int length
) {
3745 int lengthFound
= length
;
3747 if (!pdoc
->HasCaseFolder())
3748 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3750 long pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
3751 (searchFlags
& SCFIND_MATCHCASE
) != 0,
3752 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
3753 (searchFlags
& SCFIND_WORDSTART
) != 0,
3754 (searchFlags
& SCFIND_REGEXP
) != 0,
3758 targetStart
= static_cast<int>(pos
);
3759 targetEnd
= static_cast<int>(pos
+ lengthFound
);
3762 } catch (RegexError
&) {
3763 errorStatus
= SC_STATUS_WARN_REGEX
;
3768 void Editor::GoToLine(int lineNo
) {
3769 if (lineNo
> pdoc
->LinesTotal())
3770 lineNo
= pdoc
->LinesTotal();
3773 SetEmptySelection(pdoc
->LineStart(lineNo
));
3774 ShowCaretAtCurrentPosition();
3775 EnsureCaretVisible();
3778 static bool Close(Point pt1
, Point pt2
, Point threshold
) {
3779 if (std::abs(pt1
.x
- pt2
.x
) > threshold
.x
)
3781 if (std::abs(pt1
.y
- pt2
.y
) > threshold
.y
)
3786 std::string
Editor::RangeText(int start
, int end
) const {
3788 int len
= end
- start
;
3789 std::string
ret(len
, '\0');
3790 for (int i
= 0; i
< len
; i
++) {
3791 ret
[i
] = pdoc
->CharAt(start
+ i
);
3795 return std::string();
3798 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
3800 if (allowLineCopy
) {
3801 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
3802 int start
= pdoc
->LineStart(currentLine
);
3803 int end
= pdoc
->LineEnd(currentLine
);
3805 std::string text
= RangeText(start
, end
);
3806 if (pdoc
->eolMode
!= SC_EOL_LF
)
3807 text
.push_back('\r');
3808 if (pdoc
->eolMode
!= SC_EOL_CR
)
3809 text
.push_back('\n');
3810 ss
->Copy(text
, pdoc
->dbcsCodePage
,
3811 vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
3815 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
3816 if (sel
.selType
== Selection::selRectangle
)
3817 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
3818 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
3819 SelectionRange current
= rangesInOrder
[r
];
3820 text
.append(RangeText(current
.Start().Position(), current
.End().Position()));
3821 if (sel
.selType
== Selection::selRectangle
) {
3822 if (pdoc
->eolMode
!= SC_EOL_LF
)
3823 text
.push_back('\r');
3824 if (pdoc
->eolMode
!= SC_EOL_CR
)
3825 text
.push_back('\n');
3828 ss
->Copy(text
, pdoc
->dbcsCodePage
,
3829 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
3833 void Editor::CopyRangeToClipboard(int start
, int end
) {
3834 start
= pdoc
->ClampPositionIntoDocument(start
);
3835 end
= pdoc
->ClampPositionIntoDocument(end
);
3836 SelectionText selectedText
;
3837 std::string text
= RangeText(start
, end
);
3838 selectedText
.Copy(text
,
3839 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
3840 CopyToClipboard(selectedText
);
3843 void Editor::CopyText(int length
, const char *text
) {
3844 SelectionText selectedText
;
3845 selectedText
.Copy(std::string(text
, length
),
3846 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
3847 CopyToClipboard(selectedText
);
3850 void Editor::SetDragPosition(SelectionPosition newPos
) {
3851 if (newPos
.Position() >= 0) {
3852 newPos
= MovePositionOutsideChar(newPos
, 1);
3855 if (!(posDrag
== newPos
)) {
3857 if (FineTickerAvailable()) {
3858 FineTickerCancel(tickCaret
);
3859 if ((caret
.active
) && (caret
.period
> 0) && (newPos
.Position() < 0))
3860 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
3870 void Editor::DisplayCursor(Window::Cursor c
) {
3871 if (cursorMode
== SC_CURSORNORMAL
)
3874 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
3877 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
3878 int xMove
= static_cast<int>(ptStart
.x
- ptNow
.x
);
3879 int yMove
= static_cast<int>(ptStart
.y
- ptNow
.y
);
3880 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
3881 return distanceSquared
> 16;
3884 void Editor::StartDrag() {
3885 // Always handled by subclasses
3886 //SetMouseCapture(true);
3887 //DisplayCursor(Window::cursorArrow);
3890 void Editor::DropAt(SelectionPosition position
, const char *value
, size_t lengthValue
, bool moving
, bool rectangular
) {
3891 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
3892 if (inDragDrop
== ddDragging
)
3893 dropWentOutside
= false;
3895 bool positionWasInSelection
= PositionInSelection(position
.Position());
3897 bool positionOnEdgeOfSelection
=
3898 (position
== SelectionStart()) || (position
== SelectionEnd());
3900 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
3901 (positionOnEdgeOfSelection
&& !moving
)) {
3903 SelectionPosition selStart
= SelectionStart();
3904 SelectionPosition selEnd
= SelectionEnd();
3908 SelectionPosition positionAfterDeletion
= position
;
3909 if ((inDragDrop
== ddDragging
) && moving
) {
3910 // Remove dragged out text
3911 if (rectangular
|| sel
.selType
== Selection::selLines
) {
3912 for (size_t r
=0; r
<sel
.Count(); r
++) {
3913 if (position
>= sel
.Range(r
).Start()) {
3914 if (position
> sel
.Range(r
).End()) {
3915 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
3917 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
3922 if (position
> selStart
) {
3923 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
3928 position
= positionAfterDeletion
;
3930 std::string convertedText
= Document::TransformLineEnds(value
, lengthValue
, pdoc
->eolMode
);
3933 PasteRectangular(position
, convertedText
.c_str(), static_cast<int>(convertedText
.length()));
3934 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
3935 SetEmptySelection(position
);
3937 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
3938 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
3939 const int lengthInserted
= pdoc
->InsertString(
3940 position
.Position(), convertedText
.c_str(), static_cast<int>(convertedText
.length()));
3941 if (lengthInserted
> 0) {
3942 SelectionPosition posAfterInsertion
= position
;
3943 posAfterInsertion
.Add(lengthInserted
);
3944 SetSelection(posAfterInsertion
, position
);
3947 } else if (inDragDrop
== ddDragging
) {
3948 SetEmptySelection(position
);
3952 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
3953 DropAt(position
, value
, strlen(value
), moving
, rectangular
);
3957 * @return true if given position is inside the selection,
3959 bool Editor::PositionInSelection(int pos
) {
3960 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
3961 for (size_t r
=0; r
<sel
.Count(); r
++) {
3962 if (sel
.Range(r
).Contains(pos
))
3968 bool Editor::PointInSelection(Point pt
) {
3969 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
3970 Point ptPos
= LocationFromPosition(pos
);
3971 for (size_t r
=0; r
<sel
.Count(); r
++) {
3972 SelectionRange range
= sel
.Range(r
);
3973 if (range
.Contains(pos
)) {
3975 if (pos
== range
.Start()) {
3976 // see if just before selection
3977 if (pt
.x
< ptPos
.x
) {
3981 if (pos
== range
.End()) {
3982 // see if just after selection
3983 if (pt
.x
> ptPos
.x
) {
3994 bool Editor::PointInSelMargin(Point pt
) const {
3995 // Really means: "Point in a margin"
3996 if (vs
.fixedColumnWidth
> 0) { // There is a margin
3997 PRectangle rcSelMargin
= GetClientRectangle();
3998 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.leftMarginWidth
);
3999 rcSelMargin
.left
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.fixedColumnWidth
);
4000 return rcSelMargin
.ContainsWholePixel(pt
);
4006 Window::Cursor
Editor::GetMarginCursor(Point pt
) const {
4008 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
4009 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4010 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
4011 x
+= vs
.ms
[margin
].width
;
4013 return Window::cursorReverseArrow
;
4016 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
4017 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
4018 SetSelection(currentPos_
, anchor_
);
4021 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
4022 int selCurrentPos
, selAnchorPos
;
4024 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
4025 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
4026 if (lineAnchorPos_
< lineCurrentPos_
) {
4027 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
4028 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4029 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4030 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
4031 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4032 } else { // Same line, select it
4033 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4034 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4037 if (lineAnchorPos_
< lineCurrentPos_
) {
4038 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
4039 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4040 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4041 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4042 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
4043 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4044 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
4045 } else { // Same line, select it
4046 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4047 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4048 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4051 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
4054 void Editor::WordSelection(int pos
) {
4055 if (pos
< wordSelectAnchorStartPos
) {
4056 // Extend backward to the word containing pos.
4057 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
4058 // This ensures that a series of empty lines isn't counted as a single "word".
4059 if (!pdoc
->IsLineEndPosition(pos
))
4060 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
4061 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
4062 } else if (pos
> wordSelectAnchorEndPos
) {
4063 // Extend forward to the word containing the character to the left of pos.
4064 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
4065 // This ensures that a series of empty lines isn't counted as a single "word".
4066 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
4067 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
4068 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
4070 // Select only the anchored word
4071 if (pos
>= originalAnchorPos
)
4072 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
4074 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
4078 void Editor::DwellEnd(bool mouseMoved
) {
4080 ticksToDwell
= dwellDelay
;
4082 ticksToDwell
= SC_TIME_FOREVER
;
4083 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4085 NotifyDwelling(ptMouseLast
, dwelling
);
4087 if (FineTickerAvailable()) {
4088 FineTickerCancel(tickDwell
);
4089 if (mouseMoved
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4090 //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
4095 void Editor::MouseLeave() {
4096 SetHotSpotRange(NULL
);
4097 if (!HaveMouseCapture()) {
4098 ptMouseLast
= Point(-1,-1);
4103 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
4104 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
4105 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
4108 void Editor::ButtonDownWithModifiers(Point pt
, unsigned int curTime
, int modifiers
) {
4109 SetHoverIndicatorPoint(pt
);
4110 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
4112 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
4113 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
4114 const bool alt
= (modifiers
& SCI_ALT
) != 0;
4115 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
4116 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4117 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4118 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4119 inDragDrop
= ddNone
;
4120 sel
.SetMoveExtends(false);
4122 if (NotifyMarginClick(pt
, modifiers
))
4125 NotifyIndicatorClick(true, newPos
.Position(), modifiers
);
4127 bool inSelMargin
= PointInSelMargin(pt
);
4128 // In margin ctrl+(double)click should always select everything
4129 if (ctrl
&& inSelMargin
) {
4131 lastClickTime
= curTime
;
4135 if (shift
&& !inSelMargin
) {
4136 SetSelection(newPos
);
4138 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
, doubleClickCloseThreshold
)) {
4139 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4140 SetMouseCapture(true);
4141 if (FineTickerAvailable()) {
4142 FineTickerStart(tickScroll
, 100, 10);
4144 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
4145 SetEmptySelection(newPos
.Position());
4146 bool doubleClick
= false;
4147 // Stop mouse button bounce changing selection type
4148 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4150 // Inside margin selection type should be either selSubLine or selWholeLine.
4151 if (selectionType
== selSubLine
) {
4152 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
4153 // so we switch to selWholeLine in order to select whole line.
4154 selectionType
= selWholeLine
;
4155 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
4156 // If it is neither, reset selection type to line selection.
4157 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4160 if (selectionType
== selChar
) {
4161 selectionType
= selWord
;
4163 } else if (selectionType
== selWord
) {
4164 // Since we ended up here, we're inside a *triple* click, which should always select
4165 // whole line regardless of word wrap being enabled or not.
4166 selectionType
= selWholeLine
;
4168 selectionType
= selChar
;
4169 originalAnchorPos
= sel
.MainCaret();
4174 if (selectionType
== selWord
) {
4175 int charPos
= originalAnchorPos
;
4176 if (sel
.MainCaret() == originalAnchorPos
) {
4177 charPos
= PositionFromLocation(pt
, false, true);
4178 charPos
= MovePositionOutsideChar(charPos
, -1);
4181 int startWord
, endWord
;
4182 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
4183 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
4184 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
4186 // Selecting backwards, or anchor beyond last character on line. In these cases,
4187 // we select the word containing the character to the *left* of the anchor.
4188 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
4189 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
4190 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
4192 // Anchor at start of line; select nothing to begin with.
4193 startWord
= charPos
;
4198 wordSelectAnchorStartPos
= startWord
;
4199 wordSelectAnchorEndPos
= endWord
;
4200 wordSelectInitialCaretPos
= sel
.MainCaret();
4201 WordSelection(wordSelectInitialCaretPos
);
4202 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
4203 lineAnchorPos
= newPos
.Position();
4204 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4205 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4207 SetEmptySelection(sel
.MainCaret());
4209 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4211 NotifyDoubleClick(pt
, modifiers
);
4212 if (PositionIsHotspot(newCharPos
.Position()))
4213 NotifyHotSpotDoubleClicked(newCharPos
.Position(), modifiers
);
4215 } else { // Single click
4217 sel
.selType
= Selection::selStream
;
4219 // Single click in margin: select whole line or only subline if word wrap is enabled
4220 lineAnchorPos
= newPos
.Position();
4221 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4222 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4224 // Single shift+click in margin: select from line anchor to clicked line
4225 if (sel
.MainAnchor() > sel
.MainCaret())
4226 lineAnchorPos
= sel
.MainAnchor() - 1;
4228 lineAnchorPos
= sel
.MainAnchor();
4229 // Reset selection type if there is an empty selection.
4230 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
4231 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
4232 // This ensures that we continue selecting in the same selection mode.
4233 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
4234 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4235 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4238 SetDragPosition(SelectionPosition(invalidPosition
));
4239 SetMouseCapture(true);
4240 if (FineTickerAvailable()) {
4241 FineTickerStart(tickScroll
, 100, 10);
4244 if (PointIsHotspot(pt
)) {
4245 NotifyHotSpotClicked(newCharPos
.Position(), modifiers
);
4246 hotSpotClickPos
= newCharPos
.Position();
4249 if (PointInSelection(pt
) && !SelectionEmpty())
4250 inDragDrop
= ddInitial
;
4252 inDragDrop
= ddNone
;
4254 SetMouseCapture(true);
4255 if (FineTickerAvailable()) {
4256 FineTickerStart(tickScroll
, 100, 10);
4258 if (inDragDrop
!= ddInitial
) {
4259 SetDragPosition(SelectionPosition(invalidPosition
));
4261 if (ctrl
&& multipleSelection
) {
4262 SelectionRange
range(newPos
);
4263 sel
.TentativeSelection(range
);
4264 InvalidateSelection(range
, true);
4266 InvalidateSelection(SelectionRange(newPos
), true);
4267 if (sel
.Count() > 1)
4269 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
4271 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4272 SetSelection(newPos
, newPos
);
4275 SelectionPosition anchorCurrent
= newPos
;
4277 anchorCurrent
= sel
.IsRectangular() ?
4278 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
4279 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4280 selectionType
= selChar
;
4281 originalAnchorPos
= sel
.MainCaret();
4282 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
4283 SetRectangularRange();
4287 lastClickTime
= curTime
;
4289 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4290 ShowCaretAtCurrentPosition();
4293 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4294 return ButtonDownWithModifiers(pt
, curTime
, ModifierFlags(shift
, ctrl
, alt
));
4297 bool Editor::PositionIsHotspot(int position
) const {
4298 return vs
.styles
[static_cast<unsigned char>(pdoc
->StyleAt(position
))].hotspot
;
4301 bool Editor::PointIsHotspot(Point pt
) {
4302 int pos
= PositionFromLocation(pt
, true, true);
4303 if (pos
== INVALID_POSITION
)
4305 return PositionIsHotspot(pos
);
4308 void Editor::SetHoverIndicatorPosition(int position
) {
4309 int hoverIndicatorPosPrev
= hoverIndicatorPos
;
4310 hoverIndicatorPos
= INVALID_POSITION
;
4311 if (vs
.indicatorsDynamic
== 0)
4313 if (position
!= INVALID_POSITION
) {
4314 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
4315 if (vs
.indicators
[deco
->indicator
].IsDynamic()) {
4316 if (pdoc
->decorations
.ValueAt(deco
->indicator
, position
)) {
4317 hoverIndicatorPos
= position
;
4322 if (hoverIndicatorPosPrev
!= hoverIndicatorPos
) {
4323 if (hoverIndicatorPosPrev
!= INVALID_POSITION
)
4324 InvalidateRange(hoverIndicatorPosPrev
, hoverIndicatorPosPrev
+ 1);
4325 if (hoverIndicatorPos
!= INVALID_POSITION
)
4326 InvalidateRange(hoverIndicatorPos
, hoverIndicatorPos
+ 1);
4330 void Editor::SetHoverIndicatorPoint(Point pt
) {
4331 if (vs
.indicatorsDynamic
== 0) {
4332 SetHoverIndicatorPosition(INVALID_POSITION
);
4334 SetHoverIndicatorPosition(PositionFromLocation(pt
, true, true));
4338 void Editor::SetHotSpotRange(Point
*pt
) {
4340 int pos
= PositionFromLocation(*pt
, false, true);
4342 // If we don't limit this to word characters then the
4343 // range can encompass more than the run range and then
4344 // the underline will not be drawn properly.
4346 hsNew
.start
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4347 hsNew
.end
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4349 // Only invalidate the range if the hotspot range has changed...
4350 if (!(hsNew
== hotspot
)) {
4351 if (hotspot
.Valid()) {
4352 InvalidateRange(hotspot
.start
, hotspot
.end
);
4355 InvalidateRange(hotspot
.start
, hotspot
.end
);
4358 if (hotspot
.Valid()) {
4359 InvalidateRange(hotspot
.start
, hotspot
.end
);
4361 hotspot
= Range(invalidPosition
);
4365 Range
Editor::GetHotSpotRange() const {
4369 void Editor::ButtonMoveWithModifiers(Point pt
, int modifiers
) {
4370 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4374 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
4375 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4376 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
4378 if (inDragDrop
== ddInitial
) {
4379 if (DragThreshold(ptMouseLast
, pt
)) {
4380 SetMouseCapture(false);
4381 if (FineTickerAvailable()) {
4382 FineTickerCancel(tickScroll
);
4384 SetDragPosition(movePos
);
4385 CopySelectionRange(&drag
);
4392 PRectangle rcClient
= GetClientRectangle();
4393 Point ptOrigin
= GetVisibleOriginInMain();
4394 rcClient
.Move(0, -ptOrigin
.y
);
4395 if (FineTickerAvailable() && (dwellDelay
< SC_TIME_FOREVER
) && rcClient
.Contains(pt
)) {
4396 FineTickerStart(tickDwell
, dwellDelay
, dwellDelay
/10);
4398 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4399 if (HaveMouseCapture()) {
4401 // Slow down autoscrolling/selection
4402 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4403 if (autoScrollTimer
.ticksToWait
> 0)
4405 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4408 if (posDrag
.IsValid()) {
4409 SetDragPosition(movePos
);
4411 if (selectionType
== selChar
) {
4412 if (sel
.selType
== Selection::selStream
&& (modifiers
& SCI_ALT
) && mouseSelectionRectangularSwitch
) {
4413 sel
.selType
= Selection::selRectangle
;
4415 if (sel
.IsRectangular()) {
4416 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
4417 SetSelection(movePos
, sel
.RangeMain().anchor
);
4418 } else if (sel
.Count() > 1) {
4419 InvalidateSelection(sel
.RangeMain(), false);
4420 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
4421 sel
.TentativeSelection(range
);
4422 InvalidateSelection(range
, true);
4424 SetSelection(movePos
, sel
.RangeMain().anchor
);
4426 } else if (selectionType
== selWord
) {
4427 // Continue selecting by word
4428 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
4429 // No need to do anything. Previously this case was lumped
4430 // in with "Moved forward", but that can be harmful in this
4431 // case: a handler for the NotifyDoubleClick re-adjusts
4432 // the selection for a fancier definition of "word" (for
4433 // example, in Perl it is useful to include the leading
4434 // '$', '%' or '@' on variables for word selection). In this
4435 // the ButtonMove() called via Tick() for auto-scrolling
4436 // could result in the fancier word selection adjustment
4439 wordSelectInitialCaretPos
= -1;
4440 WordSelection(movePos
.Position());
4443 // Continue selecting by line
4444 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4449 int lineMove
= DisplayFromPosition(movePos
.Position());
4450 if (pt
.y
> rcClient
.bottom
) {
4451 ScrollTo(lineMove
- LinesOnScreen() + 1);
4453 } else if (pt
.y
< rcClient
.top
) {
4457 EnsureCaretVisible(false, false, true);
4459 if (hotspot
.Valid() && !PointIsHotspot(pt
))
4460 SetHotSpotRange(NULL
);
4462 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,true) != hotSpotClickPos
) {
4463 if (inDragDrop
== ddNone
) {
4464 DisplayCursor(Window::cursorText
);
4466 hotSpotClickPos
= INVALID_POSITION
;
4470 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4471 if (PointInSelMargin(pt
)) {
4472 DisplayCursor(GetMarginCursor(pt
));
4473 SetHotSpotRange(NULL
);
4474 return; // No need to test for selection
4477 // Display regular (drag) cursor over selection
4478 if (PointInSelection(pt
) && !SelectionEmpty()) {
4479 DisplayCursor(Window::cursorArrow
);
4481 SetHoverIndicatorPoint(pt
);
4482 if (PointIsHotspot(pt
)) {
4483 DisplayCursor(Window::cursorHand
);
4484 SetHotSpotRange(&pt
);
4486 if (hoverIndicatorPos
!= invalidPosition
)
4487 DisplayCursor(Window::cursorHand
);
4489 DisplayCursor(Window::cursorText
);
4490 SetHotSpotRange(NULL
);
4496 void Editor::ButtonMove(Point pt
) {
4497 ButtonMoveWithModifiers(pt
, 0);
4500 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4501 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
4502 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
4503 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4504 if (hoverIndicatorPos
!= INVALID_POSITION
)
4505 InvalidateRange(newPos
.Position(), newPos
.Position() + 1);
4506 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4507 if (inDragDrop
== ddInitial
) {
4508 inDragDrop
= ddNone
;
4509 SetEmptySelection(newPos
);
4510 selectionType
= selChar
;
4511 originalAnchorPos
= sel
.MainCaret();
4513 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
4514 hotSpotClickPos
= INVALID_POSITION
;
4515 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4516 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4517 NotifyHotSpotReleaseClick(newCharPos
.Position(), ctrl
? SCI_CTRL
: 0);
4519 if (HaveMouseCapture()) {
4520 if (PointInSelMargin(pt
)) {
4521 DisplayCursor(GetMarginCursor(pt
));
4523 DisplayCursor(Window::cursorText
);
4524 SetHotSpotRange(NULL
);
4527 SetMouseCapture(false);
4528 if (FineTickerAvailable()) {
4529 FineTickerCancel(tickScroll
);
4531 NotifyIndicatorClick(false, newPos
.Position(), 0);
4532 if (inDragDrop
== ddDragging
) {
4533 SelectionPosition selStart
= SelectionStart();
4534 SelectionPosition selEnd
= SelectionEnd();
4535 if (selStart
< selEnd
) {
4536 if (drag
.Length()) {
4537 const int length
= static_cast<int>(drag
.Length());
4539 const int lengthInserted
= pdoc
->InsertString(
4540 newPos
.Position(), drag
.Data(), length
);
4541 if (lengthInserted
> 0) {
4542 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4544 } else if (newPos
< selStart
) {
4545 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4546 const int lengthInserted
= pdoc
->InsertString(
4547 newPos
.Position(), drag
.Data(), length
);
4548 if (lengthInserted
> 0) {
4549 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4551 } else if (newPos
> selEnd
) {
4552 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4553 newPos
.Add(-static_cast<int>(drag
.Length()));
4554 const int lengthInserted
= pdoc
->InsertString(
4555 newPos
.Position(), drag
.Data(), length
);
4556 if (lengthInserted
> 0) {
4557 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4560 SetEmptySelection(newPos
.Position());
4564 selectionType
= selChar
;
4567 if (selectionType
== selChar
) {
4568 if (sel
.Count() > 1) {
4570 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
4571 InvalidateSelection(sel
.RangeMain(), true);
4573 SetSelection(newPos
, sel
.RangeMain().anchor
);
4576 sel
.CommitTentative();
4578 SetRectangularRange();
4579 lastClickTime
= curTime
;
4581 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4582 if (sel
.selType
== Selection::selStream
) {
4585 inDragDrop
= ddNone
;
4586 EnsureCaretVisible(false);
4590 // Called frequently to perform background UI including
4591 // caret blinking and automatic scrolling.
4592 void Editor::Tick() {
4593 if (HaveMouseCapture()) {
4595 ButtonMove(ptMouseLast
);
4597 if (caret
.period
> 0) {
4598 timer
.ticksToWait
-= timer
.tickSize
;
4599 if (timer
.ticksToWait
<= 0) {
4600 caret
.on
= !caret
.on
;
4601 timer
.ticksToWait
= caret
.period
;
4607 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
4608 scrollWidth
= view
.lineWidthMaxSeen
;
4611 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4612 (ticksToDwell
> 0) &&
4613 (!HaveMouseCapture()) &&
4614 (ptMouseLast
.y
>= 0)) {
4615 ticksToDwell
-= timer
.tickSize
;
4616 if (ticksToDwell
<= 0) {
4618 NotifyDwelling(ptMouseLast
, dwelling
);
4623 bool Editor::Idle() {
4627 bool wrappingDone
= !Wrapping();
4629 if (!wrappingDone
) {
4630 // Wrap lines during idle.
4633 if (!wrapPending
.NeedsWrap())
4634 wrappingDone
= true;
4637 // Add more idle things to do here, but make sure idleDone is
4638 // set correctly before the function returns. returning
4639 // false will stop calling this idle function until SetIdle() is
4642 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
4647 void Editor::SetTicking(bool) {
4648 // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
4649 // derived platform class but fine grained timers should now be implemented.
4650 // Either way, execution should not arrive here so assert failure.
4654 void Editor::TickFor(TickReason reason
) {
4657 caret
.on
= !caret
.on
;
4664 ButtonMove(ptMouseLast
);
4668 FineTickerCancel(tickWiden
);
4671 if ((!HaveMouseCapture()) &&
4672 (ptMouseLast
.y
>= 0)) {
4674 NotifyDwelling(ptMouseLast
, dwelling
);
4676 FineTickerCancel(tickDwell
);
4679 // tickPlatform handled by subclass
4684 bool Editor::FineTickerAvailable() {
4688 // FineTickerStart is be overridden by subclasses that support fine ticking so
4689 // this method should never be called.
4690 bool Editor::FineTickerRunning(TickReason
) {
4695 // FineTickerStart is be overridden by subclasses that support fine ticking so
4696 // this method should never be called.
4697 void Editor::FineTickerStart(TickReason
, int, int) {
4701 // FineTickerCancel is be overridden by subclasses that support fine ticking so
4702 // this method should never be called.
4703 void Editor::FineTickerCancel(TickReason
) {
4707 void Editor::SetFocusState(bool focusState
) {
4708 hasFocus
= focusState
;
4709 NotifyFocus(hasFocus
);
4713 ShowCaretAtCurrentPosition();
4716 int Editor::PositionAfterArea(PRectangle rcArea
) const {
4717 // The start of the document line after the display line after the area
4718 // This often means that the line after a modification is restyled which helps
4719 // detect multiline comment additions and heals single line comments
4720 int lineAfter
= TopLineOfMain() + static_cast<int>(rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
4721 if (lineAfter
< cs
.LinesDisplayed())
4722 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
4724 return pdoc
->Length();
4727 // Style to a position within the view. If this causes a change at end of last line then
4728 // affects later lines so style all the viewed text.
4729 void Editor::StyleToPositionInView(Position pos
) {
4730 int endWindow
= PositionAfterArea(GetClientDrawingRectangle());
4731 if (pos
> endWindow
)
4733 int styleAtEnd
= pdoc
->StyleAt(pos
-1);
4734 pdoc
->EnsureStyledTo(pos
);
4735 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleAt(pos
-1))) {
4736 // Style at end of line changed so is multi-line change like starting a comment
4737 // so require rest of window to be styled.
4738 DiscardOverdraw(); // Prepared bitmaps may be invalid
4739 // DiscardOverdraw may have truncated client drawing area so recalculate endWindow
4740 endWindow
= PositionAfterArea(GetClientDrawingRectangle());
4741 pdoc
->EnsureStyledTo(endWindow
);
4745 void Editor::IdleWork() {
4746 // Style the line after the modification as this allows modifications that change just the
4747 // line of the modification to heal instead of propagating to the rest of the window.
4748 if (workNeeded
.items
& WorkNeeded::workStyle
)
4749 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(workNeeded
.upTo
) + 2));
4755 void Editor::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
4756 workNeeded
.Need(items
, upTo
);
4759 bool Editor::PaintContains(PRectangle rc
) {
4763 return rcPaint
.Contains(rc
);
4767 bool Editor::PaintContainsMargin() {
4768 if (wMargin
.GetID()) {
4769 // With separate margin view, paint of text view
4770 // never contains margin.
4773 PRectangle rcSelMargin
= GetClientRectangle();
4774 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
);
4775 return PaintContains(rcSelMargin
);
4778 void Editor::CheckForChangeOutsidePaint(Range r
) {
4779 if (paintState
== painting
&& !paintingAllText
) {
4780 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4784 PRectangle rcRange
= RectangleFromRange(r
, 0);
4785 PRectangle rcText
= GetTextRectangle();
4786 if (rcRange
.top
< rcText
.top
) {
4787 rcRange
.top
= rcText
.top
;
4789 if (rcRange
.bottom
> rcText
.bottom
) {
4790 rcRange
.bottom
= rcText
.bottom
;
4793 if (!PaintContains(rcRange
)) {
4795 paintAbandonedByStyling
= true;
4800 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4801 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4802 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4803 CheckForChangeOutsidePaint(Range(braces
[0]));
4804 CheckForChangeOutsidePaint(Range(pos0
));
4807 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4808 CheckForChangeOutsidePaint(Range(braces
[1]));
4809 CheckForChangeOutsidePaint(Range(pos1
));
4812 bracesMatchStyle
= matchStyle
;
4813 if (paintState
== notPainting
) {
4819 void Editor::SetAnnotationHeights(int start
, int end
) {
4820 if (vs
.annotationVisible
) {
4822 bool changedHeight
= false;
4823 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
4824 int linesWrapped
= 1;
4826 AutoSurface
surface(this);
4827 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
4828 if (surface
&& ll
) {
4829 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
4830 linesWrapped
= ll
->lines
;
4833 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
4834 changedHeight
= true;
4836 if (changedHeight
) {
4842 void Editor::SetDocPointer(Document
*document
) {
4843 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4844 pdoc
->RemoveWatcher(this, 0);
4846 if (document
== NULL
) {
4847 pdoc
= new Document();
4853 // Ensure all positions within document
4858 braces
[0] = invalidPosition
;
4859 braces
[1] = invalidPosition
;
4861 vs
.ReleaseAllExtendedStyles();
4863 SetRepresentations();
4865 // Reset the contraction state to fully shown.
4867 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4868 SetAnnotationHeights(0, pdoc
->LinesTotal());
4869 view
.llc
.Deallocate();
4872 hotspot
= Range(invalidPosition
);
4873 hoverIndicatorPos
= invalidPosition
;
4875 view
.ClearAllTabstops();
4877 pdoc
->AddWatcher(this, 0);
4882 void Editor::SetAnnotationVisible(int visible
) {
4883 if (vs
.annotationVisible
!= visible
) {
4884 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
4885 vs
.annotationVisible
= visible
;
4886 if (changedFromOrToHidden
) {
4887 int dir
= vs
.annotationVisible
? 1 : -1;
4888 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
4889 int annotationLines
= pdoc
->AnnotationLines(line
);
4890 if (annotationLines
> 0) {
4891 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
4900 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
4902 int Editor::ExpandLine(int line
) {
4903 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4905 while (line
<= lineMaxSubord
) {
4906 cs
.SetVisible(line
, line
, true);
4907 int level
= pdoc
->GetLevel(line
);
4908 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4909 if (cs
.GetExpanded(line
)) {
4910 line
= ExpandLine(line
);
4912 line
= pdoc
->GetLastChild(line
);
4917 return lineMaxSubord
;
4920 void Editor::SetFoldExpanded(int lineDoc
, bool expanded
) {
4921 if (cs
.SetExpanded(lineDoc
, expanded
)) {
4926 void Editor::FoldLine(int line
, int action
) {
4928 if (action
== SC_FOLDACTION_TOGGLE
) {
4929 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
4930 line
= pdoc
->GetFoldParent(line
);
4934 action
= (cs
.GetExpanded(line
)) ? SC_FOLDACTION_CONTRACT
: SC_FOLDACTION_EXPAND
;
4937 if (action
== SC_FOLDACTION_CONTRACT
) {
4938 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4939 if (lineMaxSubord
> line
) {
4940 cs
.SetExpanded(line
, 0);
4941 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4943 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
4944 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
4945 // This does not re-expand the fold
4946 EnsureCaretVisible();
4951 if (!(cs
.GetVisible(line
))) {
4952 EnsureLineVisible(line
, false);
4955 cs
.SetExpanded(line
, 1);
4964 void Editor::FoldExpand(int line
, int action
, int level
) {
4965 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
4966 if (action
== SC_FOLDACTION_TOGGLE
) {
4967 expanding
= !cs
.GetExpanded(line
);
4969 SetFoldExpanded(line
, expanding
);
4970 if (expanding
&& (cs
.HiddenLines() == 0))
4973 int lineMaxSubord
= pdoc
->GetLastChild(line
, level
& SC_FOLDLEVELNUMBERMASK
);
4975 cs
.SetVisible(line
, lineMaxSubord
, expanding
);
4976 while (line
<= lineMaxSubord
) {
4977 int levelLine
= pdoc
->GetLevel(line
);
4978 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
4979 SetFoldExpanded(line
, expanding
);
4987 int Editor::ContractedFoldNext(int lineStart
) const {
4988 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
4989 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
4991 line
= cs
.ContractedNext(line
+1);
5000 * Recurse up from this line to find any folds that prevent this line from being visible
5001 * and unfold them all.
5003 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5005 // In case in need of wrapping to ensure DisplayFromDoc works.
5006 if (lineDoc
>= wrapPending
.start
)
5009 if (!cs
.GetVisible(lineDoc
)) {
5010 // Back up to find a non-blank line
5011 int lookLine
= lineDoc
;
5012 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
5013 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
5014 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
5016 int lineParent
= pdoc
->GetFoldParent(lookLine
);
5017 if (lineParent
< 0) {
5018 // Backed up to a top level line, so try to find parent of initial line
5019 lineParent
= pdoc
->GetFoldParent(lineDoc
);
5021 if (lineParent
>= 0) {
5022 if (lineDoc
!= lineParent
)
5023 EnsureLineVisible(lineParent
, enforcePolicy
);
5024 if (!cs
.GetExpanded(lineParent
)) {
5025 cs
.SetExpanded(lineParent
, 1);
5026 ExpandLine(lineParent
);
5032 if (enforcePolicy
) {
5033 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5034 if (visiblePolicy
& VISIBLE_SLOP
) {
5035 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5036 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5037 SetVerticalScrollPos();
5039 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5040 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5041 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5042 SetVerticalScrollPos();
5046 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5047 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5048 SetVerticalScrollPos();
5055 void Editor::FoldAll(int action
) {
5056 pdoc
->EnsureStyledTo(pdoc
->Length());
5057 int maxLine
= pdoc
->LinesTotal();
5058 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5059 if (action
== SC_FOLDACTION_TOGGLE
) {
5060 // Discover current state
5061 for (int lineSeek
= 0; lineSeek
< maxLine
; lineSeek
++) {
5062 if (pdoc
->GetLevel(lineSeek
) & SC_FOLDLEVELHEADERFLAG
) {
5063 expanding
= !cs
.GetExpanded(lineSeek
);
5069 cs
.SetVisible(0, maxLine
-1, true);
5070 for (int line
= 0; line
< maxLine
; line
++) {
5071 int levelLine
= pdoc
->GetLevel(line
);
5072 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5073 SetFoldExpanded(line
, true);
5077 for (int line
= 0; line
< maxLine
; line
++) {
5078 int level
= pdoc
->GetLevel(line
);
5079 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
5080 (SC_FOLDLEVELBASE
== (level
& SC_FOLDLEVELNUMBERMASK
))) {
5081 SetFoldExpanded(line
, false);
5082 int lineMaxSubord
= pdoc
->GetLastChild(line
, -1);
5083 if (lineMaxSubord
> line
) {
5084 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5093 void Editor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
5094 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
5095 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
5096 // Adding a fold point.
5097 if (cs
.SetExpanded(line
, true)) {
5100 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5102 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
5103 if (!cs
.GetExpanded(line
)) {
5104 // Removing the fold from one that has been contracted so should expand
5105 // otherwise lines are left invisible with no way to make them visible
5106 if (cs
.SetExpanded(line
, true)) {
5109 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5112 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) &&
5113 ((levelPrev
& SC_FOLDLEVELNUMBERMASK
) > (levelNow
& SC_FOLDLEVELNUMBERMASK
))) {
5114 if (cs
.HiddenLines()) {
5115 // See if should still be hidden
5116 int parentLine
= pdoc
->GetFoldParent(line
);
5117 if ((parentLine
< 0) || (cs
.GetExpanded(parentLine
) && cs
.GetVisible(parentLine
))) {
5118 cs
.SetVisible(line
, line
, true);
5126 void Editor::NeedShown(int pos
, int len
) {
5127 if (foldAutomatic
& SC_AUTOMATICFOLD_SHOW
) {
5128 int lineStart
= pdoc
->LineFromPosition(pos
);
5129 int lineEnd
= pdoc
->LineFromPosition(pos
+len
);
5130 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
5131 EnsureLineVisible(line
, false);
5134 NotifyNeedShown(pos
, len
);
5138 int Editor::GetTag(char *tagValue
, int tagNumber
) {
5139 const char *text
= 0;
5141 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
5142 char name
[3] = "\\?";
5143 name
[1] = static_cast<char>(tagNumber
+ '0');
5145 text
= pdoc
->SubstituteByPosition(name
, &length
);
5149 memcpy(tagValue
, text
, length
+ 1);
5156 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5159 length
= istrlen(text
);
5160 if (replacePatterns
) {
5161 text
= pdoc
->SubstituteByPosition(text
, &length
);
5166 if (targetStart
!= targetEnd
)
5167 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5168 targetEnd
= targetStart
;
5169 const int lengthInserted
= pdoc
->InsertString(targetStart
, text
, length
);
5170 targetEnd
= targetStart
+ lengthInserted
;
5174 bool Editor::IsUnicodeMode() const {
5175 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5178 int Editor::CodePage() const {
5180 return pdoc
->dbcsCodePage
;
5185 int Editor::WrapCount(int line
) {
5186 AutoSurface
surface(this);
5187 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5189 if (surface
&& ll
) {
5190 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5197 void Editor::AddStyledText(char *buffer
, int appendLength
) {
5198 // The buffer consists of alternating character bytes and style bytes
5199 int textLength
= appendLength
/ 2;
5200 std::string
text(textLength
, '\0');
5202 for (i
= 0; i
< textLength
; i
++) {
5203 text
[i
] = buffer
[i
*2];
5205 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), text
.c_str(), textLength
);
5206 for (i
= 0; i
< textLength
; i
++) {
5207 text
[i
] = buffer
[i
*2+1];
5209 pdoc
->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
5210 pdoc
->SetStyles(textLength
, text
.c_str());
5211 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5214 static bool ValidMargin(uptr_t wParam
) {
5215 return wParam
<= SC_MAX_MARGIN
;
5218 static char *CharPtrFromSPtr(sptr_t lParam
) {
5219 return reinterpret_cast<char *>(lParam
);
5222 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5223 vs
.EnsureStyle(wParam
);
5225 case SCI_STYLESETFORE
:
5226 vs
.styles
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
5228 case SCI_STYLESETBACK
:
5229 vs
.styles
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
5231 case SCI_STYLESETBOLD
:
5232 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
5234 case SCI_STYLESETWEIGHT
:
5235 vs
.styles
[wParam
].weight
= static_cast<int>(lParam
);
5237 case SCI_STYLESETITALIC
:
5238 vs
.styles
[wParam
].italic
= lParam
!= 0;
5240 case SCI_STYLESETEOLFILLED
:
5241 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5243 case SCI_STYLESETSIZE
:
5244 vs
.styles
[wParam
].size
= static_cast<int>(lParam
* SC_FONT_SIZE_MULTIPLIER
);
5246 case SCI_STYLESETSIZEFRACTIONAL
:
5247 vs
.styles
[wParam
].size
= static_cast<int>(lParam
);
5249 case SCI_STYLESETFONT
:
5251 vs
.SetStyleFontName(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5254 case SCI_STYLESETUNDERLINE
:
5255 vs
.styles
[wParam
].underline
= lParam
!= 0;
5257 case SCI_STYLESETCASE
:
5258 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5260 case SCI_STYLESETCHARACTERSET
:
5261 vs
.styles
[wParam
].characterSet
= static_cast<int>(lParam
);
5262 pdoc
->SetCaseFolder(NULL
);
5264 case SCI_STYLESETVISIBLE
:
5265 vs
.styles
[wParam
].visible
= lParam
!= 0;
5267 case SCI_STYLESETCHANGEABLE
:
5268 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5270 case SCI_STYLESETHOTSPOT
:
5271 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5274 InvalidateStyleRedraw();
5277 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5278 vs
.EnsureStyle(wParam
);
5280 case SCI_STYLEGETFORE
:
5281 return vs
.styles
[wParam
].fore
.AsLong();
5282 case SCI_STYLEGETBACK
:
5283 return vs
.styles
[wParam
].back
.AsLong();
5284 case SCI_STYLEGETBOLD
:
5285 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
5286 case SCI_STYLEGETWEIGHT
:
5287 return vs
.styles
[wParam
].weight
;
5288 case SCI_STYLEGETITALIC
:
5289 return vs
.styles
[wParam
].italic
? 1 : 0;
5290 case SCI_STYLEGETEOLFILLED
:
5291 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5292 case SCI_STYLEGETSIZE
:
5293 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
5294 case SCI_STYLEGETSIZEFRACTIONAL
:
5295 return vs
.styles
[wParam
].size
;
5296 case SCI_STYLEGETFONT
:
5297 return StringResult(lParam
, vs
.styles
[wParam
].fontName
);
5298 case SCI_STYLEGETUNDERLINE
:
5299 return vs
.styles
[wParam
].underline
? 1 : 0;
5300 case SCI_STYLEGETCASE
:
5301 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5302 case SCI_STYLEGETCHARACTERSET
:
5303 return vs
.styles
[wParam
].characterSet
;
5304 case SCI_STYLEGETVISIBLE
:
5305 return vs
.styles
[wParam
].visible
? 1 : 0;
5306 case SCI_STYLEGETCHANGEABLE
:
5307 return vs
.styles
[wParam
].changeable
? 1 : 0;
5308 case SCI_STYLEGETHOTSPOT
:
5309 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5314 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
5315 const size_t len
= val
? strlen(val
) : 0;
5317 char *ptr
= CharPtrFromSPtr(lParam
);
5319 memcpy(ptr
, val
, len
+1);
5323 return len
; // Not including NUL
5326 sptr_t
Editor::BytesResult(sptr_t lParam
, const unsigned char *val
, size_t len
) {
5327 // No NUL termination: len is number of valid/displayed bytes
5328 if ((lParam
) && (len
> 0)) {
5329 char *ptr
= CharPtrFromSPtr(lParam
);
5331 memcpy(ptr
, val
, len
);
5335 return val
? len
: 0;
5338 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5339 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5341 // Optional macro recording hook
5343 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5349 return pdoc
->Length() + 1;
5352 char *ptr
= CharPtrFromSPtr(lParam
);
5353 unsigned int iChar
= 0;
5354 for (; iChar
< wParam
- 1; iChar
++)
5355 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5364 pdoc
->DeleteChars(0, pdoc
->Length());
5365 SetEmptySelection(0);
5366 const char *text
= CharPtrFromSPtr(lParam
);
5367 pdoc
->InsertString(0, text
, istrlen(text
));
5371 case SCI_GETTEXTLENGTH
:
5372 return pdoc
->Length();
5383 case SCI_COPYALLOWLINE
:
5387 case SCI_VERTICALCENTRECARET
:
5388 VerticalCentreCaret();
5391 case SCI_MOVESELECTEDLINESUP
:
5392 MoveSelectedLinesUp();
5395 case SCI_MOVESELECTEDLINESDOWN
:
5396 MoveSelectedLinesDown();
5400 CopyRangeToClipboard(static_cast<int>(wParam
), static_cast<int>(lParam
));
5404 CopyText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5409 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5412 EnsureCaretVisible();
5418 EnsureCaretVisible();
5427 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5429 case SCI_EMPTYUNDOBUFFER
:
5430 pdoc
->DeleteUndoHistory();
5433 case SCI_GETFIRSTVISIBLELINE
:
5436 case SCI_SETFIRSTVISIBLELINE
:
5437 ScrollTo(static_cast<int>(wParam
));
5440 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5441 int lineStart
= pdoc
->LineStart(static_cast<int>(wParam
));
5442 int lineEnd
= pdoc
->LineStart(static_cast<int>(wParam
+ 1));
5444 return lineEnd
- lineStart
;
5446 char *ptr
= CharPtrFromSPtr(lParam
);
5448 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5449 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5454 case SCI_GETLINECOUNT
:
5455 if (pdoc
->LinesTotal() == 0)
5458 return pdoc
->LinesTotal();
5461 return !pdoc
->IsSavePoint();
5464 int nStart
= static_cast<int>(wParam
);
5465 int nEnd
= static_cast<int>(lParam
);
5467 nEnd
= pdoc
->Length();
5469 nStart
= nEnd
; // Remove selection
5470 InvalidateSelection(SelectionRange(nStart
, nEnd
));
5472 sel
.selType
= Selection::selStream
;
5473 SetSelection(nEnd
, nStart
);
5474 EnsureCaretVisible();
5478 case SCI_GETSELTEXT
: {
5479 SelectionText selectedText
;
5480 CopySelectionRange(&selectedText
);
5482 return selectedText
.LengthWithTerminator();
5484 char *ptr
= CharPtrFromSPtr(lParam
);
5485 unsigned int iChar
= 0;
5486 if (selectedText
.Length()) {
5487 for (; iChar
< selectedText
.LengthWithTerminator(); iChar
++)
5488 ptr
[iChar
] = selectedText
.Data()[iChar
];
5496 case SCI_LINEFROMPOSITION
:
5497 if (static_cast<int>(wParam
) < 0)
5499 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
5501 case SCI_POSITIONFROMLINE
:
5502 if (static_cast<int>(wParam
) < 0)
5503 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
5505 return 0; // Even if there is no text, there is a first line that starts at 0
5506 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5508 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5510 return pdoc
->LineStart(static_cast<int>(wParam
));
5512 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5513 case SCI_LINELENGTH
:
5514 if ((static_cast<int>(wParam
) < 0) ||
5515 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5517 return pdoc
->LineStart(static_cast<int>(wParam
) + 1) - pdoc
->LineStart(static_cast<int>(wParam
));
5519 case SCI_REPLACESEL
: {
5524 char *replacement
= CharPtrFromSPtr(lParam
);
5525 const int lengthInserted
= pdoc
->InsertString(
5526 sel
.MainCaret(), replacement
, istrlen(replacement
));
5527 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5528 EnsureCaretVisible();
5532 case SCI_SETTARGETSTART
:
5533 targetStart
= static_cast<int>(wParam
);
5536 case SCI_GETTARGETSTART
:
5539 case SCI_SETTARGETEND
:
5540 targetEnd
= static_cast<int>(wParam
);
5543 case SCI_GETTARGETEND
:
5546 case SCI_SETTARGETRANGE
:
5547 targetStart
= static_cast<int>(wParam
);
5548 targetEnd
= static_cast<int>(lParam
);
5551 case SCI_TARGETFROMSELECTION
:
5552 if (sel
.MainCaret() < sel
.MainAnchor()) {
5553 targetStart
= sel
.MainCaret();
5554 targetEnd
= sel
.MainAnchor();
5556 targetStart
= sel
.MainAnchor();
5557 targetEnd
= sel
.MainCaret();
5561 case SCI_GETTARGETTEXT
: {
5562 std::string text
= RangeText(targetStart
, targetEnd
);
5563 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(text
.c_str()), text
.length());
5566 case SCI_REPLACETARGET
:
5567 PLATFORM_ASSERT(lParam
);
5568 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5570 case SCI_REPLACETARGETRE
:
5571 PLATFORM_ASSERT(lParam
);
5572 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5574 case SCI_SEARCHINTARGET
:
5575 PLATFORM_ASSERT(lParam
);
5576 return SearchInTarget(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5578 case SCI_SETSEARCHFLAGS
:
5579 searchFlags
= static_cast<int>(wParam
);
5582 case SCI_GETSEARCHFLAGS
:
5586 return GetTag(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5588 case SCI_POSITIONBEFORE
:
5589 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) - 1, -1, true);
5591 case SCI_POSITIONAFTER
:
5592 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) + 1, 1, true);
5594 case SCI_POSITIONRELATIVE
:
5595 return Platform::Clamp(pdoc
->GetRelativePosition(static_cast<int>(wParam
), static_cast<int>(lParam
)), 0, pdoc
->Length());
5597 case SCI_LINESCROLL
:
5598 ScrollTo(topLine
+ static_cast<int>(lParam
));
5599 HorizontalScrollTo(xOffset
+ static_cast<int>(wParam
)* static_cast<int>(vs
.spaceWidth
));
5602 case SCI_SETXOFFSET
:
5603 xOffset
= static_cast<int>(wParam
);
5604 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
5605 SetHorizontalScrollPos();
5609 case SCI_GETXOFFSET
:
5612 case SCI_CHOOSECARETX
:
5616 case SCI_SCROLLCARET
:
5617 EnsureCaretVisible();
5620 case SCI_SETREADONLY
:
5621 pdoc
->SetReadOnly(wParam
!= 0);
5624 case SCI_GETREADONLY
:
5625 return pdoc
->IsReadOnly();
5630 case SCI_POINTXFROMPOSITION
:
5634 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5635 // Convert to view-relative
5636 return static_cast<int>(pt
.x
) - vs
.textStart
+ vs
.fixedColumnWidth
;
5639 case SCI_POINTYFROMPOSITION
:
5643 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5644 return static_cast<int>(pt
.y
);
5648 return FindText(wParam
, lParam
);
5650 case SCI_GETTEXTRANGE
: {
5653 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
5654 int cpMax
= static_cast<int>(tr
->chrg
.cpMax
);
5656 cpMax
= pdoc
->Length();
5657 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5658 int len
= static_cast<int>(cpMax
- tr
->chrg
.cpMin
); // No -1 as cpMin and cpMax are referring to inter character positions
5659 pdoc
->GetCharRange(tr
->lpstrText
, static_cast<int>(tr
->chrg
.cpMin
), len
);
5660 // Spec says copied text is terminated with a NUL
5661 tr
->lpstrText
[len
] = '\0';
5662 return len
; // Not including NUL
5665 case SCI_HIDESELECTION
:
5666 view
.hideSelection
= wParam
!= 0;
5670 case SCI_FORMATRANGE
:
5671 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
5673 case SCI_GETMARGINLEFT
:
5674 return vs
.leftMarginWidth
;
5676 case SCI_GETMARGINRIGHT
:
5677 return vs
.rightMarginWidth
;
5679 case SCI_SETMARGINLEFT
:
5680 lastXChosen
+= static_cast<int>(lParam
) - vs
.leftMarginWidth
;
5681 vs
.leftMarginWidth
= static_cast<int>(lParam
);
5682 InvalidateStyleRedraw();
5685 case SCI_SETMARGINRIGHT
:
5686 vs
.rightMarginWidth
= static_cast<int>(lParam
);
5687 InvalidateStyleRedraw();
5690 // Control specific mesages
5695 const int lengthInserted
= pdoc
->InsertString(
5696 CurrentPosition(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5697 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5701 case SCI_ADDSTYLEDTEXT
:
5703 AddStyledText(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5706 case SCI_INSERTTEXT
: {
5709 int insertPos
= static_cast<int>(wParam
);
5710 if (static_cast<int>(wParam
) == -1)
5711 insertPos
= CurrentPosition();
5712 int newCurrent
= CurrentPosition();
5713 char *sz
= CharPtrFromSPtr(lParam
);
5714 const int lengthInserted
= pdoc
->InsertString(insertPos
, sz
, istrlen(sz
));
5715 if (newCurrent
> insertPos
)
5716 newCurrent
+= lengthInserted
;
5717 SetEmptySelection(newCurrent
);
5721 case SCI_CHANGEINSERTION
:
5722 PLATFORM_ASSERT(lParam
);
5723 pdoc
->ChangeInsertion(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5726 case SCI_APPENDTEXT
:
5727 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5734 case SCI_DELETERANGE
:
5735 pdoc
->DeleteChars(static_cast<int>(wParam
), static_cast<int>(lParam
));
5738 case SCI_CLEARDOCUMENTSTYLE
:
5739 ClearDocumentStyle();
5742 case SCI_SETUNDOCOLLECTION
:
5743 pdoc
->SetUndoCollection(wParam
!= 0);
5746 case SCI_GETUNDOCOLLECTION
:
5747 return pdoc
->IsCollectingUndo();
5749 case SCI_BEGINUNDOACTION
:
5750 pdoc
->BeginUndoAction();
5753 case SCI_ENDUNDOACTION
:
5754 pdoc
->EndUndoAction();
5757 case SCI_GETCARETPERIOD
:
5758 return caret
.period
;
5760 case SCI_SETCARETPERIOD
:
5761 CaretSetPeriod(static_cast<int>(wParam
));
5764 case SCI_GETWORDCHARS
:
5765 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
5767 case SCI_SETWORDCHARS
: {
5768 pdoc
->SetDefaultCharClasses(false);
5771 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
5775 case SCI_GETWHITESPACECHARS
:
5776 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
5778 case SCI_SETWHITESPACECHARS
: {
5781 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
5785 case SCI_GETPUNCTUATIONCHARS
:
5786 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
5788 case SCI_SETPUNCTUATIONCHARS
: {
5791 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
5795 case SCI_SETCHARSDEFAULT
:
5796 pdoc
->SetDefaultCharClasses(true);
5800 return pdoc
->Length();
5803 pdoc
->Allocate(static_cast<int>(wParam
));
5807 return pdoc
->CharAt(static_cast<int>(wParam
));
5809 case SCI_SETCURRENTPOS
:
5810 if (sel
.IsRectangular()) {
5811 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
5812 SetRectangularRange();
5815 SetSelection(static_cast<int>(wParam
), sel
.MainAnchor());
5819 case SCI_GETCURRENTPOS
:
5820 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
5823 if (sel
.IsRectangular()) {
5824 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
5825 SetRectangularRange();
5828 SetSelection(sel
.MainCaret(), static_cast<int>(wParam
));
5833 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
5835 case SCI_SETSELECTIONSTART
:
5836 SetSelection(Platform::Maximum(sel
.MainCaret(), static_cast<int>(wParam
)), static_cast<int>(wParam
));
5839 case SCI_GETSELECTIONSTART
:
5840 return sel
.LimitsForRectangularElseMain().start
.Position();
5842 case SCI_SETSELECTIONEND
:
5843 SetSelection(static_cast<int>(wParam
), Platform::Minimum(sel
.MainAnchor(), static_cast<int>(wParam
)));
5846 case SCI_GETSELECTIONEND
:
5847 return sel
.LimitsForRectangularElseMain().end
.Position();
5849 case SCI_SETEMPTYSELECTION
:
5850 SetEmptySelection(static_cast<int>(wParam
));
5853 case SCI_SETPRINTMAGNIFICATION
:
5854 view
.printParameters
.magnification
= static_cast<int>(wParam
);
5857 case SCI_GETPRINTMAGNIFICATION
:
5858 return view
.printParameters
.magnification
;
5860 case SCI_SETPRINTCOLOURMODE
:
5861 view
.printParameters
.colourMode
= static_cast<int>(wParam
);
5864 case SCI_GETPRINTCOLOURMODE
:
5865 return view
.printParameters
.colourMode
;
5867 case SCI_SETPRINTWRAPMODE
:
5868 view
.printParameters
.wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5871 case SCI_GETPRINTWRAPMODE
:
5872 return view
.printParameters
.wrapState
;
5874 case SCI_GETSTYLEAT
:
5875 if (static_cast<int>(wParam
) >= pdoc
->Length())
5878 return pdoc
->StyleAt(static_cast<int>(wParam
));
5888 case SCI_SETSAVEPOINT
:
5889 pdoc
->SetSavePoint();
5892 case SCI_GETSTYLEDTEXT
: {
5895 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
5897 for (long iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
5898 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(static_cast<int>(iChar
));
5899 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(static_cast<int>(iChar
));
5901 tr
->lpstrText
[iPlace
] = '\0';
5902 tr
->lpstrText
[iPlace
+ 1] = '\0';
5907 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5909 case SCI_MARKERLINEFROMHANDLE
:
5910 return pdoc
->LineFromHandle(static_cast<int>(wParam
));
5912 case SCI_MARKERDELETEHANDLE
:
5913 pdoc
->DeleteMarkFromHandle(static_cast<int>(wParam
));
5917 return vs
.viewWhitespace
;
5920 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
5924 case SCI_GETWHITESPACESIZE
:
5925 return vs
.whitespaceSize
;
5927 case SCI_SETWHITESPACESIZE
:
5928 vs
.whitespaceSize
= static_cast<int>(wParam
);
5932 case SCI_POSITIONFROMPOINT
:
5933 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5936 case SCI_POSITIONFROMPOINTCLOSE
:
5937 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5940 case SCI_CHARPOSITIONFROMPOINT
:
5941 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5944 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
5945 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5949 GoToLine(static_cast<int>(wParam
));
5953 SetEmptySelection(static_cast<int>(wParam
));
5954 EnsureCaretVisible();
5957 case SCI_GETCURLINE
: {
5958 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
5959 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
5960 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
5962 return 1 + lineEnd
- lineStart
;
5964 PLATFORM_ASSERT(wParam
> 0);
5965 char *ptr
= CharPtrFromSPtr(lParam
);
5966 unsigned int iPlace
= 0;
5967 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
5968 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5971 return sel
.MainCaret() - lineStart
;
5974 case SCI_GETENDSTYLED
:
5975 return pdoc
->GetEndStyled();
5977 case SCI_GETEOLMODE
:
5978 return pdoc
->eolMode
;
5980 case SCI_SETEOLMODE
:
5981 pdoc
->eolMode
= static_cast<int>(wParam
);
5984 case SCI_SETLINEENDTYPESALLOWED
:
5985 if (pdoc
->SetLineEndTypesAllowed(static_cast<int>(wParam
))) {
5987 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5988 SetAnnotationHeights(0, pdoc
->LinesTotal());
5989 InvalidateStyleRedraw();
5993 case SCI_GETLINEENDTYPESALLOWED
:
5994 return pdoc
->GetLineEndTypesAllowed();
5996 case SCI_GETLINEENDTYPESACTIVE
:
5997 return pdoc
->GetLineEndTypesActive();
5999 case SCI_STARTSTYLING
:
6000 pdoc
->StartStyling(static_cast<int>(wParam
), static_cast<char>(lParam
));
6003 case SCI_SETSTYLING
:
6004 pdoc
->SetStyleFor(static_cast<int>(wParam
), static_cast<char>(lParam
));
6007 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6010 pdoc
->SetStyles(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6013 case SCI_SETBUFFEREDDRAW
:
6014 view
.bufferedDraw
= wParam
!= 0;
6017 case SCI_GETBUFFEREDDRAW
:
6018 return view
.bufferedDraw
;
6020 case SCI_GETTWOPHASEDRAW
:
6021 return view
.phasesDraw
== EditView::phasesTwo
;
6023 case SCI_SETTWOPHASEDRAW
:
6024 if (view
.SetTwoPhaseDraw(wParam
!= 0))
6025 InvalidateStyleRedraw();
6028 case SCI_GETPHASESDRAW
:
6029 return view
.phasesDraw
;
6031 case SCI_SETPHASESDRAW
:
6032 if (view
.SetPhasesDraw(static_cast<int>(wParam
)))
6033 InvalidateStyleRedraw();
6036 case SCI_SETFONTQUALITY
:
6037 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
6038 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
6039 InvalidateStyleRedraw();
6042 case SCI_GETFONTQUALITY
:
6043 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
6045 case SCI_SETTABWIDTH
:
6047 pdoc
->tabInChars
= static_cast<int>(wParam
);
6048 if (pdoc
->indentInChars
== 0)
6049 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6051 InvalidateStyleRedraw();
6054 case SCI_GETTABWIDTH
:
6055 return pdoc
->tabInChars
;
6057 case SCI_CLEARTABSTOPS
:
6058 if (view
.ClearTabstops(static_cast<int>(wParam
))) {
6059 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6060 NotifyModified(pdoc
, mh
, NULL
);
6064 case SCI_ADDTABSTOP
:
6065 if (view
.AddTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
))) {
6066 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6067 NotifyModified(pdoc
, mh
, NULL
);
6071 case SCI_GETNEXTTABSTOP
:
6072 return view
.GetNextTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
));
6075 pdoc
->indentInChars
= static_cast<int>(wParam
);
6076 if (pdoc
->indentInChars
!= 0)
6077 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6079 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6080 InvalidateStyleRedraw();
6084 return pdoc
->indentInChars
;
6086 case SCI_SETUSETABS
:
6087 pdoc
->useTabs
= wParam
!= 0;
6088 InvalidateStyleRedraw();
6091 case SCI_GETUSETABS
:
6092 return pdoc
->useTabs
;
6094 case SCI_SETLINEINDENTATION
:
6095 pdoc
->SetLineIndentation(static_cast<int>(wParam
), static_cast<int>(lParam
));
6098 case SCI_GETLINEINDENTATION
:
6099 return pdoc
->GetLineIndentation(static_cast<int>(wParam
));
6101 case SCI_GETLINEINDENTPOSITION
:
6102 return pdoc
->GetLineIndentPosition(static_cast<int>(wParam
));
6104 case SCI_SETTABINDENTS
:
6105 pdoc
->tabIndents
= wParam
!= 0;
6108 case SCI_GETTABINDENTS
:
6109 return pdoc
->tabIndents
;
6111 case SCI_SETBACKSPACEUNINDENTS
:
6112 pdoc
->backspaceUnindents
= wParam
!= 0;
6115 case SCI_GETBACKSPACEUNINDENTS
:
6116 return pdoc
->backspaceUnindents
;
6118 case SCI_SETMOUSEDWELLTIME
:
6119 dwellDelay
= static_cast<int>(wParam
);
6120 ticksToDwell
= dwellDelay
;
6123 case SCI_GETMOUSEDWELLTIME
:
6126 case SCI_WORDSTARTPOSITION
:
6127 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), -1, lParam
!= 0);
6129 case SCI_WORDENDPOSITION
:
6130 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), 1, lParam
!= 0);
6132 case SCI_SETWRAPMODE
:
6133 if (vs
.SetWrapState(static_cast<int>(wParam
))) {
6135 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6136 InvalidateStyleRedraw();
6137 ReconfigureScrollBars();
6141 case SCI_GETWRAPMODE
:
6142 return vs
.wrapState
;
6144 case SCI_SETWRAPVISUALFLAGS
:
6145 if (vs
.SetWrapVisualFlags(static_cast<int>(wParam
))) {
6146 InvalidateStyleRedraw();
6147 ReconfigureScrollBars();
6151 case SCI_GETWRAPVISUALFLAGS
:
6152 return vs
.wrapVisualFlags
;
6154 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6155 if (vs
.SetWrapVisualFlagsLocation(static_cast<int>(wParam
))) {
6156 InvalidateStyleRedraw();
6160 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6161 return vs
.wrapVisualFlagsLocation
;
6163 case SCI_SETWRAPSTARTINDENT
:
6164 if (vs
.SetWrapVisualStartIndent(static_cast<int>(wParam
))) {
6165 InvalidateStyleRedraw();
6166 ReconfigureScrollBars();
6170 case SCI_GETWRAPSTARTINDENT
:
6171 return vs
.wrapVisualStartIndent
;
6173 case SCI_SETWRAPINDENTMODE
:
6174 if (vs
.SetWrapIndentMode(static_cast<int>(wParam
))) {
6175 InvalidateStyleRedraw();
6176 ReconfigureScrollBars();
6180 case SCI_GETWRAPINDENTMODE
:
6181 return vs
.wrapIndentMode
;
6183 case SCI_SETLAYOUTCACHE
:
6184 view
.llc
.SetLevel(static_cast<int>(wParam
));
6187 case SCI_GETLAYOUTCACHE
:
6188 return view
.llc
.GetLevel();
6190 case SCI_SETPOSITIONCACHE
:
6191 view
.posCache
.SetSize(wParam
);
6194 case SCI_GETPOSITIONCACHE
:
6195 return view
.posCache
.GetSize();
6197 case SCI_SETSCROLLWIDTH
:
6198 PLATFORM_ASSERT(wParam
> 0);
6199 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6200 view
.lineWidthMaxSeen
= 0;
6201 scrollWidth
= static_cast<int>(wParam
);
6206 case SCI_GETSCROLLWIDTH
:
6209 case SCI_SETSCROLLWIDTHTRACKING
:
6210 trackLineWidth
= wParam
!= 0;
6213 case SCI_GETSCROLLWIDTHTRACKING
:
6214 return trackLineWidth
;
6220 case SCI_LINESSPLIT
:
6221 LinesSplit(static_cast<int>(wParam
));
6225 PLATFORM_ASSERT(wParam
< vs
.styles
.size());
6226 PLATFORM_ASSERT(lParam
);
6227 return TextWidth(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6229 case SCI_TEXTHEIGHT
:
6231 return vs
.lineHeight
;
6233 case SCI_SETENDATLASTLINE
:
6234 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6235 if (endAtLastLine
!= (wParam
!= 0)) {
6236 endAtLastLine
= wParam
!= 0;
6241 case SCI_GETENDATLASTLINE
:
6242 return endAtLastLine
;
6244 case SCI_SETCARETSTICKY
:
6245 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
6246 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
6247 caretSticky
= static_cast<int>(wParam
);
6251 case SCI_GETCARETSTICKY
:
6254 case SCI_TOGGLECARETSTICKY
:
6255 caretSticky
= !caretSticky
;
6259 return pdoc
->GetColumn(static_cast<int>(wParam
));
6261 case SCI_FINDCOLUMN
:
6262 return pdoc
->FindColumn(static_cast<int>(wParam
), static_cast<int>(lParam
));
6264 case SCI_SETHSCROLLBAR
:
6265 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6266 horizontalScrollBarVisible
= wParam
!= 0;
6268 ReconfigureScrollBars();
6272 case SCI_GETHSCROLLBAR
:
6273 return horizontalScrollBarVisible
;
6275 case SCI_SETVSCROLLBAR
:
6276 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6277 verticalScrollBarVisible
= wParam
!= 0;
6279 ReconfigureScrollBars();
6280 if (verticalScrollBarVisible
)
6281 SetVerticalScrollPos();
6285 case SCI_GETVSCROLLBAR
:
6286 return verticalScrollBarVisible
;
6288 case SCI_SETINDENTATIONGUIDES
:
6289 vs
.viewIndentationGuides
= IndentView(wParam
);
6293 case SCI_GETINDENTATIONGUIDES
:
6294 return vs
.viewIndentationGuides
;
6296 case SCI_SETHIGHLIGHTGUIDE
:
6297 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6298 highlightGuideColumn
= static_cast<int>(wParam
);
6303 case SCI_GETHIGHLIGHTGUIDE
:
6304 return highlightGuideColumn
;
6306 case SCI_GETLINEENDPOSITION
:
6307 return pdoc
->LineEnd(static_cast<int>(wParam
));
6309 case SCI_SETCODEPAGE
:
6310 if (ValidCodePage(static_cast<int>(wParam
))) {
6311 if (pdoc
->SetDBCSCodePage(static_cast<int>(wParam
))) {
6313 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6314 SetAnnotationHeights(0, pdoc
->LinesTotal());
6315 InvalidateStyleRedraw();
6316 SetRepresentations();
6321 case SCI_GETCODEPAGE
:
6322 return pdoc
->dbcsCodePage
;
6324 case SCI_SETIMEINTERACTION
:
6325 imeInteraction
= static_cast<EditModel::IMEInteraction
>(wParam
);
6328 case SCI_GETIMEINTERACTION
:
6329 return imeInteraction
;
6331 #ifdef INCLUDE_DEPRECATED_FEATURES
6332 case SCI_SETUSEPALETTE
:
6333 InvalidateStyleRedraw();
6336 case SCI_GETUSEPALETTE
:
6340 // Marker definition and setting
6341 case SCI_MARKERDEFINE
:
6342 if (wParam
<= MARKER_MAX
) {
6343 vs
.markers
[wParam
].markType
= static_cast<int>(lParam
);
6344 vs
.CalcLargestMarkerHeight();
6346 InvalidateStyleData();
6350 case SCI_MARKERSYMBOLDEFINED
:
6351 if (wParam
<= MARKER_MAX
)
6352 return vs
.markers
[wParam
].markType
;
6356 case SCI_MARKERSETFORE
:
6357 if (wParam
<= MARKER_MAX
)
6358 vs
.markers
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6359 InvalidateStyleData();
6362 case SCI_MARKERSETBACKSELECTED
:
6363 if (wParam
<= MARKER_MAX
)
6364 vs
.markers
[wParam
].backSelected
= ColourDesired(static_cast<long>(lParam
));
6365 InvalidateStyleData();
6368 case SCI_MARKERENABLEHIGHLIGHT
:
6369 marginView
.highlightDelimiter
.isEnabled
= wParam
== 1;
6372 case SCI_MARKERSETBACK
:
6373 if (wParam
<= MARKER_MAX
)
6374 vs
.markers
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6375 InvalidateStyleData();
6378 case SCI_MARKERSETALPHA
:
6379 if (wParam
<= MARKER_MAX
)
6380 vs
.markers
[wParam
].alpha
= static_cast<int>(lParam
);
6381 InvalidateStyleRedraw();
6383 case SCI_MARKERADD
: {
6384 int markerID
= pdoc
->AddMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6387 case SCI_MARKERADDSET
:
6389 pdoc
->AddMarkSet(static_cast<int>(wParam
), static_cast<int>(lParam
));
6392 case SCI_MARKERDELETE
:
6393 pdoc
->DeleteMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6396 case SCI_MARKERDELETEALL
:
6397 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6401 return pdoc
->GetMark(static_cast<int>(wParam
));
6403 case SCI_MARKERNEXT
:
6404 return pdoc
->MarkerNext(static_cast<int>(wParam
), static_cast<int>(lParam
));
6406 case SCI_MARKERPREVIOUS
: {
6407 for (int iLine
= static_cast<int>(wParam
); iLine
>= 0; iLine
--) {
6408 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6414 case SCI_MARKERDEFINEPIXMAP
:
6415 if (wParam
<= MARKER_MAX
) {
6416 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6417 vs
.CalcLargestMarkerHeight();
6419 InvalidateStyleData();
6423 case SCI_RGBAIMAGESETWIDTH
:
6424 sizeRGBAImage
.x
= static_cast<XYPOSITION
>(wParam
);
6427 case SCI_RGBAIMAGESETHEIGHT
:
6428 sizeRGBAImage
.y
= static_cast<XYPOSITION
>(wParam
);
6431 case SCI_RGBAIMAGESETSCALE
:
6432 scaleRGBAImage
= static_cast<float>(wParam
);
6435 case SCI_MARKERDEFINERGBAIMAGE
:
6436 if (wParam
<= MARKER_MAX
) {
6437 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0f
, reinterpret_cast<unsigned char *>(lParam
));
6438 vs
.CalcLargestMarkerHeight();
6440 InvalidateStyleData();
6444 case SCI_SETMARGINTYPEN
:
6445 if (ValidMargin(wParam
)) {
6446 vs
.ms
[wParam
].style
= static_cast<int>(lParam
);
6447 InvalidateStyleRedraw();
6451 case SCI_GETMARGINTYPEN
:
6452 if (ValidMargin(wParam
))
6453 return vs
.ms
[wParam
].style
;
6457 case SCI_SETMARGINWIDTHN
:
6458 if (ValidMargin(wParam
)) {
6459 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6460 if (vs
.ms
[wParam
].width
!= lParam
) {
6461 lastXChosen
+= static_cast<int>(lParam
) - vs
.ms
[wParam
].width
;
6462 vs
.ms
[wParam
].width
= static_cast<int>(lParam
);
6463 InvalidateStyleRedraw();
6468 case SCI_GETMARGINWIDTHN
:
6469 if (ValidMargin(wParam
))
6470 return vs
.ms
[wParam
].width
;
6474 case SCI_SETMARGINMASKN
:
6475 if (ValidMargin(wParam
)) {
6476 vs
.ms
[wParam
].mask
= static_cast<int>(lParam
);
6477 InvalidateStyleRedraw();
6481 case SCI_GETMARGINMASKN
:
6482 if (ValidMargin(wParam
))
6483 return vs
.ms
[wParam
].mask
;
6487 case SCI_SETMARGINSENSITIVEN
:
6488 if (ValidMargin(wParam
)) {
6489 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6490 InvalidateStyleRedraw();
6494 case SCI_GETMARGINSENSITIVEN
:
6495 if (ValidMargin(wParam
))
6496 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6500 case SCI_SETMARGINCURSORN
:
6501 if (ValidMargin(wParam
))
6502 vs
.ms
[wParam
].cursor
= static_cast<int>(lParam
);
6505 case SCI_GETMARGINCURSORN
:
6506 if (ValidMargin(wParam
))
6507 return vs
.ms
[wParam
].cursor
;
6511 case SCI_STYLECLEARALL
:
6513 InvalidateStyleRedraw();
6516 case SCI_STYLESETFORE
:
6517 case SCI_STYLESETBACK
:
6518 case SCI_STYLESETBOLD
:
6519 case SCI_STYLESETWEIGHT
:
6520 case SCI_STYLESETITALIC
:
6521 case SCI_STYLESETEOLFILLED
:
6522 case SCI_STYLESETSIZE
:
6523 case SCI_STYLESETSIZEFRACTIONAL
:
6524 case SCI_STYLESETFONT
:
6525 case SCI_STYLESETUNDERLINE
:
6526 case SCI_STYLESETCASE
:
6527 case SCI_STYLESETCHARACTERSET
:
6528 case SCI_STYLESETVISIBLE
:
6529 case SCI_STYLESETCHANGEABLE
:
6530 case SCI_STYLESETHOTSPOT
:
6531 StyleSetMessage(iMessage
, wParam
, lParam
);
6534 case SCI_STYLEGETFORE
:
6535 case SCI_STYLEGETBACK
:
6536 case SCI_STYLEGETBOLD
:
6537 case SCI_STYLEGETWEIGHT
:
6538 case SCI_STYLEGETITALIC
:
6539 case SCI_STYLEGETEOLFILLED
:
6540 case SCI_STYLEGETSIZE
:
6541 case SCI_STYLEGETSIZEFRACTIONAL
:
6542 case SCI_STYLEGETFONT
:
6543 case SCI_STYLEGETUNDERLINE
:
6544 case SCI_STYLEGETCASE
:
6545 case SCI_STYLEGETCHARACTERSET
:
6546 case SCI_STYLEGETVISIBLE
:
6547 case SCI_STYLEGETCHANGEABLE
:
6548 case SCI_STYLEGETHOTSPOT
:
6549 return StyleGetMessage(iMessage
, wParam
, lParam
);
6551 case SCI_STYLERESETDEFAULT
:
6552 vs
.ResetDefaultStyle();
6553 InvalidateStyleRedraw();
6555 case SCI_SETSTYLEBITS
:
6556 vs
.EnsureStyle(0xff);
6559 case SCI_GETSTYLEBITS
:
6562 case SCI_SETLINESTATE
:
6563 return pdoc
->SetLineState(static_cast<int>(wParam
), static_cast<int>(lParam
));
6565 case SCI_GETLINESTATE
:
6566 return pdoc
->GetLineState(static_cast<int>(wParam
));
6568 case SCI_GETMAXLINESTATE
:
6569 return pdoc
->GetMaxLineState();
6571 case SCI_GETCARETLINEVISIBLE
:
6572 return vs
.showCaretLineBackground
;
6573 case SCI_SETCARETLINEVISIBLE
:
6574 vs
.showCaretLineBackground
= wParam
!= 0;
6575 InvalidateStyleRedraw();
6577 case SCI_GETCARETLINEVISIBLEALWAYS
:
6578 return vs
.alwaysShowCaretLineBackground
;
6579 case SCI_SETCARETLINEVISIBLEALWAYS
:
6580 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
6581 InvalidateStyleRedraw();
6584 case SCI_GETCARETLINEBACK
:
6585 return vs
.caretLineBackground
.AsLong();
6586 case SCI_SETCARETLINEBACK
:
6587 vs
.caretLineBackground
= static_cast<int>(wParam
);
6588 InvalidateStyleRedraw();
6590 case SCI_GETCARETLINEBACKALPHA
:
6591 return vs
.caretLineAlpha
;
6592 case SCI_SETCARETLINEBACKALPHA
:
6593 vs
.caretLineAlpha
= static_cast<int>(wParam
);
6594 InvalidateStyleRedraw();
6599 case SCI_VISIBLEFROMDOCLINE
:
6600 return cs
.DisplayFromDoc(static_cast<int>(wParam
));
6602 case SCI_DOCLINEFROMVISIBLE
:
6603 return cs
.DocFromDisplay(static_cast<int>(wParam
));
6606 return WrapCount(static_cast<int>(wParam
));
6608 case SCI_SETFOLDLEVEL
: {
6609 int prev
= pdoc
->SetLevel(static_cast<int>(wParam
), static_cast<int>(lParam
));
6610 if (prev
!= static_cast<int>(lParam
))
6615 case SCI_GETFOLDLEVEL
:
6616 return pdoc
->GetLevel(static_cast<int>(wParam
));
6618 case SCI_GETLASTCHILD
:
6619 return pdoc
->GetLastChild(static_cast<int>(wParam
), static_cast<int>(lParam
));
6621 case SCI_GETFOLDPARENT
:
6622 return pdoc
->GetFoldParent(static_cast<int>(wParam
));
6625 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), true);
6632 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), false);
6637 case SCI_GETLINEVISIBLE
:
6638 return cs
.GetVisible(static_cast<int>(wParam
));
6640 case SCI_GETALLLINESVISIBLE
:
6641 return cs
.HiddenLines() ? 0 : 1;
6643 case SCI_SETFOLDEXPANDED
:
6644 SetFoldExpanded(static_cast<int>(wParam
), lParam
!= 0);
6647 case SCI_GETFOLDEXPANDED
:
6648 return cs
.GetExpanded(static_cast<int>(wParam
));
6650 case SCI_SETAUTOMATICFOLD
:
6651 foldAutomatic
= static_cast<int>(wParam
);
6654 case SCI_GETAUTOMATICFOLD
:
6655 return foldAutomatic
;
6657 case SCI_SETFOLDFLAGS
:
6658 foldFlags
= static_cast<int>(wParam
);
6662 case SCI_TOGGLEFOLD
:
6663 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
6667 FoldLine(static_cast<int>(wParam
), static_cast<int>(lParam
));
6670 case SCI_FOLDCHILDREN
:
6671 FoldExpand(static_cast<int>(wParam
), static_cast<int>(lParam
), pdoc
->GetLevel(static_cast<int>(wParam
)));
6675 FoldAll(static_cast<int>(wParam
));
6678 case SCI_EXPANDCHILDREN
:
6679 FoldExpand(static_cast<int>(wParam
), SC_FOLDACTION_EXPAND
, static_cast<int>(lParam
));
6682 case SCI_CONTRACTEDFOLDNEXT
:
6683 return ContractedFoldNext(static_cast<int>(wParam
));
6685 case SCI_ENSUREVISIBLE
:
6686 EnsureLineVisible(static_cast<int>(wParam
), false);
6689 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6690 EnsureLineVisible(static_cast<int>(wParam
), true);
6693 case SCI_SCROLLRANGE
:
6694 ScrollRange(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
6697 case SCI_SEARCHANCHOR
:
6701 case SCI_SEARCHNEXT
:
6702 case SCI_SEARCHPREV
:
6703 return SearchText(iMessage
, wParam
, lParam
);
6705 case SCI_SETXCARETPOLICY
:
6706 caretXPolicy
= static_cast<int>(wParam
);
6707 caretXSlop
= static_cast<int>(lParam
);
6710 case SCI_SETYCARETPOLICY
:
6711 caretYPolicy
= static_cast<int>(wParam
);
6712 caretYSlop
= static_cast<int>(lParam
);
6715 case SCI_SETVISIBLEPOLICY
:
6716 visiblePolicy
= static_cast<int>(wParam
);
6717 visibleSlop
= static_cast<int>(lParam
);
6720 case SCI_LINESONSCREEN
:
6721 return LinesOnScreen();
6723 case SCI_SETSELFORE
:
6724 vs
.selColours
.fore
= ColourOptional(wParam
, lParam
);
6725 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(lParam
));
6726 InvalidateStyleRedraw();
6729 case SCI_SETSELBACK
:
6730 vs
.selColours
.back
= ColourOptional(wParam
, lParam
);
6731 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(lParam
));
6732 InvalidateStyleRedraw();
6735 case SCI_SETSELALPHA
:
6736 vs
.selAlpha
= static_cast<int>(wParam
);
6737 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
6738 InvalidateStyleRedraw();
6741 case SCI_GETSELALPHA
:
6744 case SCI_GETSELEOLFILLED
:
6745 return vs
.selEOLFilled
;
6747 case SCI_SETSELEOLFILLED
:
6748 vs
.selEOLFilled
= wParam
!= 0;
6749 InvalidateStyleRedraw();
6752 case SCI_SETWHITESPACEFORE
:
6753 vs
.whitespaceColours
.fore
= ColourOptional(wParam
, lParam
);
6754 InvalidateStyleRedraw();
6757 case SCI_SETWHITESPACEBACK
:
6758 vs
.whitespaceColours
.back
= ColourOptional(wParam
, lParam
);
6759 InvalidateStyleRedraw();
6762 case SCI_SETCARETFORE
:
6763 vs
.caretcolour
= ColourDesired(static_cast<long>(wParam
));
6764 InvalidateStyleRedraw();
6767 case SCI_GETCARETFORE
:
6768 return vs
.caretcolour
.AsLong();
6770 case SCI_SETCARETSTYLE
:
6771 if (wParam
<= CARETSTYLE_BLOCK
)
6772 vs
.caretStyle
= static_cast<int>(wParam
);
6774 /* Default to the line caret */
6775 vs
.caretStyle
= CARETSTYLE_LINE
;
6776 InvalidateStyleRedraw();
6779 case SCI_GETCARETSTYLE
:
6780 return vs
.caretStyle
;
6782 case SCI_SETCARETWIDTH
:
6783 if (static_cast<int>(wParam
) <= 0)
6785 else if (wParam
>= 3)
6788 vs
.caretWidth
= static_cast<int>(wParam
);
6789 InvalidateStyleRedraw();
6792 case SCI_GETCARETWIDTH
:
6793 return vs
.caretWidth
;
6795 case SCI_ASSIGNCMDKEY
:
6796 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
6797 Platform::HighShortFromLong(static_cast<long>(wParam
)), static_cast<unsigned int>(lParam
));
6800 case SCI_CLEARCMDKEY
:
6801 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
6802 Platform::HighShortFromLong(static_cast<long>(wParam
)), SCI_NULL
);
6805 case SCI_CLEARALLCMDKEYS
:
6809 case SCI_INDICSETSTYLE
:
6810 if (wParam
<= INDIC_MAX
) {
6811 vs
.indicators
[wParam
].sacNormal
.style
= static_cast<int>(lParam
);
6812 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
6813 InvalidateStyleRedraw();
6817 case SCI_INDICGETSTYLE
:
6818 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.style
: 0;
6820 case SCI_INDICSETFORE
:
6821 if (wParam
<= INDIC_MAX
) {
6822 vs
.indicators
[wParam
].sacNormal
.fore
= ColourDesired(static_cast<long>(lParam
));
6823 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
6824 InvalidateStyleRedraw();
6828 case SCI_INDICGETFORE
:
6829 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.fore
.AsLong() : 0;
6831 case SCI_INDICSETHOVERSTYLE
:
6832 if (wParam
<= INDIC_MAX
) {
6833 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
6834 InvalidateStyleRedraw();
6838 case SCI_INDICGETHOVERSTYLE
:
6839 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.style
: 0;
6841 case SCI_INDICSETHOVERFORE
:
6842 if (wParam
<= INDIC_MAX
) {
6843 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
6844 InvalidateStyleRedraw();
6848 case SCI_INDICGETHOVERFORE
:
6849 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.fore
.AsLong() : 0;
6851 case SCI_INDICSETFLAGS
:
6852 if (wParam
<= INDIC_MAX
) {
6853 vs
.indicators
[wParam
].SetFlags(static_cast<int>(lParam
));
6854 InvalidateStyleRedraw();
6858 case SCI_INDICGETFLAGS
:
6859 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].Flags() : 0;
6861 case SCI_INDICSETUNDER
:
6862 if (wParam
<= INDIC_MAX
) {
6863 vs
.indicators
[wParam
].under
= lParam
!= 0;
6864 InvalidateStyleRedraw();
6868 case SCI_INDICGETUNDER
:
6869 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
6871 case SCI_INDICSETALPHA
:
6872 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
6873 vs
.indicators
[wParam
].fillAlpha
= static_cast<int>(lParam
);
6874 InvalidateStyleRedraw();
6878 case SCI_INDICGETALPHA
:
6879 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
6881 case SCI_INDICSETOUTLINEALPHA
:
6882 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
6883 vs
.indicators
[wParam
].outlineAlpha
= static_cast<int>(lParam
);
6884 InvalidateStyleRedraw();
6888 case SCI_INDICGETOUTLINEALPHA
:
6889 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
6891 case SCI_SETINDICATORCURRENT
:
6892 pdoc
->decorations
.SetCurrentIndicator(static_cast<int>(wParam
));
6894 case SCI_GETINDICATORCURRENT
:
6895 return pdoc
->decorations
.GetCurrentIndicator();
6896 case SCI_SETINDICATORVALUE
:
6897 pdoc
->decorations
.SetCurrentValue(static_cast<int>(wParam
));
6899 case SCI_GETINDICATORVALUE
:
6900 return pdoc
->decorations
.GetCurrentValue();
6902 case SCI_INDICATORFILLRANGE
:
6903 pdoc
->DecorationFillRange(static_cast<int>(wParam
), pdoc
->decorations
.GetCurrentValue(), static_cast<int>(lParam
));
6906 case SCI_INDICATORCLEARRANGE
:
6907 pdoc
->DecorationFillRange(static_cast<int>(wParam
), 0, static_cast<int>(lParam
));
6910 case SCI_INDICATORALLONFOR
:
6911 return pdoc
->decorations
.AllOnFor(static_cast<int>(wParam
));
6913 case SCI_INDICATORVALUEAT
:
6914 return pdoc
->decorations
.ValueAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
6916 case SCI_INDICATORSTART
:
6917 return pdoc
->decorations
.Start(static_cast<int>(wParam
), static_cast<int>(lParam
));
6919 case SCI_INDICATOREND
:
6920 return pdoc
->decorations
.End(static_cast<int>(wParam
), static_cast<int>(lParam
));
6923 case SCI_LINEDOWNEXTEND
:
6925 case SCI_PARADOWNEXTEND
:
6927 case SCI_LINEUPEXTEND
:
6929 case SCI_PARAUPEXTEND
:
6931 case SCI_CHARLEFTEXTEND
:
6933 case SCI_CHARRIGHTEXTEND
:
6935 case SCI_WORDLEFTEXTEND
:
6937 case SCI_WORDRIGHTEXTEND
:
6938 case SCI_WORDLEFTEND
:
6939 case SCI_WORDLEFTENDEXTEND
:
6940 case SCI_WORDRIGHTEND
:
6941 case SCI_WORDRIGHTENDEXTEND
:
6943 case SCI_HOMEEXTEND
:
6945 case SCI_LINEENDEXTEND
:
6947 case SCI_HOMEWRAPEXTEND
:
6948 case SCI_LINEENDWRAP
:
6949 case SCI_LINEENDWRAPEXTEND
:
6950 case SCI_DOCUMENTSTART
:
6951 case SCI_DOCUMENTSTARTEXTEND
:
6952 case SCI_DOCUMENTEND
:
6953 case SCI_DOCUMENTENDEXTEND
:
6954 case SCI_SCROLLTOSTART
:
6955 case SCI_SCROLLTOEND
:
6957 case SCI_STUTTEREDPAGEUP
:
6958 case SCI_STUTTEREDPAGEUPEXTEND
:
6959 case SCI_STUTTEREDPAGEDOWN
:
6960 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6963 case SCI_PAGEUPEXTEND
:
6965 case SCI_PAGEDOWNEXTEND
:
6966 case SCI_EDITTOGGLEOVERTYPE
:
6968 case SCI_DELETEBACK
:
6974 case SCI_VCHOMEEXTEND
:
6975 case SCI_VCHOMEWRAP
:
6976 case SCI_VCHOMEWRAPEXTEND
:
6977 case SCI_VCHOMEDISPLAY
:
6978 case SCI_VCHOMEDISPLAYEXTEND
:
6981 case SCI_DELWORDLEFT
:
6982 case SCI_DELWORDRIGHT
:
6983 case SCI_DELWORDRIGHTEND
:
6984 case SCI_DELLINELEFT
:
6985 case SCI_DELLINERIGHT
:
6988 case SCI_LINEDELETE
:
6989 case SCI_LINETRANSPOSE
:
6990 case SCI_LINEDUPLICATE
:
6993 case SCI_LINESCROLLDOWN
:
6994 case SCI_LINESCROLLUP
:
6995 case SCI_WORDPARTLEFT
:
6996 case SCI_WORDPARTLEFTEXTEND
:
6997 case SCI_WORDPARTRIGHT
:
6998 case SCI_WORDPARTRIGHTEXTEND
:
6999 case SCI_DELETEBACKNOTLINE
:
7000 case SCI_HOMEDISPLAY
:
7001 case SCI_HOMEDISPLAYEXTEND
:
7002 case SCI_LINEENDDISPLAY
:
7003 case SCI_LINEENDDISPLAYEXTEND
:
7004 case SCI_LINEDOWNRECTEXTEND
:
7005 case SCI_LINEUPRECTEXTEND
:
7006 case SCI_CHARLEFTRECTEXTEND
:
7007 case SCI_CHARRIGHTRECTEXTEND
:
7008 case SCI_HOMERECTEXTEND
:
7009 case SCI_VCHOMERECTEXTEND
:
7010 case SCI_LINEENDRECTEXTEND
:
7011 case SCI_PAGEUPRECTEXTEND
:
7012 case SCI_PAGEDOWNRECTEXTEND
:
7013 case SCI_SELECTIONDUPLICATE
:
7014 return KeyCommand(iMessage
);
7016 case SCI_BRACEHIGHLIGHT
:
7017 SetBraceHighlight(static_cast<int>(wParam
), static_cast<int>(lParam
), STYLE_BRACELIGHT
);
7020 case SCI_BRACEHIGHLIGHTINDICATOR
:
7021 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7022 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
7023 vs
.braceHighlightIndicator
= static_cast<int>(lParam
);
7027 case SCI_BRACEBADLIGHT
:
7028 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7031 case SCI_BRACEBADLIGHTINDICATOR
:
7032 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7033 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
7034 vs
.braceBadLightIndicator
= static_cast<int>(lParam
);
7038 case SCI_BRACEMATCH
:
7039 // wParam is position of char to find brace for,
7040 // lParam is maximum amount of text to restyle to find it
7041 return pdoc
->BraceMatch(static_cast<int>(wParam
), static_cast<int>(lParam
));
7043 case SCI_GETVIEWEOL
:
7046 case SCI_SETVIEWEOL
:
7047 vs
.viewEOL
= wParam
!= 0;
7048 InvalidateStyleRedraw();
7052 vs
.zoomLevel
= static_cast<int>(wParam
);
7053 InvalidateStyleRedraw();
7058 return vs
.zoomLevel
;
7060 case SCI_GETEDGECOLUMN
:
7063 case SCI_SETEDGECOLUMN
:
7064 vs
.theEdge
= static_cast<int>(wParam
);
7065 InvalidateStyleRedraw();
7068 case SCI_GETEDGEMODE
:
7069 return vs
.edgeState
;
7071 case SCI_SETEDGEMODE
:
7072 vs
.edgeState
= static_cast<int>(wParam
);
7073 InvalidateStyleRedraw();
7076 case SCI_GETEDGECOLOUR
:
7077 return vs
.edgecolour
.AsLong();
7079 case SCI_SETEDGECOLOUR
:
7080 vs
.edgecolour
= ColourDesired(static_cast<long>(wParam
));
7081 InvalidateStyleRedraw();
7084 case SCI_GETDOCPOINTER
:
7085 return reinterpret_cast<sptr_t
>(pdoc
);
7087 case SCI_SETDOCPOINTER
:
7089 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7092 case SCI_CREATEDOCUMENT
: {
7093 Document
*doc
= new Document();
7095 return reinterpret_cast<sptr_t
>(doc
);
7098 case SCI_ADDREFDOCUMENT
:
7099 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7102 case SCI_RELEASEDOCUMENT
:
7103 (reinterpret_cast<Document
*>(lParam
))->Release();
7106 case SCI_CREATELOADER
: {
7107 Document
*doc
= new Document();
7109 doc
->Allocate(static_cast<int>(wParam
));
7110 doc
->SetUndoCollection(false);
7111 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
7114 case SCI_SETMODEVENTMASK
:
7115 modEventMask
= static_cast<int>(wParam
);
7118 case SCI_GETMODEVENTMASK
:
7119 return modEventMask
;
7121 case SCI_CONVERTEOLS
:
7122 pdoc
->ConvertLineEnds(static_cast<int>(wParam
));
7123 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7126 case SCI_SETLENGTHFORENCODE
:
7127 lengthForEncode
= static_cast<int>(wParam
);
7130 case SCI_SELECTIONISRECTANGLE
:
7131 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7133 case SCI_SETSELECTIONMODE
: {
7136 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7137 sel
.selType
= Selection::selStream
;
7139 case SC_SEL_RECTANGLE
:
7140 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7141 sel
.selType
= Selection::selRectangle
;
7144 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7145 sel
.selType
= Selection::selLines
;
7148 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7149 sel
.selType
= Selection::selThin
;
7152 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7153 sel
.selType
= Selection::selStream
;
7155 InvalidateSelection(sel
.RangeMain(), true);
7158 case SCI_GETSELECTIONMODE
:
7159 switch (sel
.selType
) {
7160 case Selection::selStream
:
7161 return SC_SEL_STREAM
;
7162 case Selection::selRectangle
:
7163 return SC_SEL_RECTANGLE
;
7164 case Selection::selLines
:
7165 return SC_SEL_LINES
;
7166 case Selection::selThin
:
7169 return SC_SEL_STREAM
;
7171 case SCI_GETLINESELSTARTPOSITION
:
7172 case SCI_GETLINESELENDPOSITION
: {
7173 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(static_cast<int>(wParam
))),
7174 SelectionPosition(pdoc
->LineEnd(static_cast<int>(wParam
))));
7175 for (size_t r
=0; r
<sel
.Count(); r
++) {
7176 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7177 if (portion
.start
.IsValid()) {
7178 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
7181 return INVALID_POSITION
;
7184 case SCI_SETOVERTYPE
:
7185 inOverstrike
= wParam
!= 0;
7188 case SCI_GETOVERTYPE
:
7189 return inOverstrike
? 1 : 0;
7192 SetFocusState(wParam
!= 0);
7199 errorStatus
= static_cast<int>(wParam
);
7205 case SCI_SETMOUSEDOWNCAPTURES
:
7206 mouseDownCaptures
= wParam
!= 0;
7209 case SCI_GETMOUSEDOWNCAPTURES
:
7210 return mouseDownCaptures
;
7213 cursorMode
= static_cast<int>(wParam
);
7214 DisplayCursor(Window::cursorText
);
7220 case SCI_SETCONTROLCHARSYMBOL
:
7221 vs
.controlCharSymbol
= static_cast<int>(wParam
);
7222 InvalidateStyleRedraw();
7225 case SCI_GETCONTROLCHARSYMBOL
:
7226 return vs
.controlCharSymbol
;
7228 case SCI_SETREPRESENTATION
:
7229 reprs
.SetRepresentation(reinterpret_cast<const char *>(wParam
), CharPtrFromSPtr(lParam
));
7232 case SCI_GETREPRESENTATION
: {
7233 const Representation
*repr
= reprs
.RepresentationFromCharacter(
7234 reinterpret_cast<const char *>(wParam
), UTF8MaxBytes
);
7236 return StringResult(lParam
, repr
->stringRep
.c_str());
7241 case SCI_CLEARREPRESENTATION
:
7242 reprs
.ClearRepresentation(reinterpret_cast<const char *>(wParam
));
7245 case SCI_STARTRECORD
:
7246 recordingMacro
= true;
7249 case SCI_STOPRECORD
:
7250 recordingMacro
= false;
7253 case SCI_MOVECARETINSIDEVIEW
:
7254 MoveCaretInsideView();
7257 case SCI_SETFOLDMARGINCOLOUR
:
7258 vs
.foldmarginColour
= ColourOptional(wParam
, lParam
);
7259 InvalidateStyleRedraw();
7262 case SCI_SETFOLDMARGINHICOLOUR
:
7263 vs
.foldmarginHighlightColour
= ColourOptional(wParam
, lParam
);
7264 InvalidateStyleRedraw();
7267 case SCI_SETHOTSPOTACTIVEFORE
:
7268 vs
.hotspotColours
.fore
= ColourOptional(wParam
, lParam
);
7269 InvalidateStyleRedraw();
7272 case SCI_GETHOTSPOTACTIVEFORE
:
7273 return vs
.hotspotColours
.fore
.AsLong();
7275 case SCI_SETHOTSPOTACTIVEBACK
:
7276 vs
.hotspotColours
.back
= ColourOptional(wParam
, lParam
);
7277 InvalidateStyleRedraw();
7280 case SCI_GETHOTSPOTACTIVEBACK
:
7281 return vs
.hotspotColours
.back
.AsLong();
7283 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7284 vs
.hotspotUnderline
= wParam
!= 0;
7285 InvalidateStyleRedraw();
7288 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7289 return vs
.hotspotUnderline
? 1 : 0;
7291 case SCI_SETHOTSPOTSINGLELINE
:
7292 vs
.hotspotSingleLine
= wParam
!= 0;
7293 InvalidateStyleRedraw();
7296 case SCI_GETHOTSPOTSINGLELINE
:
7297 return vs
.hotspotSingleLine
? 1 : 0;
7299 case SCI_SETPASTECONVERTENDINGS
:
7300 convertPastes
= wParam
!= 0;
7303 case SCI_GETPASTECONVERTENDINGS
:
7304 return convertPastes
? 1 : 0;
7306 case SCI_GETCHARACTERPOINTER
:
7307 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
7309 case SCI_GETRANGEPOINTER
:
7310 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7312 case SCI_GETGAPPOSITION
:
7313 return pdoc
->GapPosition();
7315 case SCI_SETEXTRAASCENT
:
7316 vs
.extraAscent
= static_cast<int>(wParam
);
7317 InvalidateStyleRedraw();
7320 case SCI_GETEXTRAASCENT
:
7321 return vs
.extraAscent
;
7323 case SCI_SETEXTRADESCENT
:
7324 vs
.extraDescent
= static_cast<int>(wParam
);
7325 InvalidateStyleRedraw();
7328 case SCI_GETEXTRADESCENT
:
7329 return vs
.extraDescent
;
7331 case SCI_MARGINSETSTYLEOFFSET
:
7332 vs
.marginStyleOffset
= static_cast<int>(wParam
);
7333 InvalidateStyleRedraw();
7336 case SCI_MARGINGETSTYLEOFFSET
:
7337 return vs
.marginStyleOffset
;
7339 case SCI_SETMARGINOPTIONS
:
7340 marginOptions
= static_cast<int>(wParam
);
7343 case SCI_GETMARGINOPTIONS
:
7344 return marginOptions
;
7346 case SCI_MARGINSETTEXT
:
7347 pdoc
->MarginSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7350 case SCI_MARGINGETTEXT
: {
7351 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7352 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7355 case SCI_MARGINSETSTYLE
:
7356 pdoc
->MarginSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7359 case SCI_MARGINGETSTYLE
: {
7360 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7364 case SCI_MARGINSETSTYLES
:
7365 pdoc
->MarginSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7368 case SCI_MARGINGETSTYLES
: {
7369 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7370 return BytesResult(lParam
, st
.styles
, st
.length
);
7373 case SCI_MARGINTEXTCLEARALL
:
7374 pdoc
->MarginClearAll();
7377 case SCI_ANNOTATIONSETTEXT
:
7378 pdoc
->AnnotationSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7381 case SCI_ANNOTATIONGETTEXT
: {
7382 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7383 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7386 case SCI_ANNOTATIONGETSTYLE
: {
7387 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7391 case SCI_ANNOTATIONSETSTYLE
:
7392 pdoc
->AnnotationSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7395 case SCI_ANNOTATIONSETSTYLES
:
7396 pdoc
->AnnotationSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7399 case SCI_ANNOTATIONGETSTYLES
: {
7400 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7401 return BytesResult(lParam
, st
.styles
, st
.length
);
7404 case SCI_ANNOTATIONGETLINES
:
7405 return pdoc
->AnnotationLines(static_cast<int>(wParam
));
7407 case SCI_ANNOTATIONCLEARALL
:
7408 pdoc
->AnnotationClearAll();
7411 case SCI_ANNOTATIONSETVISIBLE
:
7412 SetAnnotationVisible(static_cast<int>(wParam
));
7415 case SCI_ANNOTATIONGETVISIBLE
:
7416 return vs
.annotationVisible
;
7418 case SCI_ANNOTATIONSETSTYLEOFFSET
:
7419 vs
.annotationStyleOffset
= static_cast<int>(wParam
);
7420 InvalidateStyleRedraw();
7423 case SCI_ANNOTATIONGETSTYLEOFFSET
:
7424 return vs
.annotationStyleOffset
;
7426 case SCI_RELEASEALLEXTENDEDSTYLES
:
7427 vs
.ReleaseAllExtendedStyles();
7430 case SCI_ALLOCATEEXTENDEDSTYLES
:
7431 return vs
.AllocateExtendedStyles(static_cast<int>(wParam
));
7433 case SCI_ADDUNDOACTION
:
7434 pdoc
->AddUndoAction(static_cast<int>(wParam
), lParam
& UNDO_MAY_COALESCE
);
7437 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH
:
7438 mouseSelectionRectangularSwitch
= wParam
!= 0;
7441 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH
:
7442 return mouseSelectionRectangularSwitch
;
7444 case SCI_SETMULTIPLESELECTION
:
7445 multipleSelection
= wParam
!= 0;
7449 case SCI_GETMULTIPLESELECTION
:
7450 return multipleSelection
;
7452 case SCI_SETADDITIONALSELECTIONTYPING
:
7453 additionalSelectionTyping
= wParam
!= 0;
7457 case SCI_GETADDITIONALSELECTIONTYPING
:
7458 return additionalSelectionTyping
;
7460 case SCI_SETMULTIPASTE
:
7461 multiPasteMode
= static_cast<int>(wParam
);
7464 case SCI_GETMULTIPASTE
:
7465 return multiPasteMode
;
7467 case SCI_SETADDITIONALCARETSBLINK
:
7468 view
.additionalCaretsBlink
= wParam
!= 0;
7472 case SCI_GETADDITIONALCARETSBLINK
:
7473 return view
.additionalCaretsBlink
;
7475 case SCI_SETADDITIONALCARETSVISIBLE
:
7476 view
.additionalCaretsVisible
= wParam
!= 0;
7480 case SCI_GETADDITIONALCARETSVISIBLE
:
7481 return view
.additionalCaretsVisible
;
7483 case SCI_GETSELECTIONS
:
7486 case SCI_GETSELECTIONEMPTY
:
7489 case SCI_CLEARSELECTIONS
:
7494 case SCI_SETSELECTION
:
7495 sel
.SetSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7499 case SCI_ADDSELECTION
:
7500 sel
.AddSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7504 case SCI_DROPSELECTIONN
:
7505 sel
.DropSelection(static_cast<int>(wParam
));
7509 case SCI_SETMAINSELECTION
:
7510 sel
.SetMain(static_cast<int>(wParam
));
7514 case SCI_GETMAINSELECTION
:
7517 case SCI_SETSELECTIONNCARET
:
7518 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7522 case SCI_GETSELECTIONNCARET
:
7523 return sel
.Range(wParam
).caret
.Position();
7525 case SCI_SETSELECTIONNANCHOR
:
7526 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7529 case SCI_GETSELECTIONNANCHOR
:
7530 return sel
.Range(wParam
).anchor
.Position();
7532 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
7533 sel
.Range(wParam
).caret
.SetVirtualSpace(static_cast<int>(lParam
));
7537 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
7538 return sel
.Range(wParam
).caret
.VirtualSpace();
7540 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
7541 sel
.Range(wParam
).anchor
.SetVirtualSpace(static_cast<int>(lParam
));
7545 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
7546 return sel
.Range(wParam
).anchor
.VirtualSpace();
7548 case SCI_SETSELECTIONNSTART
:
7549 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7553 case SCI_GETSELECTIONNSTART
:
7554 return sel
.Range(wParam
).Start().Position();
7556 case SCI_SETSELECTIONNEND
:
7557 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7561 case SCI_GETSELECTIONNEND
:
7562 return sel
.Range(wParam
).End().Position();
7564 case SCI_SETRECTANGULARSELECTIONCARET
:
7565 if (!sel
.IsRectangular())
7567 sel
.selType
= Selection::selRectangle
;
7568 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
7569 SetRectangularRange();
7573 case SCI_GETRECTANGULARSELECTIONCARET
:
7574 return sel
.Rectangular().caret
.Position();
7576 case SCI_SETRECTANGULARSELECTIONANCHOR
:
7577 if (!sel
.IsRectangular())
7579 sel
.selType
= Selection::selRectangle
;
7580 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
7581 SetRectangularRange();
7585 case SCI_GETRECTANGULARSELECTIONANCHOR
:
7586 return sel
.Rectangular().anchor
.Position();
7588 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7589 if (!sel
.IsRectangular())
7591 sel
.selType
= Selection::selRectangle
;
7592 sel
.Rectangular().caret
.SetVirtualSpace(static_cast<int>(wParam
));
7593 SetRectangularRange();
7597 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7598 return sel
.Rectangular().caret
.VirtualSpace();
7600 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7601 if (!sel
.IsRectangular())
7603 sel
.selType
= Selection::selRectangle
;
7604 sel
.Rectangular().anchor
.SetVirtualSpace(static_cast<int>(wParam
));
7605 SetRectangularRange();
7609 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7610 return sel
.Rectangular().anchor
.VirtualSpace();
7612 case SCI_SETVIRTUALSPACEOPTIONS
:
7613 virtualSpaceOptions
= static_cast<int>(wParam
);
7616 case SCI_GETVIRTUALSPACEOPTIONS
:
7617 return virtualSpaceOptions
;
7619 case SCI_SETADDITIONALSELFORE
:
7620 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(wParam
));
7621 InvalidateStyleRedraw();
7624 case SCI_SETADDITIONALSELBACK
:
7625 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(wParam
));
7626 InvalidateStyleRedraw();
7629 case SCI_SETADDITIONALSELALPHA
:
7630 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7631 InvalidateStyleRedraw();
7634 case SCI_GETADDITIONALSELALPHA
:
7635 return vs
.selAdditionalAlpha
;
7637 case SCI_SETADDITIONALCARETFORE
:
7638 vs
.additionalCaretColour
= ColourDesired(static_cast<long>(wParam
));
7639 InvalidateStyleRedraw();
7642 case SCI_GETADDITIONALCARETFORE
:
7643 return vs
.additionalCaretColour
.AsLong();
7645 case SCI_ROTATESELECTION
:
7647 InvalidateSelection(sel
.RangeMain(), true);
7650 case SCI_SWAPMAINANCHORCARET
:
7651 InvalidateSelection(sel
.RangeMain());
7652 sel
.RangeMain() = SelectionRange(sel
.RangeMain().anchor
, sel
.RangeMain().caret
);
7655 case SCI_CHANGELEXERSTATE
:
7656 pdoc
->ChangeLexerState(static_cast<int>(wParam
), static_cast<int>(lParam
));
7659 case SCI_SETIDENTIFIER
:
7660 SetCtrlID(static_cast<int>(wParam
));
7663 case SCI_GETIDENTIFIER
:
7666 case SCI_SETTECHNOLOGY
:
7667 // No action by default
7670 case SCI_GETTECHNOLOGY
:
7673 case SCI_COUNTCHARACTERS
:
7674 return pdoc
->CountCharacters(static_cast<int>(wParam
), static_cast<int>(lParam
));
7677 return DefWndProc(iMessage
, wParam
, lParam
);
7679 //Platform::DebugPrintf("end wnd proc\n");