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();
634 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
637 QueueIdleWork(WorkNeeded::workUpdateUI
);
640 void Editor::SetSelection(int currentPos_
, int anchor_
) {
641 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
644 // Just move the caret on the main selection
645 void Editor::SetSelection(SelectionPosition currentPos_
) {
646 currentPos_
= ClampPositionIntoDocument(currentPos_
);
647 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
648 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
649 InvalidateSelection(SelectionRange(currentPos_
));
651 if (sel
.IsRectangular()) {
653 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
654 SetRectangularRange();
657 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
661 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
664 QueueIdleWork(WorkNeeded::workUpdateUI
);
667 void Editor::SetSelection(int currentPos_
) {
668 SetSelection(SelectionPosition(currentPos_
));
671 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
672 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
673 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
674 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
675 InvalidateSelection(rangeNew
);
678 sel
.RangeMain() = rangeNew
;
679 SetRectangularRange();
682 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
685 QueueIdleWork(WorkNeeded::workUpdateUI
);
688 void Editor::SetEmptySelection(int currentPos_
) {
689 SetEmptySelection(SelectionPosition(currentPos_
));
692 bool Editor::RangeContainsProtected(int start
, int end
) const {
693 if (vs
.ProtectionActive()) {
699 for (int pos
= start
; pos
< end
; pos
++) {
700 if (vs
.styles
[pdoc
->StyleAt(pos
)].IsProtected())
707 bool Editor::SelectionContainsProtected() {
708 for (size_t r
=0; r
<sel
.Count(); r
++) {
709 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
710 sel
.Range(r
).End().Position())) {
718 * Asks document to find a good position and then moves out of any invisible positions.
720 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
721 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
724 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
725 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
726 if (posMoved
!= pos
.Position())
727 pos
.SetPosition(posMoved
);
728 if (vs
.ProtectionActive()) {
730 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1)].IsProtected()) {
731 while ((pos
.Position() < pdoc
->Length()) &&
732 (vs
.styles
[pdoc
->StyleAt(pos
.Position())].IsProtected()))
735 } else if (moveDir
< 0) {
736 if (vs
.styles
[pdoc
->StyleAt(pos
.Position())].IsProtected()) {
737 while ((pos
.Position() > 0) &&
738 (vs
.styles
[pdoc
->StyleAt(pos
.Position() - 1)].IsProtected()))
746 int Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
747 bool simpleCaret
= (sel
.Count() == 1) && sel
.Empty();
748 SelectionPosition spCaret
= sel
.Last();
750 int delta
= newPos
.Position() - sel
.MainCaret();
751 newPos
= ClampPositionIntoDocument(newPos
);
752 newPos
= MovePositionOutsideChar(newPos
, delta
);
753 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
754 // Can't turn into multiple selection so clear additional selections
755 InvalidateSelection(SelectionRange(newPos
), true);
756 SelectionRange rangeMain
= sel
.RangeMain();
757 sel
.SetSelection(rangeMain
);
759 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
760 // Switching to rectangular
761 InvalidateSelection(sel
.RangeMain(), false);
762 SelectionRange rangeMain
= sel
.RangeMain();
764 sel
.Rectangular() = rangeMain
;
766 if (selt
!= Selection::noSel
) {
769 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
770 SetSelection(newPos
);
772 SetEmptySelection(newPos
);
774 ShowCaretAtCurrentPosition();
776 int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
778 // In case in need of wrapping to ensure DisplayFromDoc works.
779 if (currentLine
>= wrapPending
.start
)
781 XYScrollPosition newXY
= XYScrollToMakeVisible(
782 SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
), xysDefault
);
783 if (simpleCaret
&& (newXY
.xOffset
== xOffset
)) {
784 // simple vertical scroll then invalidate
785 ScrollTo(newXY
.topLine
);
786 InvalidateSelection(SelectionRange(spCaret
), true);
792 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
798 int Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
799 return MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
802 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
803 pos
= ClampPositionIntoDocument(pos
);
804 pos
= MovePositionOutsideChar(pos
, moveDir
);
805 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
806 if (cs
.GetVisible(lineDoc
)) {
809 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
811 // lineDisplay is already line before fold as lines in fold use display line of line after fold
812 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
813 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
815 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
816 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
821 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
822 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
825 Point
Editor::PointMainCaret() {
826 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
830 * Choose the x position that the caret will try to stick to
831 * as it moves up and down.
833 void Editor::SetLastXChosen() {
834 Point pt
= PointMainCaret();
835 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
838 void Editor::ScrollTo(int line
, bool moveThumb
) {
839 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
840 if (topLineNew
!= topLine
) {
841 // Try to optimise small scrolls
843 int linesToMove
= topLine
- topLineNew
;
844 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
845 willRedrawAll
= !performBlit
;
847 SetTopLine(topLineNew
);
848 // Optimize by styling the view as this will invalidate any needed area
849 // which could abort the initial paint if discovered later.
850 StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
852 // Perform redraw rather than scroll if many lines would be redrawn anyway.
854 ScrollText(linesToMove
);
858 willRedrawAll
= false;
863 SetVerticalScrollPos();
868 void Editor::ScrollText(int /* linesToMove */) {
869 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
873 void Editor::HorizontalScrollTo(int xPos
) {
874 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
877 if (!Wrapping() && (xOffset
!= xPos
)) {
879 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
880 SetHorizontalScrollPos();
881 RedrawRect(GetClientRectangle());
885 void Editor::VerticalCentreCaret() {
886 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
887 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
888 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
889 if (topLine
!= newTop
) {
890 SetTopLine(newTop
> 0 ? newTop
: 0);
891 RedrawRect(GetClientRectangle());
895 // Avoid 64 bit compiler warnings.
896 // Scintilla does not support text buffers larger than 2**31
897 static int istrlen(const char *s
) {
898 return static_cast<int>(s
? strlen(s
) : 0);
901 void Editor::MoveSelectedLines(int lineDelta
) {
903 // if selection doesn't start at the beginning of the line, set the new start
904 int selectionStart
= SelectionStart().Position();
905 int startLine
= pdoc
->LineFromPosition(selectionStart
);
906 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
907 selectionStart
= beginningOfStartLine
;
909 // if selection doesn't end at the beginning of a line greater than that of the start,
910 // then set it at the beginning of the next one
911 int selectionEnd
= SelectionEnd().Position();
912 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
913 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
914 bool appendEol
= false;
915 if (selectionEnd
> beginningOfEndLine
916 || selectionStart
== selectionEnd
) {
917 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
918 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
921 // if there's nowhere for the selection to move
922 // (i.e. at the beginning going up or at the end going down),
923 // stop it right there!
924 if ((selectionStart
== 0 && lineDelta
< 0)
925 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
926 || selectionStart
== selectionEnd
) {
932 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
933 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
935 selectionEnd
= CurrentPosition();
937 SetSelection(selectionStart
, selectionEnd
);
939 SelectionText selectedText
;
940 CopySelectionRange(&selectedText
);
942 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
943 Point currentLocation
= LocationFromPosition(CurrentPosition());
944 int currentLine
= LineFromLocation(currentLocation
);
947 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
950 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
951 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
952 pdoc
->InsertString(pdoc
->Length(), eol
, istrlen(eol
));
953 GoToLine(currentLine
+ lineDelta
);
955 selectionLength
= pdoc
->InsertString(CurrentPosition(), selectedText
.Data(), selectionLength
);
957 const int lengthInserted
= pdoc
->InsertString(CurrentPosition() + selectionLength
, eol
, istrlen(eol
));
958 selectionLength
+= lengthInserted
;
960 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
963 void Editor::MoveSelectedLinesUp() {
964 MoveSelectedLines(-1);
967 void Editor::MoveSelectedLinesDown() {
968 MoveSelectedLines(1);
971 void Editor::MoveCaretInsideView(bool ensureVisible
) {
972 PRectangle rcClient
= GetTextRectangle();
973 Point pt
= PointMainCaret();
974 if (pt
.y
< rcClient
.top
) {
975 MovePositionTo(SPositionFromLocation(
976 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
)),
977 false, false, UserVirtualSpace()),
978 Selection::noSel
, ensureVisible
);
979 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
980 int yOfLastLineFullyDisplayed
= static_cast<int>(rcClient
.top
) + (LinesOnScreen() - 1) * vs
.lineHeight
;
981 MovePositionTo(SPositionFromLocation(
982 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
) + yOfLastLineFullyDisplayed
),
983 false, false, UserVirtualSpace()),
984 Selection::noSel
, ensureVisible
);
988 int Editor::DisplayFromPosition(int pos
) {
989 AutoSurface
surface(this);
990 return view
.DisplayFromPosition(surface
, *this, pos
, vs
);
994 * Ensure the caret is reasonably visible in context.
996 Caret policy in SciTE
998 If slop is set, we can define a slop value.
999 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1000 This zone is defined as a number of pixels near the vertical margins,
1001 and as a number of lines near the horizontal margins.
1002 By keeping the caret away from the edges, it is seen within its context,
1003 so it is likely that the identifier that the caret is on can be completely seen,
1004 and that the current line is seen with some of the lines following it which are
1005 often dependent on that line.
1007 If strict is set, the policy is enforced... strictly.
1008 The caret is centred on the display if slop is not set,
1009 and cannot go in the UZ if slop is set.
1011 If jumps is set, the display is moved more energetically
1012 so the caret can move in the same direction longer before the policy is applied again.
1013 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1015 If even is not set, instead of having symmetrical UZs,
1016 the left and bottom UZs are extended up to right and top UZs respectively.
1017 This way, we favour the displaying of useful information: the beginning of lines,
1018 where most code reside, and the lines after the caret, eg. the body of a function.
1021 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1022 | | | | | visibility or going into the UZ) display is...
1023 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1024 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1025 0 | 0 | 0 | 1 | Yes | moved by one position
1026 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1027 0 | 0 | 1 | 1 | Yes | centred on the caret
1028 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1029 0 | 1 | - | 1 | No, caret is always centred | -
1030 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1031 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1032 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1033 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1034 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1035 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1036 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1039 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const SelectionRange
&range
, const XYScrollOptions options
) {
1040 PRectangle rcClient
= GetTextRectangle();
1041 Point pt
= LocationFromPosition(range
.caret
);
1042 Point ptAnchor
= LocationFromPosition(range
.anchor
);
1043 const Point ptOrigin
= GetVisibleOriginInMain();
1046 ptAnchor
.x
+= ptOrigin
.x
;
1047 ptAnchor
.y
+= ptOrigin
.y
;
1048 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1050 XYScrollPosition
newXY(xOffset
, topLine
);
1051 if (rcClient
.Empty()) {
1055 // Vertical positioning
1056 if ((options
& xysVertical
) && (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1057 const int lineCaret
= DisplayFromPosition(range
.caret
.Position());
1058 const int linesOnScreen
= LinesOnScreen();
1059 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1060 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1061 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1062 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1063 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1065 // It should be possible to scroll the window to show the caret,
1066 // but this fails to remove the caret on GTK+
1067 if (bSlop
) { // A margin is defined
1070 int yMarginT
, yMarginB
;
1071 if (!(options
& xysUseMargin
)) {
1072 // In drag mode, avoid moves
1073 // otherwise, a double click will select several lines.
1074 yMarginT
= yMarginB
= 0;
1076 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1077 // a maximum of slightly less than half the heigth of the text area.
1078 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1080 yMarginB
= yMarginT
;
1082 yMarginB
= linesOnScreen
- yMarginT
- 1;
1088 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1092 yMoveB
= linesOnScreen
- yMoveT
- 1;
1094 if (lineCaret
< topLine
+ yMarginT
) {
1095 // Caret goes too high
1096 newXY
.topLine
= lineCaret
- yMoveT
;
1097 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1098 // Caret goes too low
1099 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1101 } else { // Not strict
1102 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1103 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1107 yMoveB
= linesOnScreen
- yMoveT
- 1;
1109 if (lineCaret
< topLine
) {
1110 // Caret goes too high
1111 newXY
.topLine
= lineCaret
- yMoveT
;
1112 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1113 // Caret goes too low
1114 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1118 if (!bStrict
&& !bJump
) {
1120 if (lineCaret
< topLine
) {
1121 // Caret goes too high
1122 newXY
.topLine
= lineCaret
;
1123 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1124 // Caret goes too low
1126 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1128 newXY
.topLine
= lineCaret
;
1131 } else { // Strict or going out of display
1133 // Always center caret
1134 newXY
.topLine
= lineCaret
- halfScreen
;
1136 // Always put caret on top of display
1137 newXY
.topLine
= lineCaret
;
1141 if (!(range
.caret
== range
.anchor
)) {
1142 const int lineAnchor
= DisplayFromPosition(range
.anchor
.Position());
1143 if (lineAnchor
< lineCaret
) {
1144 // Shift up to show anchor or as much of range as possible
1145 newXY
.topLine
= std::min(newXY
.topLine
, lineAnchor
);
1146 newXY
.topLine
= std::max(newXY
.topLine
, lineCaret
- LinesOnScreen());
1148 // Shift down to show anchor or as much of range as possible
1149 newXY
.topLine
= std::max(newXY
.topLine
, lineAnchor
- LinesOnScreen());
1150 newXY
.topLine
= std::min(newXY
.topLine
, lineCaret
);
1153 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1156 // Horizontal positioning
1157 if ((options
& xysHorizontal
) && !Wrapping()) {
1158 const int halfScreen
= Platform::Maximum(static_cast<int>(rcClient
.Width()) - 4, 4) / 2;
1159 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1160 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1161 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1162 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1164 if (bSlop
) { // A margin is defined
1167 int xMarginL
, xMarginR
;
1168 if (!(options
& xysUseMargin
)) {
1169 // In drag mode, avoid moves unless very near of the margin
1170 // otherwise, a simple click will select text.
1171 xMarginL
= xMarginR
= 2;
1173 // xMargin must equal to caretXSlop, with a minimum of 2 and
1174 // a maximum of slightly less than half the width of the text area.
1175 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1177 xMarginL
= xMarginR
;
1179 xMarginL
= static_cast<int>(rcClient
.Width()) - xMarginR
- 4;
1182 if (bJump
&& bEven
) {
1183 // Jump is used only in even mode
1184 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1186 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1188 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1189 // Caret is on the left of the display
1190 if (bJump
&& bEven
) {
1191 newXY
.xOffset
-= xMoveL
;
1193 // Move just enough to allow to display the caret
1194 newXY
.xOffset
-= static_cast<int>((rcClient
.left
+ xMarginL
) - pt
.x
);
1196 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1197 // Caret is on the right of the display
1198 if (bJump
&& bEven
) {
1199 newXY
.xOffset
+= xMoveR
;
1201 // Move just enough to allow to display the caret
1202 newXY
.xOffset
+= static_cast<int>(pt
.x
- (rcClient
.right
- xMarginR
) + 1);
1205 } else { // Not strict
1206 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1207 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1211 xMoveL
= static_cast<int>(rcClient
.Width()) - xMoveR
- 4;
1213 if (pt
.x
< rcClient
.left
) {
1214 // Caret is on the left of the display
1215 newXY
.xOffset
-= xMoveL
;
1216 } else if (pt
.x
>= rcClient
.right
) {
1217 // Caret is on the right of the display
1218 newXY
.xOffset
+= xMoveR
;
1223 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1224 // Strict or going out of display
1227 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.left
- halfScreen
);
1229 // Put caret on right
1230 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
+ 1);
1233 // Move just enough to allow to display the caret
1234 if (pt
.x
< rcClient
.left
) {
1235 // Caret is on the left of the display
1237 newXY
.xOffset
-= static_cast<int>(rcClient
.left
- pt
.x
);
1239 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1241 } else if (pt
.x
>= rcClient
.right
) {
1242 // Caret is on the right of the display
1243 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1247 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1248 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1249 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 2;
1250 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1251 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 2;
1252 if ((vs
.caretStyle
== CARETSTYLE_BLOCK
) || view
.imeCaretBlockOverride
) {
1253 // Ensure we can see a good portion of the block caret
1254 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1257 if (!(range
.caret
== range
.anchor
)) {
1258 if (ptAnchor
.x
< pt
.x
) {
1259 // Shift to left to show anchor or as much of range as possible
1260 int maxOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.left
) - 1;
1261 int minOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 1;
1262 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1263 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1265 // Shift to right to show anchor or as much of range as possible
1266 int minOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.right
) + 1;
1267 int maxOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 1;
1268 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1269 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1272 if (newXY
.xOffset
< 0) {
1280 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1281 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1282 if (newXY
.topLine
!= topLine
) {
1283 SetTopLine(newXY
.topLine
);
1284 SetVerticalScrollPos();
1286 if (newXY
.xOffset
!= xOffset
) {
1287 xOffset
= newXY
.xOffset
;
1288 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1289 if (newXY
.xOffset
> 0) {
1290 PRectangle rcText
= GetTextRectangle();
1291 if (horizontalScrollBarVisible
&&
1292 rcText
.Width() + xOffset
> scrollWidth
) {
1293 scrollWidth
= xOffset
+ static_cast<int>(rcText
.Width());
1297 SetHorizontalScrollPos();
1300 UpdateSystemCaret();
1304 void Editor::ScrollRange(SelectionRange range
) {
1305 SetXYScroll(XYScrollToMakeVisible(range
, xysDefault
));
1308 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1309 SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
),
1310 static_cast<XYScrollOptions
>((useMargin
?xysUseMargin
:0)|(vert
?xysVertical
:0)|(horiz
?xysHorizontal
:0))));
1313 void Editor::ShowCaretAtCurrentPosition() {
1315 caret
.active
= true;
1317 if (FineTickerAvailable()) {
1318 FineTickerCancel(tickCaret
);
1319 if (caret
.period
> 0)
1320 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1325 caret
.active
= false;
1327 if (FineTickerAvailable()) {
1328 FineTickerCancel(tickCaret
);
1334 void Editor::DropCaret() {
1335 caret
.active
= false;
1336 FineTickerCancel(tickCaret
);
1340 void Editor::CaretSetPeriod(int period
) {
1341 if (caret
.period
!= period
) {
1342 caret
.period
= period
;
1344 if (FineTickerAvailable()) {
1345 FineTickerCancel(tickCaret
);
1346 if ((caret
.active
) && (caret
.period
> 0))
1347 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1353 void Editor::InvalidateCaret() {
1354 if (posDrag
.IsValid()) {
1355 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1357 for (size_t r
=0; r
<sel
.Count(); r
++) {
1358 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1361 UpdateSystemCaret();
1364 void Editor::UpdateSystemCaret() {
1367 bool Editor::Wrapping() const {
1368 return vs
.wrapState
!= eWrapNone
;
1371 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1372 //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd);
1373 if (wrapPending
.AddRange(docLineStart
, docLineEnd
)) {
1374 view
.llc
.Invalidate(LineLayout::llPositions
);
1376 // Wrap lines during idle.
1377 if (Wrapping() && wrapPending
.NeedsWrap()) {
1382 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1383 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(lineToWrap
, *this));
1384 int linesWrapped
= 1;
1386 view
.LayoutLine(*this, lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1387 linesWrapped
= ll
->lines
;
1389 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1390 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1393 // Perform wrapping for a subset of the lines needing wrapping.
1394 // wsAll: wrap all lines which need wrapping in this single call
1395 // wsVisible: wrap currently visible lines
1396 // wsIdle: wrap one page + 100 lines
1397 // Return true if wrapping occurred.
1398 bool Editor::WrapLines(enum wrapScope ws
) {
1399 int goodTopLine
= topLine
;
1400 bool wrapOccurred
= false;
1402 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1403 wrapWidth
= LineLayout::wrapWidthInfinite
;
1404 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1405 cs
.SetHeight(lineDoc
, 1 +
1406 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1408 wrapOccurred
= true;
1410 wrapPending
.Reset();
1412 } else if (wrapPending
.NeedsWrap()) {
1413 wrapPending
.start
= std::min(wrapPending
.start
, pdoc
->LinesTotal());
1414 if (!SetIdle(true)) {
1415 // Idle processing not supported so full wrap required.
1418 // Decide where to start wrapping
1419 int lineToWrap
= wrapPending
.start
;
1420 int lineToWrapEnd
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1421 const int lineDocTop
= cs
.DocFromDisplay(topLine
);
1422 const int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1423 if (ws
== wsVisible
) {
1424 lineToWrap
= Platform::Clamp(lineDocTop
-5, wrapPending
.start
, pdoc
->LinesTotal());
1425 // Priority wrap to just after visible area.
1426 // Since wrapping could reduce display lines, treat each
1427 // as taking only one display line.
1428 lineToWrapEnd
= lineDocTop
;
1429 int lines
= LinesOnScreen() + 1;
1430 while ((lineToWrapEnd
< cs
.LinesInDoc()) && (lines
>0)) {
1431 if (cs
.GetVisible(lineToWrapEnd
))
1435 // .. and if the paint window is outside pending wraps
1436 if ((lineToWrap
> wrapPending
.end
) || (lineToWrapEnd
< wrapPending
.start
)) {
1437 // Currently visible text does not need wrapping
1440 } else if (ws
== wsIdle
) {
1441 lineToWrapEnd
= lineToWrap
+ LinesOnScreen() + 100;
1443 const int lineEndNeedWrap
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1444 lineToWrapEnd
= std::min(lineToWrapEnd
, lineEndNeedWrap
);
1446 // Ensure all lines being wrapped are styled.
1447 pdoc
->EnsureStyledTo(pdoc
->LineStart(lineToWrapEnd
));
1449 if (lineToWrap
< lineToWrapEnd
) {
1451 PRectangle rcTextArea
= GetClientRectangle();
1452 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1453 rcTextArea
.right
-= vs
.rightMarginWidth
;
1454 wrapWidth
= static_cast<int>(rcTextArea
.Width());
1456 AutoSurface
surface(this);
1458 //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd);
1460 while (lineToWrap
< lineToWrapEnd
) {
1461 if (WrapOneLine(surface
, lineToWrap
)) {
1462 wrapOccurred
= true;
1464 wrapPending
.Wrapped(lineToWrap
);
1468 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
) + std::min(subLineTop
, cs
.GetHeight(lineDocTop
)-1);
1472 // If wrapping is done, bring it to resting position
1473 if (wrapPending
.start
>= lineEndNeedWrap
) {
1474 wrapPending
.Reset();
1480 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1481 SetVerticalScrollPos();
1484 return wrapOccurred
;
1487 void Editor::LinesJoin() {
1488 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1490 bool prevNonWS
= true;
1491 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1492 if (pdoc
->IsPositionInLineEnd(pos
)) {
1493 targetEnd
-= pdoc
->LenChar(pos
);
1496 // Ensure at least one space separating previous lines
1497 const int lengthInserted
= pdoc
->InsertString(pos
, " ", 1);
1498 targetEnd
+= lengthInserted
;
1501 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1507 const char *Editor::StringFromEOLMode(int eolMode
) {
1508 if (eolMode
== SC_EOL_CRLF
) {
1510 } else if (eolMode
== SC_EOL_CR
) {
1517 void Editor::LinesSplit(int pixelWidth
) {
1518 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1519 if (pixelWidth
== 0) {
1520 PRectangle rcText
= GetTextRectangle();
1521 pixelWidth
= static_cast<int>(rcText
.Width());
1523 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1524 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1525 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1527 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1528 AutoSurface
surface(this);
1529 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
1530 if (surface
&& ll
) {
1531 unsigned int posLineStart
= pdoc
->LineStart(line
);
1532 view
.LayoutLine(*this, line
, surface
, vs
, ll
, pixelWidth
);
1533 int lengthInsertedTotal
= 0;
1534 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1535 const int lengthInserted
= pdoc
->InsertString(
1536 static_cast<int>(posLineStart
+ lengthInsertedTotal
+
1537 ll
->LineStart(subLine
)),
1539 targetEnd
+= lengthInserted
;
1540 lengthInsertedTotal
+= lengthInserted
;
1543 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1548 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1549 if (vs
.fixedColumnWidth
== 0)
1554 RefreshPixMaps(surfWindow
);
1556 // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished
1557 // at this point. The Initialised call checks for this case and sets the status
1558 // to be bad which avoids crashes in following calls.
1559 if (!surfWindow
->Initialised()) {
1563 PRectangle rcMargin
= GetClientRectangle();
1564 Point ptOrigin
= GetVisibleOriginInMain();
1565 rcMargin
.Move(0, -ptOrigin
.y
);
1567 rcMargin
.right
= static_cast<XYPOSITION
>(vs
.fixedColumnWidth
);
1569 if (!rc
.Intersects(rcMargin
))
1573 if (view
.bufferedDraw
) {
1574 surface
= marginView
.pixmapSelMargin
;
1576 surface
= surfWindow
;
1579 // Clip vertically to paint area to avoid drawing line numbers
1580 if (rcMargin
.bottom
> rc
.bottom
)
1581 rcMargin
.bottom
= rc
.bottom
;
1582 if (rcMargin
.top
< rc
.top
)
1583 rcMargin
.top
= rc
.top
;
1585 marginView
.PaintMargin(surface
, topLine
, rc
, rcMargin
, *this, vs
);
1587 if (view
.bufferedDraw
) {
1588 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *marginView
.pixmapSelMargin
);
1592 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
1593 view
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1594 marginView
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1595 if (view
.bufferedDraw
) {
1596 PRectangle rcClient
= GetClientRectangle();
1597 if (!view
.pixmapLine
->Initialised()) {
1599 view
.pixmapLine
->InitPixMap(static_cast<int>(rcClient
.Width()), vs
.lineHeight
,
1600 surfaceWindow
, wMain
.GetID());
1602 if (!marginView
.pixmapSelMargin
->Initialised()) {
1603 marginView
.pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1604 static_cast<int>(rcClient
.Height()), surfaceWindow
, wMain
.GetID());
1609 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1610 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1611 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1615 if (paintState
== paintAbandoned
)
1616 return; // Scroll bars may have changed so need redraw
1617 RefreshPixMaps(surfaceWindow
);
1619 paintAbandonedByStyling
= false;
1621 StyleToPositionInView(PositionAfterArea(rcArea
));
1623 PRectangle rcClient
= GetClientRectangle();
1624 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1625 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1627 if (NotifyUpdateUI()) {
1629 RefreshPixMaps(surfaceWindow
);
1632 // Wrap the visible lines if needed.
1633 if (WrapLines(wsVisible
)) {
1634 // The wrapping process has changed the height of some lines so
1635 // abandon this paint for a complete repaint.
1636 if (AbandonPaint()) {
1639 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
1641 PLATFORM_ASSERT(marginView
.pixmapSelPattern
->Initialised());
1643 if (!view
.bufferedDraw
)
1644 surfaceWindow
->SetClip(rcArea
);
1646 if (paintState
!= paintAbandoned
) {
1647 if (vs
.marginInside
) {
1648 PaintSelMargin(surfaceWindow
, rcArea
);
1649 PRectangle rcRightMargin
= rcClient
;
1650 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1651 if (rcArea
.Intersects(rcRightMargin
)) {
1652 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1654 } else { // Else separate view so separate paint event but leftMargin included to allow overlap
1655 PRectangle rcLeftMargin
= rcArea
;
1656 rcLeftMargin
.left
= 0;
1657 rcLeftMargin
.right
= rcLeftMargin
.left
+ vs
.leftMarginWidth
;
1658 if (rcArea
.Intersects(rcLeftMargin
)) {
1659 surfaceWindow
->FillRectangle(rcLeftMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1664 if (paintState
== paintAbandoned
) {
1665 // Either styling or NotifyUpdateUI noticed that painting is needed
1666 // outside the current painting rectangle
1667 //Platform::DebugPrintf("Abandoning paint\n");
1669 if (paintAbandonedByStyling
) {
1670 // Styling has spilled over a line end, such as occurs by starting a multiline
1671 // comment. The width of subsequent text may have changed, so rewrap.
1672 NeedWrapping(cs
.DocFromDisplay(topLine
));
1678 view
.PaintText(surfaceWindow
, *this, rcArea
, rcClient
, vs
);
1680 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
1681 if (FineTickerAvailable()) {
1682 scrollWidth
= view
.lineWidthMaxSeen
;
1683 if (!FineTickerRunning(tickWiden
)) {
1684 FineTickerStart(tickWiden
, 50, 5);
1692 // This is mostly copied from the Paint method but with some things omitted
1693 // such as the margin markers, line numbers, selection and caret
1694 // Should be merged back into a combined Draw method.
1695 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
1699 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
1702 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
1703 if (!surfaceMeasure
) {
1706 return view
.FormatRange(draw
, pfr
, surface
, surfaceMeasure
, *this, vs
);
1709 int Editor::TextWidth(int style
, const char *text
) {
1711 AutoSurface
surface(this);
1713 return static_cast<int>(surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
)));
1719 // Empty method is overridden on GTK+ to show / hide scrollbars
1720 void Editor::ReconfigureScrollBars() {}
1722 void Editor::SetScrollBars() {
1725 int nMax
= MaxScrollPos();
1726 int nPage
= LinesOnScreen();
1727 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
1732 // TODO: ensure always showing as many lines as possible
1733 // May not be, if, for example, window made larger
1734 if (topLine
> MaxScrollPos()) {
1735 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1736 SetVerticalScrollPos();
1740 if (!AbandonPaint())
1743 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1746 void Editor::ChangeSize() {
1747 DropGraphics(false);
1750 PRectangle rcTextArea
= GetClientRectangle();
1751 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1752 rcTextArea
.right
-= vs
.rightMarginWidth
;
1753 if (wrapWidth
!= rcTextArea
.Width()) {
1760 int Editor::InsertSpace(int position
, unsigned int spaces
) {
1762 std::string
spaceText(spaces
, ' ');
1763 const int lengthInserted
= pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
1764 position
+= lengthInserted
;
1769 void Editor::AddChar(char ch
) {
1776 void Editor::FilterSelections() {
1777 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
1778 SelectionRange rangeOnly
= sel
.RangeMain();
1779 InvalidateSelection(rangeOnly
, true);
1780 sel
.SetSelection(rangeOnly
);
1784 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
1788 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
1789 void Editor::AddCharUTF(const char *s
, unsigned int len
, bool treatAsDBCS
) {
1792 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1794 // Vector elements point into selection in order to change selection.
1795 std::vector
<SelectionRange
*> selPtrs
;
1796 for (size_t r
= 0; r
< sel
.Count(); r
++) {
1797 selPtrs
.push_back(&sel
.Range(r
));
1799 // Order selections by position in document.
1800 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
1802 // Loop in reverse to avoid disturbing positions of selections yet to be processed.
1803 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
1804 rit
!= selPtrs
.rend(); ++rit
) {
1805 SelectionRange
*currentSel
= *rit
;
1806 if (!RangeContainsProtected(currentSel
->Start().Position(),
1807 currentSel
->End().Position())) {
1808 int positionInsert
= currentSel
->Start().Position();
1809 if (!currentSel
->Empty()) {
1810 if (currentSel
->Length()) {
1811 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
1812 currentSel
->ClearVirtualSpace();
1814 // Range is all virtual so collapse to start of virtual space
1815 currentSel
->MinimizeVirtualSpace();
1817 } else if (inOverstrike
) {
1818 if (positionInsert
< pdoc
->Length()) {
1819 if (!pdoc
->IsPositionInLineEnd(positionInsert
)) {
1820 pdoc
->DelChar(positionInsert
);
1821 currentSel
->ClearVirtualSpace();
1825 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
1826 const int lengthInserted
= pdoc
->InsertString(positionInsert
, s
, len
);
1827 if (lengthInserted
> 0) {
1828 currentSel
->caret
.SetPosition(positionInsert
+ lengthInserted
);
1829 currentSel
->anchor
.SetPosition(positionInsert
+ lengthInserted
);
1831 currentSel
->ClearVirtualSpace();
1832 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1834 AutoSurface
surface(this);
1836 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
1838 SetVerticalScrollPos();
1849 ThinRectangularRange();
1850 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1851 EnsureCaretVisible();
1852 // Avoid blinking during rapid typing:
1853 ShowCaretAtCurrentPosition();
1854 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
1855 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
1860 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
1861 static_cast<unsigned char>(s
[1]));
1862 } else if (len
> 0) {
1863 int byte
= static_cast<unsigned char>(s
[0]);
1864 if ((byte
< 0xC0) || (1 == len
)) {
1865 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1866 // characters when not in UTF-8 mode.
1867 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1868 // characters representing themselves.
1870 // Unroll 1 to 3 byte UTF-8 sequences. See reference data at:
1871 // http://www.cl.cam.ac.uk/~mgk25/unicode.html
1872 // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
1874 int byte2
= static_cast<unsigned char>(s
[1]);
1875 if ((byte2
& 0xC0) == 0x80) {
1876 // Two-byte-character lead-byte followed by a trail-byte.
1877 byte
= (((byte
& 0x1F) << 6) | (byte2
& 0x3F));
1879 // A two-byte-character lead-byte not followed by trail-byte
1880 // represents itself.
1881 } else if (byte
< 0xF0) {
1882 int byte2
= static_cast<unsigned char>(s
[1]);
1883 int byte3
= static_cast<unsigned char>(s
[2]);
1884 if (((byte2
& 0xC0) == 0x80) && ((byte3
& 0xC0) == 0x80)) {
1885 // Three-byte-character lead byte followed by two trail bytes.
1886 byte
= (((byte
& 0x0F) << 12) | ((byte2
& 0x3F) << 6) |
1889 // A three-byte-character lead-byte not followed by two trail-bytes
1890 // represents itself.
1896 if (recordingMacro
) {
1897 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
1901 void Editor::InsertPaste(const char *text
, int len
) {
1902 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
1903 SelectionPosition selStart
= sel
.Start();
1904 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
1905 const int lengthInserted
= pdoc
->InsertString(selStart
.Position(), text
, len
);
1906 if (lengthInserted
> 0) {
1907 SetEmptySelection(selStart
.Position() + lengthInserted
);
1910 // SC_MULTIPASTE_EACH
1911 for (size_t r
=0; r
<sel
.Count(); r
++) {
1912 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1913 sel
.Range(r
).End().Position())) {
1914 int positionInsert
= sel
.Range(r
).Start().Position();
1915 if (!sel
.Range(r
).Empty()) {
1916 if (sel
.Range(r
).Length()) {
1917 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1918 sel
.Range(r
).ClearVirtualSpace();
1920 // Range is all virtual so collapse to start of virtual space
1921 sel
.Range(r
).MinimizeVirtualSpace();
1924 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
1925 const int lengthInserted
= pdoc
->InsertString(positionInsert
, text
, len
);
1926 if (lengthInserted
> 0) {
1927 sel
.Range(r
).caret
.SetPosition(positionInsert
+ lengthInserted
);
1928 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ lengthInserted
);
1930 sel
.Range(r
).ClearVirtualSpace();
1936 void Editor::InsertPasteShape(const char *text
, int len
, PasteShape shape
) {
1937 std::string convertedText
;
1938 if (convertPastes
) {
1939 // Convert line endings of the paste into our local line-endings mode
1940 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
1941 len
= static_cast<int>(convertedText
.length());
1942 text
= convertedText
.c_str();
1944 if (shape
== pasteRectangular
) {
1945 PasteRectangular(sel
.Start(), text
, len
);
1947 if (shape
== pasteLine
) {
1948 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
1949 int lengthInserted
= pdoc
->InsertString(insertPos
, text
, len
);
1950 // add the newline if necessary
1951 if ((len
> 0) && (text
[len
- 1] != '\n' && text
[len
- 1] != '\r')) {
1952 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
1953 int length
= static_cast<int>(strlen(endline
));
1954 lengthInserted
+= pdoc
->InsertString(insertPos
+ lengthInserted
, endline
, length
);
1956 if (sel
.MainCaret() == insertPos
) {
1957 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
1960 InsertPaste(text
, len
);
1965 void Editor::ClearSelection(bool retainMultipleSelections
) {
1966 if (!sel
.IsRectangular() && !retainMultipleSelections
)
1969 for (size_t r
=0; r
<sel
.Count(); r
++) {
1970 if (!sel
.Range(r
).Empty()) {
1971 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1972 sel
.Range(r
).End().Position())) {
1973 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
1974 sel
.Range(r
).Length());
1975 sel
.Range(r
) = SelectionRange(sel
.Range(r
).Start());
1979 ThinRectangularRange();
1980 sel
.RemoveDuplicates();
1984 void Editor::ClearAll() {
1987 if (0 != pdoc
->Length()) {
1988 pdoc
->DeleteChars(0, pdoc
->Length());
1990 if (!pdoc
->IsReadOnly()) {
1992 pdoc
->AnnotationClearAll();
1993 pdoc
->MarginClearAll();
1997 view
.ClearAllTabstops();
2001 SetVerticalScrollPos();
2002 InvalidateStyleRedraw();
2005 void Editor::ClearDocumentStyle() {
2006 Decoration
*deco
= pdoc
->decorations
.root
;
2008 // Save next in case deco deleted
2009 Decoration
*decoNext
= deco
->next
;
2010 if (deco
->indicator
< INDIC_CONTAINER
) {
2011 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
2012 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
2016 pdoc
->StartStyling(0, '\377');
2017 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2019 SetAnnotationHeights(0, pdoc
->LinesTotal());
2020 pdoc
->ClearLevels();
2023 void Editor::CopyAllowLine() {
2024 SelectionText selectedText
;
2025 CopySelectionRange(&selectedText
, true);
2026 CopyToClipboard(selectedText
);
2029 void Editor::Cut() {
2030 pdoc
->CheckReadOnly();
2031 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2037 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
2038 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2042 sel
.RangeMain() = SelectionRange(pos
);
2043 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2045 sel
.RangeMain().caret
= SelectionPosition(
2046 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
2047 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
2048 bool prevCr
= false;
2049 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
2051 for (int i
= 0; i
< len
; i
++) {
2052 if (IsEOLChar(ptr
[i
])) {
2053 if ((ptr
[i
] == '\r') || (!prevCr
))
2055 if (line
>= pdoc
->LinesTotal()) {
2056 if (pdoc
->eolMode
!= SC_EOL_LF
)
2057 pdoc
->InsertString(pdoc
->Length(), "\r", 1);
2058 if (pdoc
->eolMode
!= SC_EOL_CR
)
2059 pdoc
->InsertString(pdoc
->Length(), "\n", 1);
2061 // Pad the end of lines with spaces if required
2062 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
2063 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
2064 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
2065 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), " ", 1);
2066 sel
.RangeMain().caret
.Add(lengthInserted
);
2069 prevCr
= ptr
[i
] == '\r';
2071 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
2072 sel
.RangeMain().caret
.Add(lengthInserted
);
2076 SetEmptySelection(pos
);
2079 bool Editor::CanPaste() {
2080 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
2083 void Editor::Clear() {
2084 // If multiple selections, don't delete EOLS
2086 bool singleVirtual
= false;
2087 if ((sel
.Count() == 1) &&
2088 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
2089 sel
.RangeMain().Start().VirtualSpace()) {
2090 singleVirtual
= true;
2092 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
2093 for (size_t r
=0; r
<sel
.Count(); r
++) {
2094 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
2095 if (sel
.Range(r
).Start().VirtualSpace()) {
2096 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
2097 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
2099 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
2101 if ((sel
.Count() == 1) || !pdoc
->IsPositionInLineEnd(sel
.Range(r
).caret
.Position())) {
2102 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
2103 sel
.Range(r
).ClearVirtualSpace();
2104 } // else multiple selection so don't eat line ends
2106 sel
.Range(r
).ClearVirtualSpace();
2112 sel
.RemoveDuplicates();
2113 ShowCaretAtCurrentPosition(); // Avoid blinking
2116 void Editor::SelectAll() {
2118 SetSelection(0, pdoc
->Length());
2122 void Editor::Undo() {
2123 if (pdoc
->CanUndo()) {
2125 int newPos
= pdoc
->Undo();
2127 SetEmptySelection(newPos
);
2128 EnsureCaretVisible();
2132 void Editor::Redo() {
2133 if (pdoc
->CanRedo()) {
2134 int newPos
= pdoc
->Redo();
2136 SetEmptySelection(newPos
);
2137 EnsureCaretVisible();
2141 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2143 if (!sel
.IsRectangular())
2145 if (sel
.IsRectangular())
2146 allowLineStartDeletion
= false;
2147 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
2149 for (size_t r
=0; r
<sel
.Count(); r
++) {
2150 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
2151 if (sel
.Range(r
).caret
.VirtualSpace()) {
2152 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
2153 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
2155 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2156 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
2157 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2158 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
2159 UndoGroup
ugInner(pdoc
, !ug
.Needed());
2160 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2161 int indentationStep
= pdoc
->IndentSize();
2162 int indentationChange
= indentation
% indentationStep
;
2163 if (indentationChange
== 0)
2164 indentationChange
= indentationStep
;
2165 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationChange
);
2166 // SetEmptySelection
2167 sel
.Range(r
) = SelectionRange(posSelect
);
2169 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
2174 sel
.Range(r
).ClearVirtualSpace();
2177 ThinRectangularRange();
2181 sel
.RemoveDuplicates();
2182 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
2183 // Avoid blinking during rapid typing:
2184 ShowCaretAtCurrentPosition();
2187 int Editor::ModifierFlags(bool shift
, bool ctrl
, bool alt
, bool meta
) {
2189 (shift
? SCI_SHIFT
: 0) |
2190 (ctrl
? SCI_CTRL
: 0) |
2191 (alt
? SCI_ALT
: 0) |
2192 (meta
? SCI_META
: 0);
2195 void Editor::NotifyFocus(bool focus
) {
2196 SCNotification scn
= {};
2197 scn
.nmhdr
.code
= focus
? SCN_FOCUSIN
: SCN_FOCUSOUT
;
2201 void Editor::SetCtrlID(int identifier
) {
2202 ctrlID
= identifier
;
2205 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2206 SCNotification scn
= {};
2207 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2208 scn
.position
= endStyleNeeded
;
2212 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2213 NotifyStyleToNeeded(endStyleNeeded
);
2216 void Editor::NotifyLexerChanged(Document
*, void *) {
2219 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
2220 errorStatus
= status
;
2223 void Editor::NotifyChar(int ch
) {
2224 SCNotification scn
= {};
2225 scn
.nmhdr
.code
= SCN_CHARADDED
;
2230 void Editor::NotifySavePoint(bool isSavePoint
) {
2231 SCNotification scn
= {};
2233 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2235 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2240 void Editor::NotifyModifyAttempt() {
2241 SCNotification scn
= {};
2242 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2246 void Editor::NotifyDoubleClick(Point pt
, int modifiers
) {
2247 SCNotification scn
= {};
2248 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2249 scn
.line
= LineFromLocation(pt
);
2250 scn
.position
= PositionFromLocation(pt
, true);
2251 scn
.modifiers
= modifiers
;
2255 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2256 NotifyDoubleClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2259 void Editor::NotifyHotSpotDoubleClicked(int position
, int modifiers
) {
2260 SCNotification scn
= {};
2261 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
2262 scn
.position
= position
;
2263 scn
.modifiers
= modifiers
;
2267 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2268 NotifyHotSpotDoubleClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2271 void Editor::NotifyHotSpotClicked(int position
, int modifiers
) {
2272 SCNotification scn
= {};
2273 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
2274 scn
.position
= position
;
2275 scn
.modifiers
= modifiers
;
2279 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2280 NotifyHotSpotClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2283 void Editor::NotifyHotSpotReleaseClick(int position
, int modifiers
) {
2284 SCNotification scn
= {};
2285 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
2286 scn
.position
= position
;
2287 scn
.modifiers
= modifiers
;
2291 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
2292 NotifyHotSpotReleaseClick(position
, ModifierFlags(shift
, ctrl
, alt
));
2295 bool Editor::NotifyUpdateUI() {
2297 SCNotification scn
= {};
2298 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2299 scn
.updated
= needUpdateUI
;
2307 void Editor::NotifyPainted() {
2308 SCNotification scn
= {};
2309 scn
.nmhdr
.code
= SCN_PAINTED
;
2313 void Editor::NotifyIndicatorClick(bool click
, int position
, int modifiers
) {
2314 int mask
= pdoc
->decorations
.AllOnFor(position
);
2315 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
2316 SCNotification scn
= {};
2317 pdoc
->decorations
.clickNotified
= click
;
2318 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
2319 scn
.modifiers
= modifiers
;
2320 scn
.position
= position
;
2325 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
2326 NotifyIndicatorClick(click
, position
, ModifierFlags(shift
, ctrl
, alt
));
2329 bool Editor::NotifyMarginClick(Point pt
, int modifiers
) {
2330 int marginClicked
= -1;
2331 int x
= vs
.textStart
- vs
.fixedColumnWidth
;
2332 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
2333 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2334 marginClicked
= margin
;
2335 x
+= vs
.ms
[margin
].width
;
2337 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2338 int position
= pdoc
->LineStart(LineFromLocation(pt
));
2339 if ((vs
.ms
[marginClicked
].mask
& SC_MASK_FOLDERS
) && (foldAutomatic
& SC_AUTOMATICFOLD_CLICK
)) {
2340 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
2341 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
2342 int lineClick
= pdoc
->LineFromPosition(position
);
2343 if (shift
&& ctrl
) {
2344 FoldAll(SC_FOLDACTION_TOGGLE
);
2346 int levelClick
= pdoc
->GetLevel(lineClick
);
2347 if (levelClick
& SC_FOLDLEVELHEADERFLAG
) {
2349 // Ensure all children visible
2350 FoldExpand(lineClick
, SC_FOLDACTION_EXPAND
, levelClick
);
2352 FoldExpand(lineClick
, SC_FOLDACTION_TOGGLE
, levelClick
);
2355 FoldLine(lineClick
, SC_FOLDACTION_TOGGLE
);
2361 SCNotification scn
= {};
2362 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2363 scn
.modifiers
= modifiers
;
2364 scn
.position
= position
;
2365 scn
.margin
= marginClicked
;
2373 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2374 return NotifyMarginClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2377 void Editor::NotifyNeedShown(int pos
, int len
) {
2378 SCNotification scn
= {};
2379 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2385 void Editor::NotifyDwelling(Point pt
, bool state
) {
2386 SCNotification scn
= {};
2387 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2388 scn
.position
= PositionFromLocation(pt
, true);
2389 scn
.x
= static_cast<int>(pt
.x
+ vs
.ExternalMarginWidth());
2390 scn
.y
= static_cast<int>(pt
.y
);
2394 void Editor::NotifyZoom() {
2395 SCNotification scn
= {};
2396 scn
.nmhdr
.code
= SCN_ZOOM
;
2400 // Notifications from document
2401 void Editor::NotifyModifyAttempt(Document
*, void *) {
2402 //Platform::DebugPrintf("** Modify Attempt\n");
2403 NotifyModifyAttempt();
2406 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2407 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2408 NotifySavePoint(atSavePoint
);
2411 void Editor::CheckModificationForWrap(DocModification mh
) {
2412 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
2413 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2414 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2415 int lines
= Platform::Maximum(0, mh
.linesAdded
);
2417 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
2420 // Fix up annotation heights
2421 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
2425 // Move a position so it is still after the same character as before the insertion.
2426 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2427 if (position
> startInsertion
) {
2428 return position
+ length
;
2433 // Move a position so it is still after the same character as before the deletion if that
2434 // character is still present else after the previous surviving character.
2435 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2436 if (position
> startDeletion
) {
2437 int endDeletion
= startDeletion
+ length
;
2438 if (position
> endDeletion
) {
2439 return position
- length
;
2441 return startDeletion
;
2448 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2449 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
2450 if (paintState
== painting
) {
2451 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2453 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
2454 if (paintState
== painting
) {
2455 CheckForChangeOutsidePaint(
2456 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
2458 // Could check that change is before last visible line.
2462 if (mh
.modificationType
& SC_MOD_CHANGETABSTOPS
) {
2465 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
2466 if (paintState
== painting
) {
2467 CheckForChangeOutsidePaint(
2468 Range(mh
.position
, mh
.position
+ mh
.length
));
2473 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
2474 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2475 pdoc
->IncrementStyleClock();
2477 if (paintState
== notPainting
) {
2478 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2479 // Styling performed before this view
2482 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2485 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2486 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2489 // Move selection and brace highlights
2490 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2491 sel
.MovePositions(true, mh
.position
, mh
.length
);
2492 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2493 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2494 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2495 sel
.MovePositions(false, mh
.position
, mh
.length
);
2496 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2497 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2499 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
2500 // Some lines are hidden so may need shown.
2501 // TODO: check if the modified area is hidden.
2502 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2503 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2504 bool insertingNewLine
= false;
2505 for (int i
=0; i
< mh
.length
; i
++) {
2506 if ((mh
.text
[i
] == '\n') || (mh
.text
[i
] == '\r'))
2507 insertingNewLine
= true;
2509 if (insertingNewLine
&& (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
2510 NeedShown(mh
.position
, pdoc
->LineStart(lineOfPos
+1) - mh
.position
);
2512 NeedShown(mh
.position
, 0);
2513 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2514 NeedShown(mh
.position
, mh
.length
);
2517 if (mh
.linesAdded
!= 0) {
2518 // Update contraction state for inserted and removed lines
2519 // lineOfPos should be calculated in context of state before modification, shouldn't it
2520 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2521 if (mh
.position
> pdoc
->LineStart(lineOfPos
))
2522 lineOfPos
++; // Affecting subsequent lines
2523 if (mh
.linesAdded
> 0) {
2524 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2526 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2528 view
.LinesAddedOrRemoved(lineOfPos
, mh
.linesAdded
);
2530 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
2531 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2532 if (vs
.annotationVisible
) {
2533 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
2537 CheckModificationForWrap(mh
);
2538 if (mh
.linesAdded
!= 0) {
2539 // Avoid scrolling of display if change before current display
2540 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
2541 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2542 if (newTop
!= topLine
) {
2544 SetVerticalScrollPos();
2548 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
2549 QueueIdleWork(WorkNeeded::workStyle
, pdoc
->Length());
2553 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
2554 QueueIdleWork(WorkNeeded::workStyle
, mh
.position
+ mh
.length
);
2555 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2560 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
2564 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
2565 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
2566 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
2567 // Fold changes can affect the drawing of following lines so redraw whole margin
2568 RedrawSelMargin(marginView
.highlightDelimiter
.isEnabled
? -1 : mh
.line
- 1, true);
2570 RedrawSelMargin(mh
.line
);
2574 if ((mh
.modificationType
& SC_MOD_CHANGEFOLD
) && (foldAutomatic
& SC_AUTOMATICFOLD_CHANGE
)) {
2575 FoldChanged(mh
.line
, mh
.foldLevelNow
, mh
.foldLevelPrev
);
2578 // NOW pay the piper WRT "deferred" visual updates
2579 if (IsLastStep(mh
)) {
2584 // If client wants to see this modification
2585 if (mh
.modificationType
& modEventMask
) {
2586 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
2587 // Real modification made to text of document.
2588 NotifyChange(); // Send EN_CHANGE
2591 SCNotification scn
= {};
2592 scn
.nmhdr
.code
= SCN_MODIFIED
;
2593 scn
.position
= mh
.position
;
2594 scn
.modificationType
= mh
.modificationType
;
2596 scn
.length
= mh
.length
;
2597 scn
.linesAdded
= mh
.linesAdded
;
2599 scn
.foldLevelNow
= mh
.foldLevelNow
;
2600 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2601 scn
.token
= mh
.token
;
2602 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
2607 void Editor::NotifyDeleted(Document
*, void *) {
2611 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2613 // Enumerates all macroable messages
2619 case SCI_REPLACESEL
:
2621 case SCI_INSERTTEXT
:
2622 case SCI_APPENDTEXT
:
2627 case SCI_SEARCHANCHOR
:
2628 case SCI_SEARCHNEXT
:
2629 case SCI_SEARCHPREV
:
2631 case SCI_LINEDOWNEXTEND
:
2633 case SCI_PARADOWNEXTEND
:
2635 case SCI_LINEUPEXTEND
:
2637 case SCI_PARAUPEXTEND
:
2639 case SCI_CHARLEFTEXTEND
:
2641 case SCI_CHARRIGHTEXTEND
:
2643 case SCI_WORDLEFTEXTEND
:
2645 case SCI_WORDRIGHTEXTEND
:
2646 case SCI_WORDPARTLEFT
:
2647 case SCI_WORDPARTLEFTEXTEND
:
2648 case SCI_WORDPARTRIGHT
:
2649 case SCI_WORDPARTRIGHTEXTEND
:
2650 case SCI_WORDLEFTEND
:
2651 case SCI_WORDLEFTENDEXTEND
:
2652 case SCI_WORDRIGHTEND
:
2653 case SCI_WORDRIGHTENDEXTEND
:
2655 case SCI_HOMEEXTEND
:
2657 case SCI_LINEENDEXTEND
:
2659 case SCI_HOMEWRAPEXTEND
:
2660 case SCI_LINEENDWRAP
:
2661 case SCI_LINEENDWRAPEXTEND
:
2662 case SCI_DOCUMENTSTART
:
2663 case SCI_DOCUMENTSTARTEXTEND
:
2664 case SCI_DOCUMENTEND
:
2665 case SCI_DOCUMENTENDEXTEND
:
2666 case SCI_STUTTEREDPAGEUP
:
2667 case SCI_STUTTEREDPAGEUPEXTEND
:
2668 case SCI_STUTTEREDPAGEDOWN
:
2669 case SCI_STUTTEREDPAGEDOWNEXTEND
:
2671 case SCI_PAGEUPEXTEND
:
2673 case SCI_PAGEDOWNEXTEND
:
2674 case SCI_EDITTOGGLEOVERTYPE
:
2676 case SCI_DELETEBACK
:
2681 case SCI_VCHOMEEXTEND
:
2682 case SCI_VCHOMEWRAP
:
2683 case SCI_VCHOMEWRAPEXTEND
:
2684 case SCI_VCHOMEDISPLAY
:
2685 case SCI_VCHOMEDISPLAYEXTEND
:
2686 case SCI_DELWORDLEFT
:
2687 case SCI_DELWORDRIGHT
:
2688 case SCI_DELWORDRIGHTEND
:
2689 case SCI_DELLINELEFT
:
2690 case SCI_DELLINERIGHT
:
2693 case SCI_LINEDELETE
:
2694 case SCI_LINETRANSPOSE
:
2695 case SCI_LINEDUPLICATE
:
2698 case SCI_LINESCROLLDOWN
:
2699 case SCI_LINESCROLLUP
:
2700 case SCI_DELETEBACKNOTLINE
:
2701 case SCI_HOMEDISPLAY
:
2702 case SCI_HOMEDISPLAYEXTEND
:
2703 case SCI_LINEENDDISPLAY
:
2704 case SCI_LINEENDDISPLAYEXTEND
:
2705 case SCI_SETSELECTIONMODE
:
2706 case SCI_LINEDOWNRECTEXTEND
:
2707 case SCI_LINEUPRECTEXTEND
:
2708 case SCI_CHARLEFTRECTEXTEND
:
2709 case SCI_CHARRIGHTRECTEXTEND
:
2710 case SCI_HOMERECTEXTEND
:
2711 case SCI_VCHOMERECTEXTEND
:
2712 case SCI_LINEENDRECTEXTEND
:
2713 case SCI_PAGEUPRECTEXTEND
:
2714 case SCI_PAGEDOWNRECTEXTEND
:
2715 case SCI_SELECTIONDUPLICATE
:
2716 case SCI_COPYALLOWLINE
:
2717 case SCI_VERTICALCENTRECARET
:
2718 case SCI_MOVESELECTEDLINESUP
:
2719 case SCI_MOVESELECTEDLINESDOWN
:
2720 case SCI_SCROLLTOSTART
:
2721 case SCI_SCROLLTOEND
:
2724 // Filter out all others like display changes. Also, newlines are redundant
2725 // with char insert messages.
2728 // printf("Filtered out %ld of macro recording\n", iMessage);
2732 // Send notification
2733 SCNotification scn
= {};
2734 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2735 scn
.message
= iMessage
;
2736 scn
.wParam
= wParam
;
2737 scn
.lParam
= lParam
;
2741 // Something has changed that the container should know about
2742 void Editor::ContainerNeedsUpdate(int flags
) {
2743 needUpdateUI
|= flags
;
2747 * Force scroll and keep position relative to top of window.
2749 * If stuttered = true and not already at first/last row, move to first/last row of window.
2750 * If stuttered = true and already at first/last row, scroll as normal.
2752 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
2754 SelectionPosition newPos
;
2756 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
2757 int topStutterLine
= topLine
+ caretYSlop
;
2758 int bottomStutterLine
=
2759 pdoc
->LineFromPosition(PositionFromLocation(
2760 Point::FromInts(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
2763 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
2764 topLineNew
= topLine
;
2765 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
2766 false, false, UserVirtualSpace());
2768 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
2769 topLineNew
= topLine
;
2770 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
2771 false, false, UserVirtualSpace());
2774 Point pt
= LocationFromPosition(sel
.MainCaret());
2776 topLineNew
= Platform::Clamp(
2777 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2778 newPos
= SPositionFromLocation(
2779 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(pt
.y
) + direction
* (vs
.lineHeight
* LinesToScroll())),
2780 false, false, UserVirtualSpace());
2783 if (topLineNew
!= topLine
) {
2784 SetTopLine(topLineNew
);
2785 MovePositionTo(newPos
, selt
);
2787 SetVerticalScrollPos();
2789 MovePositionTo(newPos
, selt
);
2793 void Editor::ChangeCaseOfSelection(int caseMapping
) {
2795 for (size_t r
=0; r
<sel
.Count(); r
++) {
2796 SelectionRange current
= sel
.Range(r
);
2797 SelectionRange currentNoVS
= current
;
2798 currentNoVS
.ClearVirtualSpace();
2799 size_t rangeBytes
= currentNoVS
.Length();
2800 if (rangeBytes
> 0) {
2801 std::string sText
= RangeText(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
2803 std::string sMapped
= CaseMapString(sText
, caseMapping
);
2805 if (sMapped
!= sText
) {
2806 size_t firstDifference
= 0;
2807 while (sMapped
[firstDifference
] == sText
[firstDifference
])
2809 size_t lastDifferenceText
= sText
.size() - 1;
2810 size_t lastDifferenceMapped
= sMapped
.size() - 1;
2811 while (sMapped
[lastDifferenceMapped
] == sText
[lastDifferenceText
]) {
2812 lastDifferenceText
--;
2813 lastDifferenceMapped
--;
2815 size_t endDifferenceText
= sText
.size() - 1 - lastDifferenceText
;
2817 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2818 static_cast<int>(rangeBytes
- firstDifference
- endDifferenceText
));
2819 const int lengthChange
= static_cast<int>(lastDifferenceMapped
- firstDifference
+ 1);
2820 const int lengthInserted
= pdoc
->InsertString(
2821 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2822 sMapped
.c_str() + firstDifference
,
2824 // Automatic movement changes selection so reset to exactly the same as it was.
2825 int diffSizes
= static_cast<int>(sMapped
.size() - sText
.size()) + lengthInserted
- lengthChange
;
2826 if (diffSizes
!= 0) {
2827 if (current
.anchor
> current
.caret
)
2828 current
.anchor
.Add(diffSizes
);
2830 current
.caret
.Add(diffSizes
);
2832 sel
.Range(r
) = current
;
2838 void Editor::LineTranspose() {
2839 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2843 const int startPrevious
= pdoc
->LineStart(line
- 1);
2844 const std::string linePrevious
= RangeText(startPrevious
, pdoc
->LineEnd(line
- 1));
2846 int startCurrent
= pdoc
->LineStart(line
);
2847 const std::string lineCurrent
= RangeText(startCurrent
, pdoc
->LineEnd(line
));
2849 pdoc
->DeleteChars(startCurrent
, static_cast<int>(lineCurrent
.length()));
2850 pdoc
->DeleteChars(startPrevious
, static_cast<int>(linePrevious
.length()));
2851 startCurrent
-= static_cast<int>(linePrevious
.length());
2853 startCurrent
+= pdoc
->InsertString(startPrevious
, lineCurrent
.c_str(),
2854 static_cast<int>(lineCurrent
.length()));
2855 pdoc
->InsertString(startCurrent
, linePrevious
.c_str(),
2856 static_cast<int>(linePrevious
.length()));
2857 // Move caret to start of current line
2858 MovePositionTo(SelectionPosition(startCurrent
));
2862 void Editor::Duplicate(bool forLine
) {
2867 const char *eol
= "";
2870 eol
= StringFromEOLMode(pdoc
->eolMode
);
2871 eolLen
= istrlen(eol
);
2873 for (size_t r
=0; r
<sel
.Count(); r
++) {
2874 SelectionPosition start
= sel
.Range(r
).Start();
2875 SelectionPosition end
= sel
.Range(r
).End();
2877 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2878 start
= SelectionPosition(pdoc
->LineStart(line
));
2879 end
= SelectionPosition(pdoc
->LineEnd(line
));
2881 std::string text
= RangeText(start
.Position(), end
.Position());
2882 int lengthInserted
= eolLen
;
2884 lengthInserted
= pdoc
->InsertString(end
.Position(), eol
, eolLen
);
2885 pdoc
->InsertString(end
.Position() + lengthInserted
, text
.c_str(), static_cast<int>(text
.length()));
2887 if (sel
.Count() && sel
.IsRectangular()) {
2888 SelectionPosition last
= sel
.Last();
2890 int line
= pdoc
->LineFromPosition(last
.Position());
2891 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
2893 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
2894 sel
.Rectangular().anchor
= last
;
2896 sel
.Rectangular().caret
= last
;
2897 SetRectangularRange();
2901 void Editor::CancelModes() {
2902 sel
.SetMoveExtends(false);
2905 void Editor::NewLine() {
2906 // Remove non-main ranges
2907 InvalidateSelection(sel
.RangeMain(), true);
2908 sel
.SetSelection(sel
.RangeMain());
2909 sel
.RangeMain().ClearVirtualSpace();
2911 // Clear main range and insert line end
2912 bool needGroupUndo
= !sel
.Empty();
2914 pdoc
->BeginUndoAction();
2918 const char *eol
= "\n";
2919 if (pdoc
->eolMode
== SC_EOL_CRLF
) {
2921 } else if (pdoc
->eolMode
== SC_EOL_CR
) {
2923 } // else SC_EOL_LF -> "\n" already set
2924 const int insertLength
= pdoc
->InsertString(sel
.MainCaret(), eol
, istrlen(eol
));
2925 // Want to end undo group before NotifyChar as applications often modify text here
2927 pdoc
->EndUndoAction();
2928 if (insertLength
> 0) {
2929 SetEmptySelection(sel
.MainCaret() + insertLength
);
2932 if (recordingMacro
) {
2936 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
2943 EnsureCaretVisible();
2944 // Avoid blinking during rapid typing:
2945 ShowCaretAtCurrentPosition();
2948 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
2949 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
2950 if (sel
.IsRectangular()) {
2951 if (selt
== Selection::noSel
) {
2952 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
2954 caretToUse
= sel
.Rectangular().caret
;
2958 Point pt
= LocationFromPosition(caretToUse
);
2961 if (vs
.annotationVisible
) {
2962 int lineDoc
= pdoc
->LineFromPosition(caretToUse
.Position());
2963 Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
2964 int subLine
= static_cast<int>(pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
2966 if (direction
< 0 && subLine
== 0) {
2967 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
2968 if (lineDisplay
> 0) {
2969 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
2971 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
2972 skipLines
= pdoc
->AnnotationLines(lineDoc
);
2976 int newY
= static_cast<int>(pt
.y
) + (1 + skipLines
) * direction
* vs
.lineHeight
;
2977 SelectionPosition posNew
= SPositionFromLocation(
2978 Point::FromInts(lastXChosen
- xOffset
, newY
), false, false, UserVirtualSpace());
2980 if (direction
< 0) {
2981 // Line wrapping may lead to a location on the same line, so
2982 // seek back if that is the case.
2983 Point ptNew
= LocationFromPosition(posNew
.Position());
2984 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
2986 posNew
.SetVirtualSpace(0);
2987 ptNew
= LocationFromPosition(posNew
.Position());
2989 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
2990 // There is an equivalent case when moving down which skips
2992 Point ptNew
= LocationFromPosition(posNew
.Position());
2993 while ((posNew
.Position() > caretToUse
.Position()) && (ptNew
.y
> newY
)) {
2995 posNew
.SetVirtualSpace(0);
2996 ptNew
= LocationFromPosition(posNew
.Position());
3000 MovePositionTo(MovePositionSoVisible(posNew
, direction
), selt
);
3003 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
3004 int lineDoc
, savedPos
= sel
.MainCaret();
3006 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
3007 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
3008 if (direction
> 0) {
3009 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
3010 if (selt
== Selection::noSel
) {
3011 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
3016 } while (!cs
.GetVisible(lineDoc
));
3019 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3021 AutoSurface
surface(this);
3022 int posRet
= view
.StartEndDisplayLine(surface
, *this, pos
, start
, vs
);
3023 if (posRet
== INVALID_POSITION
) {
3030 int Editor::KeyCommand(unsigned int iMessage
) {
3035 case SCI_LINEDOWNEXTEND
:
3036 CursorUpOrDown(1, Selection::selStream
);
3038 case SCI_LINEDOWNRECTEXTEND
:
3039 CursorUpOrDown(1, Selection::selRectangle
);
3044 case SCI_PARADOWNEXTEND
:
3045 ParaUpOrDown(1, Selection::selStream
);
3047 case SCI_LINESCROLLDOWN
:
3048 ScrollTo(topLine
+ 1);
3049 MoveCaretInsideView(false);
3054 case SCI_LINEUPEXTEND
:
3055 CursorUpOrDown(-1, Selection::selStream
);
3057 case SCI_LINEUPRECTEXTEND
:
3058 CursorUpOrDown(-1, Selection::selRectangle
);
3063 case SCI_PARAUPEXTEND
:
3064 ParaUpOrDown(-1, Selection::selStream
);
3066 case SCI_LINESCROLLUP
:
3067 ScrollTo(topLine
- 1);
3068 MoveCaretInsideView(false);
3071 if (SelectionEmpty() || sel
.MoveExtends()) {
3072 if ((sel
.Count() == 1) && pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3073 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3074 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3075 MovePositionTo(spCaret
);
3076 } else if (sel
.MoveExtends() && sel
.selType
== Selection::selStream
) {
3077 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1));
3079 MovePositionTo(MovePositionSoVisible(
3080 SelectionPosition((sel
.LimitsForRectangularElseMain().start
).Position() - 1), -1));
3083 MovePositionTo(sel
.LimitsForRectangularElseMain().start
);
3087 case SCI_CHARLEFTEXTEND
:
3088 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3089 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3090 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3091 MovePositionTo(spCaret
, Selection::selStream
);
3093 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selStream
);
3097 case SCI_CHARLEFTRECTEXTEND
:
3098 if (pdoc
->IsLineEndPosition(sel
.MainCaret()) && sel
.RangeMain().caret
.VirtualSpace()) {
3099 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3100 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3101 MovePositionTo(spCaret
, Selection::selRectangle
);
3103 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() - 1), -1), Selection::selRectangle
);
3108 if (SelectionEmpty() || sel
.MoveExtends()) {
3109 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3110 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3111 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3112 MovePositionTo(spCaret
);
3113 } else if (sel
.MoveExtends() && sel
.selType
== Selection::selStream
) {
3114 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1));
3116 MovePositionTo(MovePositionSoVisible(
3117 SelectionPosition((sel
.LimitsForRectangularElseMain().end
).Position() + 1), 1));
3120 MovePositionTo(sel
.LimitsForRectangularElseMain().end
);
3124 case SCI_CHARRIGHTEXTEND
:
3125 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3126 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3127 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3128 MovePositionTo(spCaret
, Selection::selStream
);
3130 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selStream
);
3134 case SCI_CHARRIGHTRECTEXTEND
:
3135 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3136 SelectionPosition spCaret
= sel
.RangeMain().caret
;
3137 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3138 MovePositionTo(spCaret
, Selection::selRectangle
);
3140 MovePositionTo(MovePositionSoVisible(SelectionPosition(sel
.MainCaret() + 1), 1), Selection::selRectangle
);
3145 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1));
3148 case SCI_WORDLEFTEXTEND
:
3149 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), -1), -1), Selection::selStream
);
3153 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1));
3156 case SCI_WORDRIGHTEXTEND
:
3157 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordStart(sel
.MainCaret(), 1), 1), Selection::selStream
);
3161 case SCI_WORDLEFTEND
:
3162 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1));
3165 case SCI_WORDLEFTENDEXTEND
:
3166 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), -1), -1), Selection::selStream
);
3169 case SCI_WORDRIGHTEND
:
3170 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1));
3173 case SCI_WORDRIGHTENDEXTEND
:
3174 MovePositionTo(MovePositionSoVisible(pdoc
->NextWordEnd(sel
.MainCaret(), 1), 1), Selection::selStream
);
3179 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3182 case SCI_HOMEEXTEND
:
3183 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selStream
);
3186 case SCI_HOMERECTEXTEND
:
3187 MovePositionTo(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())), Selection::selRectangle
);
3191 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()));
3194 case SCI_LINEENDEXTEND
:
3195 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selStream
);
3198 case SCI_LINEENDRECTEXTEND
:
3199 MovePositionTo(pdoc
->LineEndPosition(sel
.MainCaret()), Selection::selRectangle
);
3202 case SCI_HOMEWRAP
: {
3203 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3204 if (sel
.RangeMain().caret
<= homePos
)
3205 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3206 MovePositionTo(homePos
);
3210 case SCI_HOMEWRAPEXTEND
: {
3211 SelectionPosition homePos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3212 if (sel
.RangeMain().caret
<= homePos
)
3213 homePos
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret())));
3214 MovePositionTo(homePos
, Selection::selStream
);
3218 case SCI_LINEENDWRAP
: {
3219 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
3220 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
3221 if (endPos
> realEndPos
// if moved past visible EOLs
3222 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
3223 endPos
= realEndPos
;
3224 MovePositionTo(endPos
);
3228 case SCI_LINEENDWRAPEXTEND
: {
3229 SelectionPosition endPos
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), false), 1);
3230 SelectionPosition realEndPos
= SelectionPosition(pdoc
->LineEndPosition(sel
.MainCaret()));
3231 if (endPos
> realEndPos
// if moved past visible EOLs
3232 || sel
.RangeMain().caret
>= endPos
) // if at end of display line already
3233 endPos
= realEndPos
;
3234 MovePositionTo(endPos
, Selection::selStream
);
3238 case SCI_DOCUMENTSTART
:
3242 case SCI_DOCUMENTSTARTEXTEND
:
3243 MovePositionTo(0, Selection::selStream
);
3246 case SCI_DOCUMENTEND
:
3247 MovePositionTo(pdoc
->Length());
3250 case SCI_DOCUMENTENDEXTEND
:
3251 MovePositionTo(pdoc
->Length(), Selection::selStream
);
3254 case SCI_STUTTEREDPAGEUP
:
3255 PageMove(-1, Selection::noSel
, true);
3257 case SCI_STUTTEREDPAGEUPEXTEND
:
3258 PageMove(-1, Selection::selStream
, true);
3260 case SCI_STUTTEREDPAGEDOWN
:
3261 PageMove(1, Selection::noSel
, true);
3263 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3264 PageMove(1, Selection::selStream
, true);
3269 case SCI_PAGEUPEXTEND
:
3270 PageMove(-1, Selection::selStream
);
3272 case SCI_PAGEUPRECTEXTEND
:
3273 PageMove(-1, Selection::selRectangle
);
3278 case SCI_PAGEDOWNEXTEND
:
3279 PageMove(1, Selection::selStream
);
3281 case SCI_PAGEDOWNRECTEXTEND
:
3282 PageMove(1, Selection::selRectangle
);
3284 case SCI_EDITTOGGLEOVERTYPE
:
3285 inOverstrike
= !inOverstrike
;
3287 ShowCaretAtCurrentPosition();
3288 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
3291 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3292 // Also unselect text
3295 case SCI_DELETEBACK
:
3297 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3300 EnsureCaretVisible();
3302 case SCI_DELETEBACKNOTLINE
:
3304 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3307 EnsureCaretVisible();
3311 if (caretSticky
== SC_CARETSTICKY_OFF
) {
3314 EnsureCaretVisible();
3315 ShowCaretAtCurrentPosition(); // Avoid blinking
3319 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3322 EnsureCaretVisible();
3323 ShowCaretAtCurrentPosition(); // Avoid blinking
3332 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()));
3335 case SCI_VCHOMEEXTEND
:
3336 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selStream
);
3339 case SCI_VCHOMERECTEXTEND
:
3340 MovePositionTo(pdoc
->VCHomePosition(sel
.MainCaret()), Selection::selRectangle
);
3343 case SCI_VCHOMEWRAP
: {
3344 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3345 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3346 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
3347 homePos
= viewLineStart
;
3349 MovePositionTo(homePos
);
3353 case SCI_VCHOMEWRAPEXTEND
: {
3354 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3355 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3356 if ((viewLineStart
< sel
.RangeMain().caret
) && (viewLineStart
> homePos
))
3357 homePos
= viewLineStart
;
3359 MovePositionTo(homePos
, Selection::selStream
);
3364 if (vs
.zoomLevel
< 20) {
3366 InvalidateStyleRedraw();
3371 if (vs
.zoomLevel
> -10) {
3373 InvalidateStyleRedraw();
3377 case SCI_DELWORDLEFT
: {
3378 int startWord
= pdoc
->NextWordStart(sel
.MainCaret(), -1);
3379 pdoc
->DeleteChars(startWord
, sel
.MainCaret() - startWord
);
3380 sel
.RangeMain().ClearVirtualSpace();
3384 case SCI_DELWORDRIGHT
: {
3386 InvalidateSelection(sel
.RangeMain(), true);
3387 sel
.RangeMain().caret
= SelectionPosition(
3388 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
3389 sel
.RangeMain().anchor
= sel
.RangeMain().caret
;
3390 int endWord
= pdoc
->NextWordStart(sel
.MainCaret(), 1);
3391 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
3394 case SCI_DELWORDRIGHTEND
: {
3396 InvalidateSelection(sel
.RangeMain(), true);
3397 sel
.RangeMain().caret
= SelectionPosition(
3398 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
3399 int endWord
= pdoc
->NextWordEnd(sel
.MainCaret(), 1);
3400 pdoc
->DeleteChars(sel
.MainCaret(), endWord
- sel
.MainCaret());
3403 case SCI_DELLINELEFT
: {
3404 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3405 int start
= pdoc
->LineStart(line
);
3406 pdoc
->DeleteChars(start
, sel
.MainCaret() - start
);
3407 sel
.RangeMain().ClearVirtualSpace();
3411 case SCI_DELLINERIGHT
: {
3412 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3413 int end
= pdoc
->LineEnd(line
);
3414 pdoc
->DeleteChars(sel
.MainCaret(), end
- sel
.MainCaret());
3417 case SCI_LINECOPY
: {
3418 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3419 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3420 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3421 pdoc
->LineStart(lineEnd
+ 1));
3425 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3426 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3427 int start
= pdoc
->LineStart(lineStart
);
3428 int end
= pdoc
->LineStart(lineEnd
+ 1);
3429 SetSelection(start
, end
);
3434 case SCI_LINEDELETE
: {
3435 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3436 int start
= pdoc
->LineStart(line
);
3437 int end
= pdoc
->LineStart(line
+ 1);
3438 pdoc
->DeleteChars(start
, end
- start
);
3441 case SCI_LINETRANSPOSE
:
3444 case SCI_LINEDUPLICATE
:
3447 case SCI_SELECTIONDUPLICATE
:
3451 ChangeCaseOfSelection(cmLower
);
3454 ChangeCaseOfSelection(cmUpper
);
3456 case SCI_WORDPARTLEFT
:
3457 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1));
3460 case SCI_WORDPARTLEFTEXTEND
:
3461 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartLeft(sel
.MainCaret()), -1), Selection::selStream
);
3464 case SCI_WORDPARTRIGHT
:
3465 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1));
3468 case SCI_WORDPARTRIGHTEXTEND
:
3469 MovePositionTo(MovePositionSoVisible(pdoc
->WordPartRight(sel
.MainCaret()), 1), Selection::selStream
);
3472 case SCI_HOMEDISPLAY
:
3473 MovePositionTo(MovePositionSoVisible(
3474 StartEndDisplayLine(sel
.MainCaret(), true), -1));
3477 case SCI_VCHOMEDISPLAY
: {
3478 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3479 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3480 if (viewLineStart
> homePos
)
3481 homePos
= viewLineStart
;
3483 MovePositionTo(homePos
);
3487 case SCI_HOMEDISPLAYEXTEND
:
3488 MovePositionTo(MovePositionSoVisible(
3489 StartEndDisplayLine(sel
.MainCaret(), true), -1), Selection::selStream
);
3492 case SCI_VCHOMEDISPLAYEXTEND
: {
3493 SelectionPosition homePos
= SelectionPosition(pdoc
->VCHomePosition(sel
.MainCaret()));
3494 SelectionPosition viewLineStart
= MovePositionSoVisible(StartEndDisplayLine(sel
.MainCaret(), true), -1);
3495 if (viewLineStart
> homePos
)
3496 homePos
= viewLineStart
;
3498 MovePositionTo(homePos
, Selection::selStream
);
3502 case SCI_LINEENDDISPLAY
:
3503 MovePositionTo(MovePositionSoVisible(
3504 StartEndDisplayLine(sel
.MainCaret(), false), 1));
3507 case SCI_LINEENDDISPLAYEXTEND
:
3508 MovePositionTo(MovePositionSoVisible(
3509 StartEndDisplayLine(sel
.MainCaret(), false), 1), Selection::selStream
);
3512 case SCI_SCROLLTOSTART
:
3515 case SCI_SCROLLTOEND
:
3516 ScrollTo(MaxScrollPos());
3522 int Editor::KeyDefault(int, int) {
3526 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
3528 int msg
= kmap
.Find(key
, modifiers
);
3532 return static_cast<int>(WndProc(msg
, 0, 0));
3536 return KeyDefault(key
, modifiers
);
3540 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3541 return KeyDownWithModifiers(key
, ModifierFlags(shift
, ctrl
, alt
), consumed
);
3544 void Editor::Indent(bool forwards
) {
3546 for (size_t r
=0; r
<sel
.Count(); r
++) {
3547 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
3548 int caretPosition
= sel
.Range(r
).caret
.Position();
3549 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
3550 if (lineOfAnchor
== lineCurrentPos
) {
3552 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
3553 caretPosition
= sel
.Range(r
).caret
.Position();
3554 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3556 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3557 int indentationStep
= pdoc
->IndentSize();
3558 const int posSelect
= pdoc
->SetLineIndentation(
3559 lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
3560 sel
.Range(r
) = SelectionRange(posSelect
);
3562 if (pdoc
->useTabs
) {
3563 const int lengthInserted
= pdoc
->InsertString(caretPosition
, "\t", 1);
3564 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3566 int numSpaces
= (pdoc
->tabInChars
) -
3567 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
3569 numSpaces
= pdoc
->tabInChars
;
3570 const std::string
spaceText(numSpaces
, ' ');
3571 const int lengthInserted
= pdoc
->InsertString(caretPosition
, spaceText
.c_str(),
3572 static_cast<int>(spaceText
.length()));
3573 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3577 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3579 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3580 int indentationStep
= pdoc
->IndentSize();
3581 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3582 sel
.Range(r
) = SelectionRange(posSelect
);
3584 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
3588 int newPos
= caretPosition
;
3589 while (pdoc
->GetColumn(newPos
) > newColumn
)
3591 sel
.Range(r
) = SelectionRange(newPos
);
3594 } else { // Multiline
3595 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
3596 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
3597 // Multiple lines selected so indent / dedent
3598 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3599 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3600 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
3601 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3602 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3603 if (lineOfAnchor
< lineCurrentPos
) {
3604 if (currentPosPosOnLine
== 0)
3605 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3607 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3609 if (anchorPosOnLine
== 0)
3610 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3612 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3616 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
3619 class CaseFolderASCII
: public CaseFolderTable
{
3624 ~CaseFolderASCII() {
3629 CaseFolder
*Editor::CaseFolderForEncoding() {
3630 // Simple default that only maps ASCII upper case to lower case.
3631 return new CaseFolderASCII();
3635 * Search of a text in the document, in the given range.
3636 * @return The position of the found text, -1 if not found.
3638 long Editor::FindText(
3639 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3640 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3641 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3643 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
3644 int lengthFound
= istrlen(ft
->lpstrText
);
3645 if (!pdoc
->HasCaseFolder())
3646 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3648 int pos
= pdoc
->FindText(ft
->chrg
.cpMin
, ft
->chrg
.cpMax
, ft
->lpstrText
,
3649 (wParam
& SCFIND_MATCHCASE
) != 0,
3650 (wParam
& SCFIND_WHOLEWORD
) != 0,
3651 (wParam
& SCFIND_WORDSTART
) != 0,
3652 (wParam
& SCFIND_REGEXP
) != 0,
3653 static_cast<int>(wParam
),
3656 ft
->chrgText
.cpMin
= pos
;
3657 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3660 } catch (RegexError
&) {
3661 errorStatus
= SC_STATUS_WARN_REGEX
;
3667 * Relocatable search support : Searches relative to current selection
3668 * point and sets the selection to the found text range with
3672 * Anchor following searches at current selection start: This allows
3673 * multiple incremental interactive searches to be macro recorded
3674 * while still setting the selection to found text so the find/select
3675 * operation is self-contained.
3677 void Editor::SearchAnchor() {
3678 searchAnchor
= SelectionStart().Position();
3682 * Find text from current search anchor: Must call @c SearchAnchor first.
3683 * Used for next text and previous text requests.
3684 * @return The position of the found text, -1 if not found.
3686 long Editor::SearchText(
3687 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3688 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3689 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3690 sptr_t lParam
) { ///< The text to search for.
3692 const char *txt
= reinterpret_cast<char *>(lParam
);
3694 int lengthFound
= istrlen(txt
);
3695 if (!pdoc
->HasCaseFolder())
3696 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3698 if (iMessage
== SCI_SEARCHNEXT
) {
3699 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3700 (wParam
& SCFIND_MATCHCASE
) != 0,
3701 (wParam
& SCFIND_WHOLEWORD
) != 0,
3702 (wParam
& SCFIND_WORDSTART
) != 0,
3703 (wParam
& SCFIND_REGEXP
) != 0,
3704 static_cast<int>(wParam
),
3707 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3708 (wParam
& SCFIND_MATCHCASE
) != 0,
3709 (wParam
& SCFIND_WHOLEWORD
) != 0,
3710 (wParam
& SCFIND_WORDSTART
) != 0,
3711 (wParam
& SCFIND_REGEXP
) != 0,
3712 static_cast<int>(wParam
),
3715 } catch (RegexError
&) {
3716 errorStatus
= SC_STATUS_WARN_REGEX
;
3720 SetSelection(pos
, pos
+ lengthFound
);
3726 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
3728 for (size_t i
=0; i
<ret
.size(); i
++) {
3729 switch (caseMapping
) {
3731 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
3732 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
3735 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
3736 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
3744 * Search for text in the target range of the document.
3745 * @return The position of the found text, -1 if not found.
3747 long Editor::SearchInTarget(const char *text
, int length
) {
3748 int lengthFound
= length
;
3750 if (!pdoc
->HasCaseFolder())
3751 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3753 int pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
3754 (searchFlags
& SCFIND_MATCHCASE
) != 0,
3755 (searchFlags
& SCFIND_WHOLEWORD
) != 0,
3756 (searchFlags
& SCFIND_WORDSTART
) != 0,
3757 (searchFlags
& SCFIND_REGEXP
) != 0,
3762 targetEnd
= pos
+ lengthFound
;
3765 } catch (RegexError
&) {
3766 errorStatus
= SC_STATUS_WARN_REGEX
;
3771 void Editor::GoToLine(int lineNo
) {
3772 if (lineNo
> pdoc
->LinesTotal())
3773 lineNo
= pdoc
->LinesTotal();
3776 SetEmptySelection(pdoc
->LineStart(lineNo
));
3777 ShowCaretAtCurrentPosition();
3778 EnsureCaretVisible();
3781 static bool Close(Point pt1
, Point pt2
, Point threshold
) {
3782 if (abs(pt1
.x
- pt2
.x
) > threshold
.x
)
3784 if (abs(pt1
.y
- pt2
.y
) > threshold
.y
)
3789 std::string
Editor::RangeText(int start
, int end
) const {
3791 int len
= end
- start
;
3792 std::string
ret(len
, '\0');
3793 for (int i
= 0; i
< len
; i
++) {
3794 ret
[i
] = pdoc
->CharAt(start
+ i
);
3798 return std::string();
3801 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
3803 if (allowLineCopy
) {
3804 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
3805 int start
= pdoc
->LineStart(currentLine
);
3806 int end
= pdoc
->LineEnd(currentLine
);
3808 std::string text
= RangeText(start
, end
);
3809 if (pdoc
->eolMode
!= SC_EOL_LF
)
3810 text
.push_back('\r');
3811 if (pdoc
->eolMode
!= SC_EOL_CR
)
3812 text
.push_back('\n');
3813 ss
->Copy(text
, pdoc
->dbcsCodePage
,
3814 vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
3818 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
3819 if (sel
.selType
== Selection::selRectangle
)
3820 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
3821 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
3822 SelectionRange current
= rangesInOrder
[r
];
3823 text
.append(RangeText(current
.Start().Position(), current
.End().Position()));
3824 if (sel
.selType
== Selection::selRectangle
) {
3825 if (pdoc
->eolMode
!= SC_EOL_LF
)
3826 text
.push_back('\r');
3827 if (pdoc
->eolMode
!= SC_EOL_CR
)
3828 text
.push_back('\n');
3831 ss
->Copy(text
, pdoc
->dbcsCodePage
,
3832 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
3836 void Editor::CopyRangeToClipboard(int start
, int end
) {
3837 start
= pdoc
->ClampPositionIntoDocument(start
);
3838 end
= pdoc
->ClampPositionIntoDocument(end
);
3839 SelectionText selectedText
;
3840 std::string text
= RangeText(start
, end
);
3841 selectedText
.Copy(text
,
3842 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
3843 CopyToClipboard(selectedText
);
3846 void Editor::CopyText(int length
, const char *text
) {
3847 SelectionText selectedText
;
3848 selectedText
.Copy(std::string(text
, length
),
3849 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
3850 CopyToClipboard(selectedText
);
3853 void Editor::SetDragPosition(SelectionPosition newPos
) {
3854 if (newPos
.Position() >= 0) {
3855 newPos
= MovePositionOutsideChar(newPos
, 1);
3858 if (!(posDrag
== newPos
)) {
3860 if (FineTickerAvailable()) {
3861 FineTickerCancel(tickCaret
);
3862 if ((caret
.active
) && (caret
.period
> 0) && (newPos
.Position() < 0))
3863 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
3873 void Editor::DisplayCursor(Window::Cursor c
) {
3874 if (cursorMode
== SC_CURSORNORMAL
)
3877 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
3880 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
3881 int xMove
= static_cast<int>(ptStart
.x
- ptNow
.x
);
3882 int yMove
= static_cast<int>(ptStart
.y
- ptNow
.y
);
3883 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
3884 return distanceSquared
> 16;
3887 void Editor::StartDrag() {
3888 // Always handled by subclasses
3889 //SetMouseCapture(true);
3890 //DisplayCursor(Window::cursorArrow);
3893 void Editor::DropAt(SelectionPosition position
, const char *value
, size_t lengthValue
, bool moving
, bool rectangular
) {
3894 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
3895 if (inDragDrop
== ddDragging
)
3896 dropWentOutside
= false;
3898 bool positionWasInSelection
= PositionInSelection(position
.Position());
3900 bool positionOnEdgeOfSelection
=
3901 (position
== SelectionStart()) || (position
== SelectionEnd());
3903 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
3904 (positionOnEdgeOfSelection
&& !moving
)) {
3906 SelectionPosition selStart
= SelectionStart();
3907 SelectionPosition selEnd
= SelectionEnd();
3911 SelectionPosition positionAfterDeletion
= position
;
3912 if ((inDragDrop
== ddDragging
) && moving
) {
3913 // Remove dragged out text
3914 if (rectangular
|| sel
.selType
== Selection::selLines
) {
3915 for (size_t r
=0; r
<sel
.Count(); r
++) {
3916 if (position
>= sel
.Range(r
).Start()) {
3917 if (position
> sel
.Range(r
).End()) {
3918 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
3920 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
3925 if (position
> selStart
) {
3926 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
3931 position
= positionAfterDeletion
;
3933 std::string convertedText
= Document::TransformLineEnds(value
, lengthValue
, pdoc
->eolMode
);
3936 PasteRectangular(position
, convertedText
.c_str(), static_cast<int>(convertedText
.length()));
3937 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
3938 SetEmptySelection(position
);
3940 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
3941 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
3942 const int lengthInserted
= pdoc
->InsertString(
3943 position
.Position(), convertedText
.c_str(), static_cast<int>(convertedText
.length()));
3944 if (lengthInserted
> 0) {
3945 SelectionPosition posAfterInsertion
= position
;
3946 posAfterInsertion
.Add(lengthInserted
);
3947 SetSelection(posAfterInsertion
, position
);
3950 } else if (inDragDrop
== ddDragging
) {
3951 SetEmptySelection(position
);
3955 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
3956 DropAt(position
, value
, strlen(value
), moving
, rectangular
);
3960 * @return true if given position is inside the selection,
3962 bool Editor::PositionInSelection(int pos
) {
3963 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
3964 for (size_t r
=0; r
<sel
.Count(); r
++) {
3965 if (sel
.Range(r
).Contains(pos
))
3971 bool Editor::PointInSelection(Point pt
) {
3972 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
3973 Point ptPos
= LocationFromPosition(pos
);
3974 for (size_t r
=0; r
<sel
.Count(); r
++) {
3975 SelectionRange range
= sel
.Range(r
);
3976 if (range
.Contains(pos
)) {
3978 if (pos
== range
.Start()) {
3979 // see if just before selection
3980 if (pt
.x
< ptPos
.x
) {
3984 if (pos
== range
.End()) {
3985 // see if just after selection
3986 if (pt
.x
> ptPos
.x
) {
3997 bool Editor::PointInSelMargin(Point pt
) const {
3998 // Really means: "Point in a margin"
3999 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4000 PRectangle rcSelMargin
= GetClientRectangle();
4001 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.leftMarginWidth
);
4002 rcSelMargin
.left
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.fixedColumnWidth
);
4003 return rcSelMargin
.Contains(pt
);
4009 Window::Cursor
Editor::GetMarginCursor(Point pt
) const {
4011 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
4012 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4013 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
4014 x
+= vs
.ms
[margin
].width
;
4016 return Window::cursorReverseArrow
;
4019 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
4020 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
4021 SetSelection(currentPos_
, anchor_
);
4024 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
4025 int selCurrentPos
, selAnchorPos
;
4027 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
4028 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
4029 if (lineAnchorPos_
< lineCurrentPos_
) {
4030 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
4031 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4032 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4033 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
4034 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4035 } else { // Same line, select it
4036 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4037 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4040 if (lineAnchorPos_
< lineCurrentPos_
) {
4041 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
4042 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4043 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4044 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4045 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
4046 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4047 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
4048 } else { // Same line, select it
4049 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4050 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4051 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4054 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
4057 void Editor::WordSelection(int pos
) {
4058 if (pos
< wordSelectAnchorStartPos
) {
4059 // Extend backward to the word containing pos.
4060 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
4061 // This ensures that a series of empty lines isn't counted as a single "word".
4062 if (!pdoc
->IsLineEndPosition(pos
))
4063 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
4064 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
4065 } else if (pos
> wordSelectAnchorEndPos
) {
4066 // Extend forward to the word containing the character to the left of pos.
4067 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
4068 // This ensures that a series of empty lines isn't counted as a single "word".
4069 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
4070 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
4071 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
4073 // Select only the anchored word
4074 if (pos
>= originalAnchorPos
)
4075 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
4077 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
4081 void Editor::DwellEnd(bool mouseMoved
) {
4083 ticksToDwell
= dwellDelay
;
4085 ticksToDwell
= SC_TIME_FOREVER
;
4086 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4088 NotifyDwelling(ptMouseLast
, dwelling
);
4090 if (FineTickerAvailable()) {
4091 FineTickerCancel(tickDwell
);
4092 if (mouseMoved
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4093 //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
4098 void Editor::MouseLeave() {
4099 SetHotSpotRange(NULL
);
4100 if (!HaveMouseCapture()) {
4101 ptMouseLast
= Point(-1,-1);
4106 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
4107 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
4108 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
4111 void Editor::ButtonDownWithModifiers(Point pt
, unsigned int curTime
, int modifiers
) {
4112 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
4114 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
4115 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
4116 const bool alt
= (modifiers
& SCI_ALT
) != 0;
4117 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
4118 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4119 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4120 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4121 inDragDrop
= ddNone
;
4122 sel
.SetMoveExtends(false);
4124 if (NotifyMarginClick(pt
, modifiers
))
4127 NotifyIndicatorClick(true, newPos
.Position(), modifiers
);
4129 bool inSelMargin
= PointInSelMargin(pt
);
4130 // In margin ctrl+(double)click should always select everything
4131 if (ctrl
&& inSelMargin
) {
4133 lastClickTime
= curTime
;
4137 if (shift
&& !inSelMargin
) {
4138 SetSelection(newPos
);
4140 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
, doubleClickCloseThreshold
)) {
4141 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4142 SetMouseCapture(true);
4143 if (FineTickerAvailable()) {
4144 FineTickerStart(tickScroll
, 100, 10);
4146 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
4147 SetEmptySelection(newPos
.Position());
4148 bool doubleClick
= false;
4149 // Stop mouse button bounce changing selection type
4150 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4152 // Inside margin selection type should be either selSubLine or selWholeLine.
4153 if (selectionType
== selSubLine
) {
4154 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
4155 // so we switch to selWholeLine in order to select whole line.
4156 selectionType
= selWholeLine
;
4157 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
4158 // If it is neither, reset selection type to line selection.
4159 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4162 if (selectionType
== selChar
) {
4163 selectionType
= selWord
;
4165 } else if (selectionType
== selWord
) {
4166 // Since we ended up here, we're inside a *triple* click, which should always select
4167 // whole line regardless of word wrap being enabled or not.
4168 selectionType
= selWholeLine
;
4170 selectionType
= selChar
;
4171 originalAnchorPos
= sel
.MainCaret();
4176 if (selectionType
== selWord
) {
4177 int charPos
= originalAnchorPos
;
4178 if (sel
.MainCaret() == originalAnchorPos
) {
4179 charPos
= PositionFromLocation(pt
, false, true);
4180 charPos
= MovePositionOutsideChar(charPos
, -1);
4183 int startWord
, endWord
;
4184 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
4185 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
4186 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
4188 // Selecting backwards, or anchor beyond last character on line. In these cases,
4189 // we select the word containing the character to the *left* of the anchor.
4190 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
4191 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
4192 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
4194 // Anchor at start of line; select nothing to begin with.
4195 startWord
= charPos
;
4200 wordSelectAnchorStartPos
= startWord
;
4201 wordSelectAnchorEndPos
= endWord
;
4202 wordSelectInitialCaretPos
= sel
.MainCaret();
4203 WordSelection(wordSelectInitialCaretPos
);
4204 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
4205 lineAnchorPos
= newPos
.Position();
4206 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4207 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4209 SetEmptySelection(sel
.MainCaret());
4211 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4213 NotifyDoubleClick(pt
, modifiers
);
4214 if (PositionIsHotspot(newCharPos
.Position()))
4215 NotifyHotSpotDoubleClicked(newCharPos
.Position(), modifiers
);
4217 } else { // Single click
4219 sel
.selType
= Selection::selStream
;
4221 // Single click in margin: select whole line or only subline if word wrap is enabled
4222 lineAnchorPos
= newPos
.Position();
4223 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4224 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4226 // Single shift+click in margin: select from line anchor to clicked line
4227 if (sel
.MainAnchor() > sel
.MainCaret())
4228 lineAnchorPos
= sel
.MainAnchor() - 1;
4230 lineAnchorPos
= sel
.MainAnchor();
4231 // Reset selection type if there is an empty selection.
4232 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
4233 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
4234 // This ensures that we continue selecting in the same selection mode.
4235 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
4236 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4237 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4240 SetDragPosition(SelectionPosition(invalidPosition
));
4241 SetMouseCapture(true);
4242 if (FineTickerAvailable()) {
4243 FineTickerStart(tickScroll
, 100, 10);
4246 if (PointIsHotspot(pt
)) {
4247 NotifyHotSpotClicked(newCharPos
.Position(), modifiers
);
4248 hotSpotClickPos
= newCharPos
.Position();
4251 if (PointInSelection(pt
) && !SelectionEmpty())
4252 inDragDrop
= ddInitial
;
4254 inDragDrop
= ddNone
;
4256 SetMouseCapture(true);
4257 if (FineTickerAvailable()) {
4258 FineTickerStart(tickScroll
, 100, 10);
4260 if (inDragDrop
!= ddInitial
) {
4261 SetDragPosition(SelectionPosition(invalidPosition
));
4263 if (ctrl
&& multipleSelection
) {
4264 SelectionRange
range(newPos
);
4265 sel
.TentativeSelection(range
);
4266 InvalidateSelection(range
, true);
4268 InvalidateSelection(SelectionRange(newPos
), true);
4269 if (sel
.Count() > 1)
4271 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
4273 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4274 SetSelection(newPos
, newPos
);
4277 SelectionPosition anchorCurrent
= newPos
;
4279 anchorCurrent
= sel
.IsRectangular() ?
4280 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
4281 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4282 selectionType
= selChar
;
4283 originalAnchorPos
= sel
.MainCaret();
4284 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
4285 SetRectangularRange();
4289 lastClickTime
= curTime
;
4291 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4292 ShowCaretAtCurrentPosition();
4295 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4296 return ButtonDownWithModifiers(pt
, curTime
, ModifierFlags(shift
, ctrl
, alt
));
4299 bool Editor::PositionIsHotspot(int position
) const {
4300 return vs
.styles
[static_cast<unsigned char>(pdoc
->StyleAt(position
))].hotspot
;
4303 bool Editor::PointIsHotspot(Point pt
) {
4304 int pos
= PositionFromLocation(pt
, true, true);
4305 if (pos
== INVALID_POSITION
)
4307 return PositionIsHotspot(pos
);
4310 void Editor::SetHotSpotRange(Point
*pt
) {
4312 int pos
= PositionFromLocation(*pt
, false, true);
4314 // If we don't limit this to word characters then the
4315 // range can encompass more than the run range and then
4316 // the underline will not be drawn properly.
4318 hsNew
.start
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4319 hsNew
.end
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4321 // Only invalidate the range if the hotspot range has changed...
4322 if (!(hsNew
== hotspot
)) {
4323 if (hotspot
.Valid()) {
4324 InvalidateRange(hotspot
.start
, hotspot
.end
);
4327 InvalidateRange(hotspot
.start
, hotspot
.end
);
4330 if (hotspot
.Valid()) {
4331 InvalidateRange(hotspot
.start
, hotspot
.end
);
4333 hotspot
= Range(invalidPosition
);
4337 Range
Editor::GetHotSpotRange() const {
4341 void Editor::ButtonMoveWithModifiers(Point pt
, int modifiers
) {
4342 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4346 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
4347 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4348 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
4350 if (inDragDrop
== ddInitial
) {
4351 if (DragThreshold(ptMouseLast
, pt
)) {
4352 SetMouseCapture(false);
4353 if (FineTickerAvailable()) {
4354 FineTickerCancel(tickScroll
);
4356 SetDragPosition(movePos
);
4357 CopySelectionRange(&drag
);
4364 PRectangle rcClient
= GetClientRectangle();
4365 Point ptOrigin
= GetVisibleOriginInMain();
4366 rcClient
.Move(0, -ptOrigin
.y
);
4367 if (FineTickerAvailable() && (dwellDelay
< SC_TIME_FOREVER
) && rcClient
.Contains(pt
)) {
4368 FineTickerStart(tickDwell
, dwellDelay
, dwellDelay
/10);
4370 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4371 if (HaveMouseCapture()) {
4373 // Slow down autoscrolling/selection
4374 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4375 if (autoScrollTimer
.ticksToWait
> 0)
4377 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4380 if (posDrag
.IsValid()) {
4381 SetDragPosition(movePos
);
4383 if (selectionType
== selChar
) {
4384 if (sel
.selType
== Selection::selStream
&& (modifiers
& SCI_ALT
) && mouseSelectionRectangularSwitch
) {
4385 sel
.selType
= Selection::selRectangle
;
4387 if (sel
.IsRectangular()) {
4388 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
4389 SetSelection(movePos
, sel
.RangeMain().anchor
);
4390 } else if (sel
.Count() > 1) {
4391 InvalidateSelection(sel
.RangeMain(), false);
4392 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
4393 sel
.TentativeSelection(range
);
4394 InvalidateSelection(range
, true);
4396 SetSelection(movePos
, sel
.RangeMain().anchor
);
4398 } else if (selectionType
== selWord
) {
4399 // Continue selecting by word
4400 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
4401 // No need to do anything. Previously this case was lumped
4402 // in with "Moved forward", but that can be harmful in this
4403 // case: a handler for the NotifyDoubleClick re-adjusts
4404 // the selection for a fancier definition of "word" (for
4405 // example, in Perl it is useful to include the leading
4406 // '$', '%' or '@' on variables for word selection). In this
4407 // the ButtonMove() called via Tick() for auto-scrolling
4408 // could result in the fancier word selection adjustment
4411 wordSelectInitialCaretPos
= -1;
4412 WordSelection(movePos
.Position());
4415 // Continue selecting by line
4416 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4421 int lineMove
= DisplayFromPosition(movePos
.Position());
4422 if (pt
.y
> rcClient
.bottom
) {
4423 ScrollTo(lineMove
- LinesOnScreen() + 1);
4425 } else if (pt
.y
< rcClient
.top
) {
4429 EnsureCaretVisible(false, false, true);
4431 if (hotspot
.Valid() && !PointIsHotspot(pt
))
4432 SetHotSpotRange(NULL
);
4434 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,true) != hotSpotClickPos
) {
4435 if (inDragDrop
== ddNone
) {
4436 DisplayCursor(Window::cursorText
);
4438 hotSpotClickPos
= INVALID_POSITION
;
4442 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4443 if (PointInSelMargin(pt
)) {
4444 DisplayCursor(GetMarginCursor(pt
));
4445 SetHotSpotRange(NULL
);
4446 return; // No need to test for selection
4449 // Display regular (drag) cursor over selection
4450 if (PointInSelection(pt
) && !SelectionEmpty()) {
4451 DisplayCursor(Window::cursorArrow
);
4452 } else if (PointIsHotspot(pt
)) {
4453 DisplayCursor(Window::cursorHand
);
4454 SetHotSpotRange(&pt
);
4456 DisplayCursor(Window::cursorText
);
4457 SetHotSpotRange(NULL
);
4462 void Editor::ButtonMove(Point pt
) {
4463 ButtonMoveWithModifiers(pt
, 0);
4466 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4467 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
4468 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
4469 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4470 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4471 if (inDragDrop
== ddInitial
) {
4472 inDragDrop
= ddNone
;
4473 SetEmptySelection(newPos
);
4474 selectionType
= selChar
;
4475 originalAnchorPos
= sel
.MainCaret();
4477 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
4478 hotSpotClickPos
= INVALID_POSITION
;
4479 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4480 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4481 NotifyHotSpotReleaseClick(newCharPos
.Position(), ctrl
? SCI_CTRL
: 0);
4483 if (HaveMouseCapture()) {
4484 if (PointInSelMargin(pt
)) {
4485 DisplayCursor(GetMarginCursor(pt
));
4487 DisplayCursor(Window::cursorText
);
4488 SetHotSpotRange(NULL
);
4491 SetMouseCapture(false);
4492 if (FineTickerAvailable()) {
4493 FineTickerCancel(tickScroll
);
4495 NotifyIndicatorClick(false, newPos
.Position(), 0);
4496 if (inDragDrop
== ddDragging
) {
4497 SelectionPosition selStart
= SelectionStart();
4498 SelectionPosition selEnd
= SelectionEnd();
4499 if (selStart
< selEnd
) {
4500 if (drag
.Length()) {
4501 const int length
= static_cast<int>(drag
.Length());
4503 const int lengthInserted
= pdoc
->InsertString(
4504 newPos
.Position(), drag
.Data(), length
);
4505 if (lengthInserted
> 0) {
4506 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4508 } else if (newPos
< selStart
) {
4509 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4510 const int lengthInserted
= pdoc
->InsertString(
4511 newPos
.Position(), drag
.Data(), length
);
4512 if (lengthInserted
> 0) {
4513 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4515 } else if (newPos
> selEnd
) {
4516 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4517 newPos
.Add(-static_cast<int>(drag
.Length()));
4518 const int lengthInserted
= pdoc
->InsertString(
4519 newPos
.Position(), drag
.Data(), length
);
4520 if (lengthInserted
> 0) {
4521 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4524 SetEmptySelection(newPos
.Position());
4528 selectionType
= selChar
;
4531 if (selectionType
== selChar
) {
4532 if (sel
.Count() > 1) {
4534 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
4535 InvalidateSelection(sel
.RangeMain(), true);
4537 SetSelection(newPos
, sel
.RangeMain().anchor
);
4540 sel
.CommitTentative();
4542 SetRectangularRange();
4543 lastClickTime
= curTime
;
4545 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4546 if (sel
.selType
== Selection::selStream
) {
4549 inDragDrop
= ddNone
;
4550 EnsureCaretVisible(false);
4554 // Called frequently to perform background UI including
4555 // caret blinking and automatic scrolling.
4556 void Editor::Tick() {
4557 if (HaveMouseCapture()) {
4559 ButtonMove(ptMouseLast
);
4561 if (caret
.period
> 0) {
4562 timer
.ticksToWait
-= timer
.tickSize
;
4563 if (timer
.ticksToWait
<= 0) {
4564 caret
.on
= !caret
.on
;
4565 timer
.ticksToWait
= caret
.period
;
4571 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
4572 scrollWidth
= view
.lineWidthMaxSeen
;
4575 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4576 (ticksToDwell
> 0) &&
4577 (!HaveMouseCapture()) &&
4578 (ptMouseLast
.y
>= 0)) {
4579 ticksToDwell
-= timer
.tickSize
;
4580 if (ticksToDwell
<= 0) {
4582 NotifyDwelling(ptMouseLast
, dwelling
);
4587 bool Editor::Idle() {
4591 bool wrappingDone
= !Wrapping();
4593 if (!wrappingDone
) {
4594 // Wrap lines during idle.
4597 if (!wrapPending
.NeedsWrap())
4598 wrappingDone
= true;
4601 // Add more idle things to do here, but make sure idleDone is
4602 // set correctly before the function returns. returning
4603 // false will stop calling this idle function until SetIdle() is
4606 idleDone
= wrappingDone
; // && thatDone && theOtherThingDone...
4611 void Editor::SetTicking(bool) {
4612 // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
4613 // derived platform class but fine grained timers should now be implemented.
4614 // Either way, execution should not arrive here so assert failure.
4618 void Editor::TickFor(TickReason reason
) {
4621 caret
.on
= !caret
.on
;
4628 ButtonMove(ptMouseLast
);
4632 FineTickerCancel(tickWiden
);
4635 if ((!HaveMouseCapture()) &&
4636 (ptMouseLast
.y
>= 0)) {
4638 NotifyDwelling(ptMouseLast
, dwelling
);
4640 FineTickerCancel(tickDwell
);
4643 // tickPlatform handled by subclass
4648 bool Editor::FineTickerAvailable() {
4652 // FineTickerStart is be overridden by subclasses that support fine ticking so
4653 // this method should never be called.
4654 bool Editor::FineTickerRunning(TickReason
) {
4659 // FineTickerStart is be overridden by subclasses that support fine ticking so
4660 // this method should never be called.
4661 void Editor::FineTickerStart(TickReason
, int, int) {
4665 // FineTickerCancel is be overridden by subclasses that support fine ticking so
4666 // this method should never be called.
4667 void Editor::FineTickerCancel(TickReason
) {
4671 void Editor::SetFocusState(bool focusState
) {
4672 hasFocus
= focusState
;
4673 NotifyFocus(hasFocus
);
4675 ShowCaretAtCurrentPosition();
4682 int Editor::PositionAfterArea(PRectangle rcArea
) const {
4683 // The start of the document line after the display line after the area
4684 // This often means that the line after a modification is restyled which helps
4685 // detect multiline comment additions and heals single line comments
4686 int lineAfter
= TopLineOfMain() + static_cast<int>(rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
4687 if (lineAfter
< cs
.LinesDisplayed())
4688 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
4690 return pdoc
->Length();
4693 // Style to a position within the view. If this causes a change at end of last line then
4694 // affects later lines so style all the viewed text.
4695 void Editor::StyleToPositionInView(Position pos
) {
4696 int endWindow
= PositionAfterArea(GetClientDrawingRectangle());
4697 if (pos
> endWindow
)
4699 int styleAtEnd
= pdoc
->StyleAt(pos
-1);
4700 pdoc
->EnsureStyledTo(pos
);
4701 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleAt(pos
-1))) {
4702 // Style at end of line changed so is multi-line change like starting a comment
4703 // so require rest of window to be styled.
4704 DiscardOverdraw(); // Prepared bitmaps may be invalid
4705 // DiscardOverdraw may have truncated client drawing area so recalculate endWindow
4706 endWindow
= PositionAfterArea(GetClientDrawingRectangle());
4707 pdoc
->EnsureStyledTo(endWindow
);
4711 void Editor::IdleWork() {
4712 // Style the line after the modification as this allows modifications that change just the
4713 // line of the modification to heal instead of propagating to the rest of the window.
4714 if (workNeeded
.items
& WorkNeeded::workStyle
)
4715 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(workNeeded
.upTo
) + 2));
4721 void Editor::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
4722 workNeeded
.Need(items
, upTo
);
4725 bool Editor::PaintContains(PRectangle rc
) {
4729 return rcPaint
.Contains(rc
);
4733 bool Editor::PaintContainsMargin() {
4734 if (wMargin
.GetID()) {
4735 // With separate margin view, paint of text view
4736 // never contains margin.
4739 PRectangle rcSelMargin
= GetClientRectangle();
4740 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
);
4741 return PaintContains(rcSelMargin
);
4744 void Editor::CheckForChangeOutsidePaint(Range r
) {
4745 if (paintState
== painting
&& !paintingAllText
) {
4746 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
4750 PRectangle rcRange
= RectangleFromRange(r
, 0);
4751 PRectangle rcText
= GetTextRectangle();
4752 if (rcRange
.top
< rcText
.top
) {
4753 rcRange
.top
= rcText
.top
;
4755 if (rcRange
.bottom
> rcText
.bottom
) {
4756 rcRange
.bottom
= rcText
.bottom
;
4759 if (!PaintContains(rcRange
)) {
4761 paintAbandonedByStyling
= true;
4766 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
4767 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
4768 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
4769 CheckForChangeOutsidePaint(Range(braces
[0]));
4770 CheckForChangeOutsidePaint(Range(pos0
));
4773 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
4774 CheckForChangeOutsidePaint(Range(braces
[1]));
4775 CheckForChangeOutsidePaint(Range(pos1
));
4778 bracesMatchStyle
= matchStyle
;
4779 if (paintState
== notPainting
) {
4785 void Editor::SetAnnotationHeights(int start
, int end
) {
4786 if (vs
.annotationVisible
) {
4787 bool changedHeight
= false;
4788 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
4789 int linesWrapped
= 1;
4791 AutoSurface
surface(this);
4792 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
4793 if (surface
&& ll
) {
4794 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
4795 linesWrapped
= ll
->lines
;
4798 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
4799 changedHeight
= true;
4801 if (changedHeight
) {
4807 void Editor::SetDocPointer(Document
*document
) {
4808 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
4809 pdoc
->RemoveWatcher(this, 0);
4811 if (document
== NULL
) {
4812 pdoc
= new Document();
4818 // Ensure all positions within document
4823 braces
[0] = invalidPosition
;
4824 braces
[1] = invalidPosition
;
4826 vs
.ReleaseAllExtendedStyles();
4828 SetRepresentations();
4830 // Reset the contraction state to fully shown.
4832 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
4833 SetAnnotationHeights(0, pdoc
->LinesTotal());
4834 view
.llc
.Deallocate();
4837 view
.ClearAllTabstops();
4839 pdoc
->AddWatcher(this, 0);
4844 void Editor::SetAnnotationVisible(int visible
) {
4845 if (vs
.annotationVisible
!= visible
) {
4846 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
4847 vs
.annotationVisible
= visible
;
4848 if (changedFromOrToHidden
) {
4849 int dir
= vs
.annotationVisible
? 1 : -1;
4850 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
4851 int annotationLines
= pdoc
->AnnotationLines(line
);
4852 if (annotationLines
> 0) {
4853 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
4862 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
4864 int Editor::ExpandLine(int line
) {
4865 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4867 while (line
<= lineMaxSubord
) {
4868 cs
.SetVisible(line
, line
, true);
4869 int level
= pdoc
->GetLevel(line
);
4870 if (level
& SC_FOLDLEVELHEADERFLAG
) {
4871 if (cs
.GetExpanded(line
)) {
4872 line
= ExpandLine(line
);
4874 line
= pdoc
->GetLastChild(line
);
4879 return lineMaxSubord
;
4882 void Editor::SetFoldExpanded(int lineDoc
, bool expanded
) {
4883 if (cs
.SetExpanded(lineDoc
, expanded
)) {
4888 void Editor::FoldLine(int line
, int action
) {
4890 if (action
== SC_FOLDACTION_TOGGLE
) {
4891 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
4892 line
= pdoc
->GetFoldParent(line
);
4896 action
= (cs
.GetExpanded(line
)) ? SC_FOLDACTION_CONTRACT
: SC_FOLDACTION_EXPAND
;
4899 if (action
== SC_FOLDACTION_CONTRACT
) {
4900 int lineMaxSubord
= pdoc
->GetLastChild(line
);
4901 if (lineMaxSubord
> line
) {
4902 cs
.SetExpanded(line
, 0);
4903 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
4905 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
4906 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
4907 // This does not re-expand the fold
4908 EnsureCaretVisible();
4913 if (!(cs
.GetVisible(line
))) {
4914 EnsureLineVisible(line
, false);
4917 cs
.SetExpanded(line
, 1);
4926 void Editor::FoldExpand(int line
, int action
, int level
) {
4927 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
4928 if (action
== SC_FOLDACTION_TOGGLE
) {
4929 expanding
= !cs
.GetExpanded(line
);
4931 SetFoldExpanded(line
, expanding
);
4932 if (expanding
&& (cs
.HiddenLines() == 0))
4935 int lineMaxSubord
= pdoc
->GetLastChild(line
, level
& SC_FOLDLEVELNUMBERMASK
);
4937 cs
.SetVisible(line
, lineMaxSubord
, expanding
);
4938 while (line
<= lineMaxSubord
) {
4939 int levelLine
= pdoc
->GetLevel(line
);
4940 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
4941 SetFoldExpanded(line
, expanding
);
4949 int Editor::ContractedFoldNext(int lineStart
) const {
4950 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
4951 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
4953 line
= cs
.ContractedNext(line
+1);
4962 * Recurse up from this line to find any folds that prevent this line from being visible
4963 * and unfold them all.
4965 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
4967 // In case in need of wrapping to ensure DisplayFromDoc works.
4968 if (lineDoc
>= wrapPending
.start
)
4971 if (!cs
.GetVisible(lineDoc
)) {
4972 // Back up to find a non-blank line
4973 int lookLine
= lineDoc
;
4974 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
4975 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
4976 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
4978 int lineParent
= pdoc
->GetFoldParent(lookLine
);
4979 if (lineParent
< 0) {
4980 // Backed up to a top level line, so try to find parent of initial line
4981 lineParent
= pdoc
->GetFoldParent(lineDoc
);
4983 if (lineParent
>= 0) {
4984 if (lineDoc
!= lineParent
)
4985 EnsureLineVisible(lineParent
, enforcePolicy
);
4986 if (!cs
.GetExpanded(lineParent
)) {
4987 cs
.SetExpanded(lineParent
, 1);
4988 ExpandLine(lineParent
);
4994 if (enforcePolicy
) {
4995 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
4996 if (visiblePolicy
& VISIBLE_SLOP
) {
4997 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
4998 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
4999 SetVerticalScrollPos();
5001 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5002 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5003 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5004 SetVerticalScrollPos();
5008 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5009 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5010 SetVerticalScrollPos();
5017 void Editor::FoldAll(int action
) {
5018 pdoc
->EnsureStyledTo(pdoc
->Length());
5019 int maxLine
= pdoc
->LinesTotal();
5020 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5021 if (action
== SC_FOLDACTION_TOGGLE
) {
5022 // Discover current state
5023 for (int lineSeek
= 0; lineSeek
< maxLine
; lineSeek
++) {
5024 if (pdoc
->GetLevel(lineSeek
) & SC_FOLDLEVELHEADERFLAG
) {
5025 expanding
= !cs
.GetExpanded(lineSeek
);
5031 cs
.SetVisible(0, maxLine
-1, true);
5032 for (int line
= 0; line
< maxLine
; line
++) {
5033 int levelLine
= pdoc
->GetLevel(line
);
5034 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5035 SetFoldExpanded(line
, true);
5039 for (int line
= 0; line
< maxLine
; line
++) {
5040 int level
= pdoc
->GetLevel(line
);
5041 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
5042 (SC_FOLDLEVELBASE
== (level
& SC_FOLDLEVELNUMBERMASK
))) {
5043 SetFoldExpanded(line
, false);
5044 int lineMaxSubord
= pdoc
->GetLastChild(line
, -1);
5045 if (lineMaxSubord
> line
) {
5046 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5055 void Editor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
5056 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
5057 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
5058 // Adding a fold point.
5059 if (cs
.SetExpanded(line
, true)) {
5062 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5064 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
5065 if (!cs
.GetExpanded(line
)) {
5066 // Removing the fold from one that has been contracted so should expand
5067 // otherwise lines are left invisible with no way to make them visible
5068 if (cs
.SetExpanded(line
, true)) {
5071 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5074 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) &&
5075 ((levelPrev
& SC_FOLDLEVELNUMBERMASK
) > (levelNow
& SC_FOLDLEVELNUMBERMASK
))) {
5076 if (cs
.HiddenLines()) {
5077 // See if should still be hidden
5078 int parentLine
= pdoc
->GetFoldParent(line
);
5079 if ((parentLine
< 0) || (cs
.GetExpanded(parentLine
) && cs
.GetVisible(parentLine
))) {
5080 cs
.SetVisible(line
, line
, true);
5088 void Editor::NeedShown(int pos
, int len
) {
5089 if (foldAutomatic
& SC_AUTOMATICFOLD_SHOW
) {
5090 int lineStart
= pdoc
->LineFromPosition(pos
);
5091 int lineEnd
= pdoc
->LineFromPosition(pos
+len
);
5092 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
5093 EnsureLineVisible(line
, false);
5096 NotifyNeedShown(pos
, len
);
5100 int Editor::GetTag(char *tagValue
, int tagNumber
) {
5101 const char *text
= 0;
5103 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
5104 char name
[3] = "\\?";
5105 name
[1] = static_cast<char>(tagNumber
+ '0');
5107 text
= pdoc
->SubstituteByPosition(name
, &length
);
5111 memcpy(tagValue
, text
, length
+ 1);
5118 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5121 length
= istrlen(text
);
5122 if (replacePatterns
) {
5123 text
= pdoc
->SubstituteByPosition(text
, &length
);
5128 if (targetStart
!= targetEnd
)
5129 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5130 targetEnd
= targetStart
;
5131 const int lengthInserted
= pdoc
->InsertString(targetStart
, text
, length
);
5132 targetEnd
= targetStart
+ lengthInserted
;
5136 bool Editor::IsUnicodeMode() const {
5137 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5140 int Editor::CodePage() const {
5142 return pdoc
->dbcsCodePage
;
5147 int Editor::WrapCount(int line
) {
5148 AutoSurface
surface(this);
5149 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5151 if (surface
&& ll
) {
5152 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5159 void Editor::AddStyledText(char *buffer
, int appendLength
) {
5160 // The buffer consists of alternating character bytes and style bytes
5161 int textLength
= appendLength
/ 2;
5162 std::string
text(textLength
, '\0');
5164 for (i
= 0; i
< textLength
; i
++) {
5165 text
[i
] = buffer
[i
*2];
5167 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), text
.c_str(), textLength
);
5168 for (i
= 0; i
< textLength
; i
++) {
5169 text
[i
] = buffer
[i
*2+1];
5171 pdoc
->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
5172 pdoc
->SetStyles(textLength
, text
.c_str());
5173 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5176 static bool ValidMargin(uptr_t wParam
) {
5177 return wParam
<= SC_MAX_MARGIN
;
5180 static char *CharPtrFromSPtr(sptr_t lParam
) {
5181 return reinterpret_cast<char *>(lParam
);
5184 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5185 vs
.EnsureStyle(wParam
);
5187 case SCI_STYLESETFORE
:
5188 vs
.styles
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
5190 case SCI_STYLESETBACK
:
5191 vs
.styles
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
5193 case SCI_STYLESETBOLD
:
5194 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
5196 case SCI_STYLESETWEIGHT
:
5197 vs
.styles
[wParam
].weight
= static_cast<int>(lParam
);
5199 case SCI_STYLESETITALIC
:
5200 vs
.styles
[wParam
].italic
= lParam
!= 0;
5202 case SCI_STYLESETEOLFILLED
:
5203 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5205 case SCI_STYLESETSIZE
:
5206 vs
.styles
[wParam
].size
= static_cast<int>(lParam
* SC_FONT_SIZE_MULTIPLIER
);
5208 case SCI_STYLESETSIZEFRACTIONAL
:
5209 vs
.styles
[wParam
].size
= static_cast<int>(lParam
);
5211 case SCI_STYLESETFONT
:
5213 vs
.SetStyleFontName(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5216 case SCI_STYLESETUNDERLINE
:
5217 vs
.styles
[wParam
].underline
= lParam
!= 0;
5219 case SCI_STYLESETCASE
:
5220 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5222 case SCI_STYLESETCHARACTERSET
:
5223 vs
.styles
[wParam
].characterSet
= static_cast<int>(lParam
);
5224 pdoc
->SetCaseFolder(NULL
);
5226 case SCI_STYLESETVISIBLE
:
5227 vs
.styles
[wParam
].visible
= lParam
!= 0;
5229 case SCI_STYLESETCHANGEABLE
:
5230 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5232 case SCI_STYLESETHOTSPOT
:
5233 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5236 InvalidateStyleRedraw();
5239 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5240 vs
.EnsureStyle(wParam
);
5242 case SCI_STYLEGETFORE
:
5243 return vs
.styles
[wParam
].fore
.AsLong();
5244 case SCI_STYLEGETBACK
:
5245 return vs
.styles
[wParam
].back
.AsLong();
5246 case SCI_STYLEGETBOLD
:
5247 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
5248 case SCI_STYLEGETWEIGHT
:
5249 return vs
.styles
[wParam
].weight
;
5250 case SCI_STYLEGETITALIC
:
5251 return vs
.styles
[wParam
].italic
? 1 : 0;
5252 case SCI_STYLEGETEOLFILLED
:
5253 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5254 case SCI_STYLEGETSIZE
:
5255 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
5256 case SCI_STYLEGETSIZEFRACTIONAL
:
5257 return vs
.styles
[wParam
].size
;
5258 case SCI_STYLEGETFONT
:
5259 return StringResult(lParam
, vs
.styles
[wParam
].fontName
);
5260 case SCI_STYLEGETUNDERLINE
:
5261 return vs
.styles
[wParam
].underline
? 1 : 0;
5262 case SCI_STYLEGETCASE
:
5263 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5264 case SCI_STYLEGETCHARACTERSET
:
5265 return vs
.styles
[wParam
].characterSet
;
5266 case SCI_STYLEGETVISIBLE
:
5267 return vs
.styles
[wParam
].visible
? 1 : 0;
5268 case SCI_STYLEGETCHANGEABLE
:
5269 return vs
.styles
[wParam
].changeable
? 1 : 0;
5270 case SCI_STYLEGETHOTSPOT
:
5271 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5276 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
5277 const size_t len
= val
? strlen(val
) : 0;
5279 char *ptr
= CharPtrFromSPtr(lParam
);
5281 memcpy(ptr
, val
, len
+1);
5285 return len
; // Not including NUL
5288 sptr_t
Editor::BytesResult(sptr_t lParam
, const unsigned char *val
, size_t len
) {
5289 // No NUL termination: len is number of valid/displayed bytes
5291 char *ptr
= CharPtrFromSPtr(lParam
);
5293 memcpy(ptr
, val
, len
);
5297 return val
? len
: 0;
5300 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5301 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5303 // Optional macro recording hook
5305 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5311 return pdoc
->Length() + 1;
5314 char *ptr
= CharPtrFromSPtr(lParam
);
5315 unsigned int iChar
= 0;
5316 for (; iChar
< wParam
- 1; iChar
++)
5317 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5326 pdoc
->DeleteChars(0, pdoc
->Length());
5327 SetEmptySelection(0);
5328 const char *text
= CharPtrFromSPtr(lParam
);
5329 pdoc
->InsertString(0, text
, istrlen(text
));
5333 case SCI_GETTEXTLENGTH
:
5334 return pdoc
->Length();
5345 case SCI_COPYALLOWLINE
:
5349 case SCI_VERTICALCENTRECARET
:
5350 VerticalCentreCaret();
5353 case SCI_MOVESELECTEDLINESUP
:
5354 MoveSelectedLinesUp();
5357 case SCI_MOVESELECTEDLINESDOWN
:
5358 MoveSelectedLinesDown();
5362 CopyRangeToClipboard(static_cast<int>(wParam
), static_cast<int>(lParam
));
5366 CopyText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5371 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5374 EnsureCaretVisible();
5380 EnsureCaretVisible();
5389 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5391 case SCI_EMPTYUNDOBUFFER
:
5392 pdoc
->DeleteUndoHistory();
5395 case SCI_GETFIRSTVISIBLELINE
:
5398 case SCI_SETFIRSTVISIBLELINE
:
5399 ScrollTo(static_cast<int>(wParam
));
5402 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5403 int lineStart
= pdoc
->LineStart(static_cast<int>(wParam
));
5404 int lineEnd
= pdoc
->LineStart(static_cast<int>(wParam
+ 1));
5406 return lineEnd
- lineStart
;
5408 char *ptr
= CharPtrFromSPtr(lParam
);
5410 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5411 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5416 case SCI_GETLINECOUNT
:
5417 if (pdoc
->LinesTotal() == 0)
5420 return pdoc
->LinesTotal();
5423 return !pdoc
->IsSavePoint();
5426 int nStart
= static_cast<int>(wParam
);
5427 int nEnd
= static_cast<int>(lParam
);
5429 nEnd
= pdoc
->Length();
5431 nStart
= nEnd
; // Remove selection
5432 InvalidateSelection(SelectionRange(nStart
, nEnd
));
5434 sel
.selType
= Selection::selStream
;
5435 SetSelection(nEnd
, nStart
);
5436 EnsureCaretVisible();
5440 case SCI_GETSELTEXT
: {
5441 SelectionText selectedText
;
5442 CopySelectionRange(&selectedText
);
5444 return selectedText
.LengthWithTerminator();
5446 char *ptr
= CharPtrFromSPtr(lParam
);
5447 unsigned int iChar
= 0;
5448 if (selectedText
.Length()) {
5449 for (; iChar
< selectedText
.LengthWithTerminator(); iChar
++)
5450 ptr
[iChar
] = selectedText
.Data()[iChar
];
5458 case SCI_LINEFROMPOSITION
:
5459 if (static_cast<int>(wParam
) < 0)
5461 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
5463 case SCI_POSITIONFROMLINE
:
5464 if (static_cast<int>(wParam
) < 0)
5465 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
5467 return 0; // Even if there is no text, there is a first line that starts at 0
5468 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5470 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5472 return pdoc
->LineStart(static_cast<int>(wParam
));
5474 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5475 case SCI_LINELENGTH
:
5476 if ((static_cast<int>(wParam
) < 0) ||
5477 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5479 return pdoc
->LineStart(static_cast<int>(wParam
) + 1) - pdoc
->LineStart(static_cast<int>(wParam
));
5481 case SCI_REPLACESEL
: {
5486 char *replacement
= CharPtrFromSPtr(lParam
);
5487 const int lengthInserted
= pdoc
->InsertString(
5488 sel
.MainCaret(), replacement
, istrlen(replacement
));
5489 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5490 EnsureCaretVisible();
5494 case SCI_SETTARGETSTART
:
5495 targetStart
= static_cast<int>(wParam
);
5498 case SCI_GETTARGETSTART
:
5501 case SCI_SETTARGETEND
:
5502 targetEnd
= static_cast<int>(wParam
);
5505 case SCI_GETTARGETEND
:
5508 case SCI_TARGETFROMSELECTION
:
5509 if (sel
.MainCaret() < sel
.MainAnchor()) {
5510 targetStart
= sel
.MainCaret();
5511 targetEnd
= sel
.MainAnchor();
5513 targetStart
= sel
.MainAnchor();
5514 targetEnd
= sel
.MainCaret();
5518 case SCI_REPLACETARGET
:
5519 PLATFORM_ASSERT(lParam
);
5520 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5522 case SCI_REPLACETARGETRE
:
5523 PLATFORM_ASSERT(lParam
);
5524 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5526 case SCI_SEARCHINTARGET
:
5527 PLATFORM_ASSERT(lParam
);
5528 return SearchInTarget(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5530 case SCI_SETSEARCHFLAGS
:
5531 searchFlags
= static_cast<int>(wParam
);
5534 case SCI_GETSEARCHFLAGS
:
5538 return GetTag(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5540 case SCI_POSITIONBEFORE
:
5541 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) - 1, -1, true);
5543 case SCI_POSITIONAFTER
:
5544 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) + 1, 1, true);
5546 case SCI_POSITIONRELATIVE
:
5547 return Platform::Clamp(pdoc
->GetRelativePosition(static_cast<int>(wParam
), static_cast<int>(lParam
)), 0, pdoc
->Length());
5549 case SCI_LINESCROLL
:
5550 ScrollTo(topLine
+ static_cast<int>(lParam
));
5551 HorizontalScrollTo(xOffset
+ static_cast<int>(wParam
)* static_cast<int>(vs
.spaceWidth
));
5554 case SCI_SETXOFFSET
:
5555 xOffset
= static_cast<int>(wParam
);
5556 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
5557 SetHorizontalScrollPos();
5561 case SCI_GETXOFFSET
:
5564 case SCI_CHOOSECARETX
:
5568 case SCI_SCROLLCARET
:
5569 EnsureCaretVisible();
5572 case SCI_SETREADONLY
:
5573 pdoc
->SetReadOnly(wParam
!= 0);
5576 case SCI_GETREADONLY
:
5577 return pdoc
->IsReadOnly();
5582 case SCI_POINTXFROMPOSITION
:
5586 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5587 // Convert to view-relative
5588 return static_cast<int>(pt
.x
) - vs
.textStart
+ vs
.fixedColumnWidth
;
5591 case SCI_POINTYFROMPOSITION
:
5595 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5596 return static_cast<int>(pt
.y
);
5600 return FindText(wParam
, lParam
);
5602 case SCI_GETTEXTRANGE
: {
5605 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
5606 int cpMax
= tr
->chrg
.cpMax
;
5608 cpMax
= pdoc
->Length();
5609 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
5610 int len
= cpMax
- tr
->chrg
.cpMin
; // No -1 as cpMin and cpMax are referring to inter character positions
5611 pdoc
->GetCharRange(tr
->lpstrText
, tr
->chrg
.cpMin
, len
);
5612 // Spec says copied text is terminated with a NUL
5613 tr
->lpstrText
[len
] = '\0';
5614 return len
; // Not including NUL
5617 case SCI_HIDESELECTION
:
5618 view
.hideSelection
= wParam
!= 0;
5622 case SCI_FORMATRANGE
:
5623 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
5625 case SCI_GETMARGINLEFT
:
5626 return vs
.leftMarginWidth
;
5628 case SCI_GETMARGINRIGHT
:
5629 return vs
.rightMarginWidth
;
5631 case SCI_SETMARGINLEFT
:
5632 lastXChosen
+= static_cast<int>(lParam
) - vs
.leftMarginWidth
;
5633 vs
.leftMarginWidth
= static_cast<int>(lParam
);
5634 InvalidateStyleRedraw();
5637 case SCI_SETMARGINRIGHT
:
5638 vs
.rightMarginWidth
= static_cast<int>(lParam
);
5639 InvalidateStyleRedraw();
5642 // Control specific mesages
5647 const int lengthInserted
= pdoc
->InsertString(
5648 CurrentPosition(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5649 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5653 case SCI_ADDSTYLEDTEXT
:
5655 AddStyledText(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5658 case SCI_INSERTTEXT
: {
5661 int insertPos
= static_cast<int>(wParam
);
5662 if (static_cast<int>(wParam
) == -1)
5663 insertPos
= CurrentPosition();
5664 int newCurrent
= CurrentPosition();
5665 char *sz
= CharPtrFromSPtr(lParam
);
5666 const int lengthInserted
= pdoc
->InsertString(insertPos
, sz
, istrlen(sz
));
5667 if (newCurrent
> insertPos
)
5668 newCurrent
+= lengthInserted
;
5669 SetEmptySelection(newCurrent
);
5673 case SCI_CHANGEINSERTION
:
5674 PLATFORM_ASSERT(lParam
);
5675 pdoc
->ChangeInsertion(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5678 case SCI_APPENDTEXT
:
5679 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5686 case SCI_DELETERANGE
:
5687 pdoc
->DeleteChars(static_cast<int>(wParam
), static_cast<int>(lParam
));
5690 case SCI_CLEARDOCUMENTSTYLE
:
5691 ClearDocumentStyle();
5694 case SCI_SETUNDOCOLLECTION
:
5695 pdoc
->SetUndoCollection(wParam
!= 0);
5698 case SCI_GETUNDOCOLLECTION
:
5699 return pdoc
->IsCollectingUndo();
5701 case SCI_BEGINUNDOACTION
:
5702 pdoc
->BeginUndoAction();
5705 case SCI_ENDUNDOACTION
:
5706 pdoc
->EndUndoAction();
5709 case SCI_GETCARETPERIOD
:
5710 return caret
.period
;
5712 case SCI_SETCARETPERIOD
:
5713 CaretSetPeriod(static_cast<int>(wParam
));
5716 case SCI_GETWORDCHARS
:
5717 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
5719 case SCI_SETWORDCHARS
: {
5720 pdoc
->SetDefaultCharClasses(false);
5723 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
5727 case SCI_GETWHITESPACECHARS
:
5728 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
5730 case SCI_SETWHITESPACECHARS
: {
5733 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
5737 case SCI_GETPUNCTUATIONCHARS
:
5738 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
5740 case SCI_SETPUNCTUATIONCHARS
: {
5743 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
5747 case SCI_SETCHARSDEFAULT
:
5748 pdoc
->SetDefaultCharClasses(true);
5752 return pdoc
->Length();
5755 pdoc
->Allocate(static_cast<int>(wParam
));
5759 return pdoc
->CharAt(static_cast<int>(wParam
));
5761 case SCI_SETCURRENTPOS
:
5762 if (sel
.IsRectangular()) {
5763 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
5764 SetRectangularRange();
5767 SetSelection(static_cast<int>(wParam
), sel
.MainAnchor());
5771 case SCI_GETCURRENTPOS
:
5772 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
5775 if (sel
.IsRectangular()) {
5776 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
5777 SetRectangularRange();
5780 SetSelection(sel
.MainCaret(), static_cast<int>(wParam
));
5785 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
5787 case SCI_SETSELECTIONSTART
:
5788 SetSelection(Platform::Maximum(sel
.MainCaret(), static_cast<int>(wParam
)), static_cast<int>(wParam
));
5791 case SCI_GETSELECTIONSTART
:
5792 return sel
.LimitsForRectangularElseMain().start
.Position();
5794 case SCI_SETSELECTIONEND
:
5795 SetSelection(static_cast<int>(wParam
), Platform::Minimum(sel
.MainAnchor(), static_cast<int>(wParam
)));
5798 case SCI_GETSELECTIONEND
:
5799 return sel
.LimitsForRectangularElseMain().end
.Position();
5801 case SCI_SETEMPTYSELECTION
:
5802 SetEmptySelection(static_cast<int>(wParam
));
5805 case SCI_SETPRINTMAGNIFICATION
:
5806 view
.printParameters
.magnification
= static_cast<int>(wParam
);
5809 case SCI_GETPRINTMAGNIFICATION
:
5810 return view
.printParameters
.magnification
;
5812 case SCI_SETPRINTCOLOURMODE
:
5813 view
.printParameters
.colourMode
= static_cast<int>(wParam
);
5816 case SCI_GETPRINTCOLOURMODE
:
5817 return view
.printParameters
.colourMode
;
5819 case SCI_SETPRINTWRAPMODE
:
5820 view
.printParameters
.wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
5823 case SCI_GETPRINTWRAPMODE
:
5824 return view
.printParameters
.wrapState
;
5826 case SCI_GETSTYLEAT
:
5827 if (static_cast<int>(wParam
) >= pdoc
->Length())
5830 return pdoc
->StyleAt(static_cast<int>(wParam
));
5840 case SCI_SETSAVEPOINT
:
5841 pdoc
->SetSavePoint();
5844 case SCI_GETSTYLEDTEXT
: {
5847 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
5849 for (int iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
5850 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(iChar
);
5851 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(iChar
);
5853 tr
->lpstrText
[iPlace
] = '\0';
5854 tr
->lpstrText
[iPlace
+ 1] = '\0';
5859 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5861 case SCI_MARKERLINEFROMHANDLE
:
5862 return pdoc
->LineFromHandle(static_cast<int>(wParam
));
5864 case SCI_MARKERDELETEHANDLE
:
5865 pdoc
->DeleteMarkFromHandle(static_cast<int>(wParam
));
5869 return vs
.viewWhitespace
;
5872 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
5876 case SCI_GETWHITESPACESIZE
:
5877 return vs
.whitespaceSize
;
5879 case SCI_SETWHITESPACESIZE
:
5880 vs
.whitespaceSize
= static_cast<int>(wParam
);
5884 case SCI_POSITIONFROMPOINT
:
5885 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5888 case SCI_POSITIONFROMPOINTCLOSE
:
5889 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5892 case SCI_CHARPOSITIONFROMPOINT
:
5893 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5896 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
5897 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
5901 GoToLine(static_cast<int>(wParam
));
5905 SetEmptySelection(static_cast<int>(wParam
));
5906 EnsureCaretVisible();
5909 case SCI_GETCURLINE
: {
5910 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
5911 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
5912 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
5914 return 1 + lineEnd
- lineStart
;
5916 PLATFORM_ASSERT(wParam
> 0);
5917 char *ptr
= CharPtrFromSPtr(lParam
);
5918 unsigned int iPlace
= 0;
5919 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
5920 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5923 return sel
.MainCaret() - lineStart
;
5926 case SCI_GETENDSTYLED
:
5927 return pdoc
->GetEndStyled();
5929 case SCI_GETEOLMODE
:
5930 return pdoc
->eolMode
;
5932 case SCI_SETEOLMODE
:
5933 pdoc
->eolMode
= static_cast<int>(wParam
);
5936 case SCI_SETLINEENDTYPESALLOWED
:
5937 if (pdoc
->SetLineEndTypesAllowed(static_cast<int>(wParam
))) {
5939 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5940 SetAnnotationHeights(0, pdoc
->LinesTotal());
5941 InvalidateStyleRedraw();
5945 case SCI_GETLINEENDTYPESALLOWED
:
5946 return pdoc
->GetLineEndTypesAllowed();
5948 case SCI_GETLINEENDTYPESACTIVE
:
5949 return pdoc
->GetLineEndTypesActive();
5951 case SCI_STARTSTYLING
:
5952 pdoc
->StartStyling(static_cast<int>(wParam
), static_cast<char>(lParam
));
5955 case SCI_SETSTYLING
:
5956 pdoc
->SetStyleFor(static_cast<int>(wParam
), static_cast<char>(lParam
));
5959 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
5962 pdoc
->SetStyles(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5965 case SCI_SETBUFFEREDDRAW
:
5966 view
.bufferedDraw
= wParam
!= 0;
5969 case SCI_GETBUFFEREDDRAW
:
5970 return view
.bufferedDraw
;
5972 case SCI_GETTWOPHASEDRAW
:
5973 return view
.phasesDraw
== EditView::phasesTwo
;
5975 case SCI_SETTWOPHASEDRAW
:
5976 if (view
.SetTwoPhaseDraw(wParam
!= 0))
5977 InvalidateStyleRedraw();
5980 case SCI_GETPHASESDRAW
:
5981 return view
.phasesDraw
;
5983 case SCI_SETPHASESDRAW
:
5984 if (view
.SetPhasesDraw(static_cast<int>(wParam
)))
5985 InvalidateStyleRedraw();
5988 case SCI_SETFONTQUALITY
:
5989 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
5990 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
5991 InvalidateStyleRedraw();
5994 case SCI_GETFONTQUALITY
:
5995 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
5997 case SCI_SETTABWIDTH
:
5999 pdoc
->tabInChars
= static_cast<int>(wParam
);
6000 if (pdoc
->indentInChars
== 0)
6001 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6003 InvalidateStyleRedraw();
6006 case SCI_GETTABWIDTH
:
6007 return pdoc
->tabInChars
;
6009 case SCI_CLEARTABSTOPS
:
6010 if (view
.ClearTabstops(static_cast<int>(wParam
))) {
6011 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6012 NotifyModified(pdoc
, mh
, NULL
);
6016 case SCI_ADDTABSTOP
:
6017 if (view
.AddTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
))) {
6018 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6019 NotifyModified(pdoc
, mh
, NULL
);
6023 case SCI_GETNEXTTABSTOP
:
6024 return view
.GetNextTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
));
6027 pdoc
->indentInChars
= static_cast<int>(wParam
);
6028 if (pdoc
->indentInChars
!= 0)
6029 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6031 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6032 InvalidateStyleRedraw();
6036 return pdoc
->indentInChars
;
6038 case SCI_SETUSETABS
:
6039 pdoc
->useTabs
= wParam
!= 0;
6040 InvalidateStyleRedraw();
6043 case SCI_GETUSETABS
:
6044 return pdoc
->useTabs
;
6046 case SCI_SETLINEINDENTATION
:
6047 pdoc
->SetLineIndentation(static_cast<int>(wParam
), static_cast<int>(lParam
));
6050 case SCI_GETLINEINDENTATION
:
6051 return pdoc
->GetLineIndentation(static_cast<int>(wParam
));
6053 case SCI_GETLINEINDENTPOSITION
:
6054 return pdoc
->GetLineIndentPosition(static_cast<int>(wParam
));
6056 case SCI_SETTABINDENTS
:
6057 pdoc
->tabIndents
= wParam
!= 0;
6060 case SCI_GETTABINDENTS
:
6061 return pdoc
->tabIndents
;
6063 case SCI_SETBACKSPACEUNINDENTS
:
6064 pdoc
->backspaceUnindents
= wParam
!= 0;
6067 case SCI_GETBACKSPACEUNINDENTS
:
6068 return pdoc
->backspaceUnindents
;
6070 case SCI_SETMOUSEDWELLTIME
:
6071 dwellDelay
= static_cast<int>(wParam
);
6072 ticksToDwell
= dwellDelay
;
6075 case SCI_GETMOUSEDWELLTIME
:
6078 case SCI_WORDSTARTPOSITION
:
6079 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), -1, lParam
!= 0);
6081 case SCI_WORDENDPOSITION
:
6082 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), 1, lParam
!= 0);
6084 case SCI_SETWRAPMODE
:
6085 if (vs
.SetWrapState(static_cast<int>(wParam
))) {
6087 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6088 InvalidateStyleRedraw();
6089 ReconfigureScrollBars();
6093 case SCI_GETWRAPMODE
:
6094 return vs
.wrapState
;
6096 case SCI_SETWRAPVISUALFLAGS
:
6097 if (vs
.SetWrapVisualFlags(static_cast<int>(wParam
))) {
6098 InvalidateStyleRedraw();
6099 ReconfigureScrollBars();
6103 case SCI_GETWRAPVISUALFLAGS
:
6104 return vs
.wrapVisualFlags
;
6106 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6107 if (vs
.SetWrapVisualFlagsLocation(static_cast<int>(wParam
))) {
6108 InvalidateStyleRedraw();
6112 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6113 return vs
.wrapVisualFlagsLocation
;
6115 case SCI_SETWRAPSTARTINDENT
:
6116 if (vs
.SetWrapVisualStartIndent(static_cast<int>(wParam
))) {
6117 InvalidateStyleRedraw();
6118 ReconfigureScrollBars();
6122 case SCI_GETWRAPSTARTINDENT
:
6123 return vs
.wrapVisualStartIndent
;
6125 case SCI_SETWRAPINDENTMODE
:
6126 if (vs
.SetWrapIndentMode(static_cast<int>(wParam
))) {
6127 InvalidateStyleRedraw();
6128 ReconfigureScrollBars();
6132 case SCI_GETWRAPINDENTMODE
:
6133 return vs
.wrapIndentMode
;
6135 case SCI_SETLAYOUTCACHE
:
6136 view
.llc
.SetLevel(static_cast<int>(wParam
));
6139 case SCI_GETLAYOUTCACHE
:
6140 return view
.llc
.GetLevel();
6142 case SCI_SETPOSITIONCACHE
:
6143 view
.posCache
.SetSize(wParam
);
6146 case SCI_GETPOSITIONCACHE
:
6147 return view
.posCache
.GetSize();
6149 case SCI_SETSCROLLWIDTH
:
6150 PLATFORM_ASSERT(wParam
> 0);
6151 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6152 view
.lineWidthMaxSeen
= 0;
6153 scrollWidth
= static_cast<int>(wParam
);
6158 case SCI_GETSCROLLWIDTH
:
6161 case SCI_SETSCROLLWIDTHTRACKING
:
6162 trackLineWidth
= wParam
!= 0;
6165 case SCI_GETSCROLLWIDTHTRACKING
:
6166 return trackLineWidth
;
6172 case SCI_LINESSPLIT
:
6173 LinesSplit(static_cast<int>(wParam
));
6177 PLATFORM_ASSERT(wParam
< vs
.styles
.size());
6178 PLATFORM_ASSERT(lParam
);
6179 return TextWidth(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6181 case SCI_TEXTHEIGHT
:
6182 return vs
.lineHeight
;
6184 case SCI_SETENDATLASTLINE
:
6185 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6186 if (endAtLastLine
!= (wParam
!= 0)) {
6187 endAtLastLine
= wParam
!= 0;
6192 case SCI_GETENDATLASTLINE
:
6193 return endAtLastLine
;
6195 case SCI_SETCARETSTICKY
:
6196 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
6197 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
6198 caretSticky
= static_cast<int>(wParam
);
6202 case SCI_GETCARETSTICKY
:
6205 case SCI_TOGGLECARETSTICKY
:
6206 caretSticky
= !caretSticky
;
6210 return pdoc
->GetColumn(static_cast<int>(wParam
));
6212 case SCI_FINDCOLUMN
:
6213 return pdoc
->FindColumn(static_cast<int>(wParam
), static_cast<int>(lParam
));
6215 case SCI_SETHSCROLLBAR
:
6216 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6217 horizontalScrollBarVisible
= wParam
!= 0;
6219 ReconfigureScrollBars();
6223 case SCI_GETHSCROLLBAR
:
6224 return horizontalScrollBarVisible
;
6226 case SCI_SETVSCROLLBAR
:
6227 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6228 verticalScrollBarVisible
= wParam
!= 0;
6230 ReconfigureScrollBars();
6231 if (verticalScrollBarVisible
)
6232 SetVerticalScrollPos();
6236 case SCI_GETVSCROLLBAR
:
6237 return verticalScrollBarVisible
;
6239 case SCI_SETINDENTATIONGUIDES
:
6240 vs
.viewIndentationGuides
= IndentView(wParam
);
6244 case SCI_GETINDENTATIONGUIDES
:
6245 return vs
.viewIndentationGuides
;
6247 case SCI_SETHIGHLIGHTGUIDE
:
6248 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6249 highlightGuideColumn
= static_cast<int>(wParam
);
6254 case SCI_GETHIGHLIGHTGUIDE
:
6255 return highlightGuideColumn
;
6257 case SCI_GETLINEENDPOSITION
:
6258 return pdoc
->LineEnd(static_cast<int>(wParam
));
6260 case SCI_SETCODEPAGE
:
6261 if (ValidCodePage(static_cast<int>(wParam
))) {
6262 if (pdoc
->SetDBCSCodePage(static_cast<int>(wParam
))) {
6264 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6265 SetAnnotationHeights(0, pdoc
->LinesTotal());
6266 InvalidateStyleRedraw();
6267 SetRepresentations();
6272 case SCI_GETCODEPAGE
:
6273 return pdoc
->dbcsCodePage
;
6275 case SCI_SETIMEINTERACTION
:
6276 imeInteraction
= static_cast<EditModel::IMEInteraction
>(wParam
);
6279 case SCI_GETIMEINTERACTION
:
6280 return imeInteraction
;
6282 #ifdef INCLUDE_DEPRECATED_FEATURES
6283 case SCI_SETUSEPALETTE
:
6284 InvalidateStyleRedraw();
6287 case SCI_GETUSEPALETTE
:
6291 // Marker definition and setting
6292 case SCI_MARKERDEFINE
:
6293 if (wParam
<= MARKER_MAX
) {
6294 vs
.markers
[wParam
].markType
= static_cast<int>(lParam
);
6295 vs
.CalcLargestMarkerHeight();
6297 InvalidateStyleData();
6301 case SCI_MARKERSYMBOLDEFINED
:
6302 if (wParam
<= MARKER_MAX
)
6303 return vs
.markers
[wParam
].markType
;
6307 case SCI_MARKERSETFORE
:
6308 if (wParam
<= MARKER_MAX
)
6309 vs
.markers
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6310 InvalidateStyleData();
6313 case SCI_MARKERSETBACKSELECTED
:
6314 if (wParam
<= MARKER_MAX
)
6315 vs
.markers
[wParam
].backSelected
= ColourDesired(static_cast<long>(lParam
));
6316 InvalidateStyleData();
6319 case SCI_MARKERENABLEHIGHLIGHT
:
6320 marginView
.highlightDelimiter
.isEnabled
= wParam
== 1;
6323 case SCI_MARKERSETBACK
:
6324 if (wParam
<= MARKER_MAX
)
6325 vs
.markers
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6326 InvalidateStyleData();
6329 case SCI_MARKERSETALPHA
:
6330 if (wParam
<= MARKER_MAX
)
6331 vs
.markers
[wParam
].alpha
= static_cast<int>(lParam
);
6332 InvalidateStyleRedraw();
6334 case SCI_MARKERADD
: {
6335 int markerID
= pdoc
->AddMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6338 case SCI_MARKERADDSET
:
6340 pdoc
->AddMarkSet(static_cast<int>(wParam
), static_cast<int>(lParam
));
6343 case SCI_MARKERDELETE
:
6344 pdoc
->DeleteMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6347 case SCI_MARKERDELETEALL
:
6348 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6352 return pdoc
->GetMark(static_cast<int>(wParam
));
6354 case SCI_MARKERNEXT
:
6355 return pdoc
->MarkerNext(static_cast<int>(wParam
), static_cast<int>(lParam
));
6357 case SCI_MARKERPREVIOUS
: {
6358 for (int iLine
= static_cast<int>(wParam
); iLine
>= 0; iLine
--) {
6359 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6365 case SCI_MARKERDEFINEPIXMAP
:
6366 if (wParam
<= MARKER_MAX
) {
6367 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6368 vs
.CalcLargestMarkerHeight();
6370 InvalidateStyleData();
6374 case SCI_RGBAIMAGESETWIDTH
:
6375 sizeRGBAImage
.x
= static_cast<XYPOSITION
>(wParam
);
6378 case SCI_RGBAIMAGESETHEIGHT
:
6379 sizeRGBAImage
.y
= static_cast<XYPOSITION
>(wParam
);
6382 case SCI_RGBAIMAGESETSCALE
:
6383 scaleRGBAImage
= static_cast<float>(wParam
);
6386 case SCI_MARKERDEFINERGBAIMAGE
:
6387 if (wParam
<= MARKER_MAX
) {
6388 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0f
, reinterpret_cast<unsigned char *>(lParam
));
6389 vs
.CalcLargestMarkerHeight();
6391 InvalidateStyleData();
6395 case SCI_SETMARGINTYPEN
:
6396 if (ValidMargin(wParam
)) {
6397 vs
.ms
[wParam
].style
= static_cast<int>(lParam
);
6398 InvalidateStyleRedraw();
6402 case SCI_GETMARGINTYPEN
:
6403 if (ValidMargin(wParam
))
6404 return vs
.ms
[wParam
].style
;
6408 case SCI_SETMARGINWIDTHN
:
6409 if (ValidMargin(wParam
)) {
6410 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6411 if (vs
.ms
[wParam
].width
!= lParam
) {
6412 lastXChosen
+= static_cast<int>(lParam
) - vs
.ms
[wParam
].width
;
6413 vs
.ms
[wParam
].width
= static_cast<int>(lParam
);
6414 InvalidateStyleRedraw();
6419 case SCI_GETMARGINWIDTHN
:
6420 if (ValidMargin(wParam
))
6421 return vs
.ms
[wParam
].width
;
6425 case SCI_SETMARGINMASKN
:
6426 if (ValidMargin(wParam
)) {
6427 vs
.ms
[wParam
].mask
= static_cast<int>(lParam
);
6428 InvalidateStyleRedraw();
6432 case SCI_GETMARGINMASKN
:
6433 if (ValidMargin(wParam
))
6434 return vs
.ms
[wParam
].mask
;
6438 case SCI_SETMARGINSENSITIVEN
:
6439 if (ValidMargin(wParam
)) {
6440 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6441 InvalidateStyleRedraw();
6445 case SCI_GETMARGINSENSITIVEN
:
6446 if (ValidMargin(wParam
))
6447 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6451 case SCI_SETMARGINCURSORN
:
6452 if (ValidMargin(wParam
))
6453 vs
.ms
[wParam
].cursor
= static_cast<int>(lParam
);
6456 case SCI_GETMARGINCURSORN
:
6457 if (ValidMargin(wParam
))
6458 return vs
.ms
[wParam
].cursor
;
6462 case SCI_STYLECLEARALL
:
6464 InvalidateStyleRedraw();
6467 case SCI_STYLESETFORE
:
6468 case SCI_STYLESETBACK
:
6469 case SCI_STYLESETBOLD
:
6470 case SCI_STYLESETWEIGHT
:
6471 case SCI_STYLESETITALIC
:
6472 case SCI_STYLESETEOLFILLED
:
6473 case SCI_STYLESETSIZE
:
6474 case SCI_STYLESETSIZEFRACTIONAL
:
6475 case SCI_STYLESETFONT
:
6476 case SCI_STYLESETUNDERLINE
:
6477 case SCI_STYLESETCASE
:
6478 case SCI_STYLESETCHARACTERSET
:
6479 case SCI_STYLESETVISIBLE
:
6480 case SCI_STYLESETCHANGEABLE
:
6481 case SCI_STYLESETHOTSPOT
:
6482 StyleSetMessage(iMessage
, wParam
, lParam
);
6485 case SCI_STYLEGETFORE
:
6486 case SCI_STYLEGETBACK
:
6487 case SCI_STYLEGETBOLD
:
6488 case SCI_STYLEGETWEIGHT
:
6489 case SCI_STYLEGETITALIC
:
6490 case SCI_STYLEGETEOLFILLED
:
6491 case SCI_STYLEGETSIZE
:
6492 case SCI_STYLEGETSIZEFRACTIONAL
:
6493 case SCI_STYLEGETFONT
:
6494 case SCI_STYLEGETUNDERLINE
:
6495 case SCI_STYLEGETCASE
:
6496 case SCI_STYLEGETCHARACTERSET
:
6497 case SCI_STYLEGETVISIBLE
:
6498 case SCI_STYLEGETCHANGEABLE
:
6499 case SCI_STYLEGETHOTSPOT
:
6500 return StyleGetMessage(iMessage
, wParam
, lParam
);
6502 case SCI_STYLERESETDEFAULT
:
6503 vs
.ResetDefaultStyle();
6504 InvalidateStyleRedraw();
6506 case SCI_SETSTYLEBITS
:
6507 vs
.EnsureStyle(0xff);
6510 case SCI_GETSTYLEBITS
:
6513 case SCI_SETLINESTATE
:
6514 return pdoc
->SetLineState(static_cast<int>(wParam
), static_cast<int>(lParam
));
6516 case SCI_GETLINESTATE
:
6517 return pdoc
->GetLineState(static_cast<int>(wParam
));
6519 case SCI_GETMAXLINESTATE
:
6520 return pdoc
->GetMaxLineState();
6522 case SCI_GETCARETLINEVISIBLE
:
6523 return vs
.showCaretLineBackground
;
6524 case SCI_SETCARETLINEVISIBLE
:
6525 vs
.showCaretLineBackground
= wParam
!= 0;
6526 InvalidateStyleRedraw();
6528 case SCI_GETCARETLINEVISIBLEALWAYS
:
6529 return vs
.alwaysShowCaretLineBackground
;
6530 case SCI_SETCARETLINEVISIBLEALWAYS
:
6531 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
6532 InvalidateStyleRedraw();
6535 case SCI_GETCARETLINEBACK
:
6536 return vs
.caretLineBackground
.AsLong();
6537 case SCI_SETCARETLINEBACK
:
6538 vs
.caretLineBackground
= static_cast<int>(wParam
);
6539 InvalidateStyleRedraw();
6541 case SCI_GETCARETLINEBACKALPHA
:
6542 return vs
.caretLineAlpha
;
6543 case SCI_SETCARETLINEBACKALPHA
:
6544 vs
.caretLineAlpha
= static_cast<int>(wParam
);
6545 InvalidateStyleRedraw();
6550 case SCI_VISIBLEFROMDOCLINE
:
6551 return cs
.DisplayFromDoc(static_cast<int>(wParam
));
6553 case SCI_DOCLINEFROMVISIBLE
:
6554 return cs
.DocFromDisplay(static_cast<int>(wParam
));
6557 return WrapCount(static_cast<int>(wParam
));
6559 case SCI_SETFOLDLEVEL
: {
6560 int prev
= pdoc
->SetLevel(static_cast<int>(wParam
), static_cast<int>(lParam
));
6561 if (prev
!= static_cast<int>(lParam
))
6566 case SCI_GETFOLDLEVEL
:
6567 return pdoc
->GetLevel(static_cast<int>(wParam
));
6569 case SCI_GETLASTCHILD
:
6570 return pdoc
->GetLastChild(static_cast<int>(wParam
), static_cast<int>(lParam
));
6572 case SCI_GETFOLDPARENT
:
6573 return pdoc
->GetFoldParent(static_cast<int>(wParam
));
6576 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), true);
6583 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), false);
6588 case SCI_GETLINEVISIBLE
:
6589 return cs
.GetVisible(static_cast<int>(wParam
));
6591 case SCI_GETALLLINESVISIBLE
:
6592 return cs
.HiddenLines() ? 0 : 1;
6594 case SCI_SETFOLDEXPANDED
:
6595 SetFoldExpanded(static_cast<int>(wParam
), lParam
!= 0);
6598 case SCI_GETFOLDEXPANDED
:
6599 return cs
.GetExpanded(static_cast<int>(wParam
));
6601 case SCI_SETAUTOMATICFOLD
:
6602 foldAutomatic
= static_cast<int>(wParam
);
6605 case SCI_GETAUTOMATICFOLD
:
6606 return foldAutomatic
;
6608 case SCI_SETFOLDFLAGS
:
6609 foldFlags
= static_cast<int>(wParam
);
6613 case SCI_TOGGLEFOLD
:
6614 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
6618 FoldLine(static_cast<int>(wParam
), static_cast<int>(lParam
));
6621 case SCI_FOLDCHILDREN
:
6622 FoldExpand(static_cast<int>(wParam
), static_cast<int>(lParam
), pdoc
->GetLevel(static_cast<int>(wParam
)));
6626 FoldAll(static_cast<int>(wParam
));
6629 case SCI_EXPANDCHILDREN
:
6630 FoldExpand(static_cast<int>(wParam
), SC_FOLDACTION_EXPAND
, static_cast<int>(lParam
));
6633 case SCI_CONTRACTEDFOLDNEXT
:
6634 return ContractedFoldNext(static_cast<int>(wParam
));
6636 case SCI_ENSUREVISIBLE
:
6637 EnsureLineVisible(static_cast<int>(wParam
), false);
6640 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
6641 EnsureLineVisible(static_cast<int>(wParam
), true);
6644 case SCI_SCROLLRANGE
:
6645 ScrollRange(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
6648 case SCI_SEARCHANCHOR
:
6652 case SCI_SEARCHNEXT
:
6653 case SCI_SEARCHPREV
:
6654 return SearchText(iMessage
, wParam
, lParam
);
6656 case SCI_SETXCARETPOLICY
:
6657 caretXPolicy
= static_cast<int>(wParam
);
6658 caretXSlop
= static_cast<int>(lParam
);
6661 case SCI_SETYCARETPOLICY
:
6662 caretYPolicy
= static_cast<int>(wParam
);
6663 caretYSlop
= static_cast<int>(lParam
);
6666 case SCI_SETVISIBLEPOLICY
:
6667 visiblePolicy
= static_cast<int>(wParam
);
6668 visibleSlop
= static_cast<int>(lParam
);
6671 case SCI_LINESONSCREEN
:
6672 return LinesOnScreen();
6674 case SCI_SETSELFORE
:
6675 vs
.selColours
.fore
= ColourOptional(wParam
, lParam
);
6676 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(lParam
));
6677 InvalidateStyleRedraw();
6680 case SCI_SETSELBACK
:
6681 vs
.selColours
.back
= ColourOptional(wParam
, lParam
);
6682 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(lParam
));
6683 InvalidateStyleRedraw();
6686 case SCI_SETSELALPHA
:
6687 vs
.selAlpha
= static_cast<int>(wParam
);
6688 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
6689 InvalidateStyleRedraw();
6692 case SCI_GETSELALPHA
:
6695 case SCI_GETSELEOLFILLED
:
6696 return vs
.selEOLFilled
;
6698 case SCI_SETSELEOLFILLED
:
6699 vs
.selEOLFilled
= wParam
!= 0;
6700 InvalidateStyleRedraw();
6703 case SCI_SETWHITESPACEFORE
:
6704 vs
.whitespaceColours
.fore
= ColourOptional(wParam
, lParam
);
6705 InvalidateStyleRedraw();
6708 case SCI_SETWHITESPACEBACK
:
6709 vs
.whitespaceColours
.back
= ColourOptional(wParam
, lParam
);
6710 InvalidateStyleRedraw();
6713 case SCI_SETCARETFORE
:
6714 vs
.caretcolour
= ColourDesired(static_cast<long>(wParam
));
6715 InvalidateStyleRedraw();
6718 case SCI_GETCARETFORE
:
6719 return vs
.caretcolour
.AsLong();
6721 case SCI_SETCARETSTYLE
:
6722 if (wParam
<= CARETSTYLE_BLOCK
)
6723 vs
.caretStyle
= static_cast<int>(wParam
);
6725 /* Default to the line caret */
6726 vs
.caretStyle
= CARETSTYLE_LINE
;
6727 InvalidateStyleRedraw();
6730 case SCI_GETCARETSTYLE
:
6731 return vs
.caretStyle
;
6733 case SCI_SETCARETWIDTH
:
6734 if (static_cast<int>(wParam
) <= 0)
6736 else if (wParam
>= 3)
6739 vs
.caretWidth
= static_cast<int>(wParam
);
6740 InvalidateStyleRedraw();
6743 case SCI_GETCARETWIDTH
:
6744 return vs
.caretWidth
;
6746 case SCI_ASSIGNCMDKEY
:
6747 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
6748 Platform::HighShortFromLong(static_cast<long>(wParam
)), static_cast<unsigned int>(lParam
));
6751 case SCI_CLEARCMDKEY
:
6752 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
6753 Platform::HighShortFromLong(static_cast<long>(wParam
)), SCI_NULL
);
6756 case SCI_CLEARALLCMDKEYS
:
6760 case SCI_INDICSETSTYLE
:
6761 if (wParam
<= INDIC_MAX
) {
6762 vs
.indicators
[wParam
].style
= static_cast<int>(lParam
);
6763 InvalidateStyleRedraw();
6767 case SCI_INDICGETSTYLE
:
6768 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].style
: 0;
6770 case SCI_INDICSETFORE
:
6771 if (wParam
<= INDIC_MAX
) {
6772 vs
.indicators
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6773 InvalidateStyleRedraw();
6777 case SCI_INDICGETFORE
:
6778 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fore
.AsLong() : 0;
6780 case SCI_INDICSETUNDER
:
6781 if (wParam
<= INDIC_MAX
) {
6782 vs
.indicators
[wParam
].under
= lParam
!= 0;
6783 InvalidateStyleRedraw();
6787 case SCI_INDICGETUNDER
:
6788 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
6790 case SCI_INDICSETALPHA
:
6791 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
6792 vs
.indicators
[wParam
].fillAlpha
= static_cast<int>(lParam
);
6793 InvalidateStyleRedraw();
6797 case SCI_INDICGETALPHA
:
6798 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
6800 case SCI_INDICSETOUTLINEALPHA
:
6801 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
6802 vs
.indicators
[wParam
].outlineAlpha
= static_cast<int>(lParam
);
6803 InvalidateStyleRedraw();
6807 case SCI_INDICGETOUTLINEALPHA
:
6808 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
6810 case SCI_SETINDICATORCURRENT
:
6811 pdoc
->decorations
.SetCurrentIndicator(static_cast<int>(wParam
));
6813 case SCI_GETINDICATORCURRENT
:
6814 return pdoc
->decorations
.GetCurrentIndicator();
6815 case SCI_SETINDICATORVALUE
:
6816 pdoc
->decorations
.SetCurrentValue(static_cast<int>(wParam
));
6818 case SCI_GETINDICATORVALUE
:
6819 return pdoc
->decorations
.GetCurrentValue();
6821 case SCI_INDICATORFILLRANGE
:
6822 pdoc
->DecorationFillRange(static_cast<int>(wParam
), pdoc
->decorations
.GetCurrentValue(), static_cast<int>(lParam
));
6825 case SCI_INDICATORCLEARRANGE
:
6826 pdoc
->DecorationFillRange(static_cast<int>(wParam
), 0, static_cast<int>(lParam
));
6829 case SCI_INDICATORALLONFOR
:
6830 return pdoc
->decorations
.AllOnFor(static_cast<int>(wParam
));
6832 case SCI_INDICATORVALUEAT
:
6833 return pdoc
->decorations
.ValueAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
6835 case SCI_INDICATORSTART
:
6836 return pdoc
->decorations
.Start(static_cast<int>(wParam
), static_cast<int>(lParam
));
6838 case SCI_INDICATOREND
:
6839 return pdoc
->decorations
.End(static_cast<int>(wParam
), static_cast<int>(lParam
));
6842 case SCI_LINEDOWNEXTEND
:
6844 case SCI_PARADOWNEXTEND
:
6846 case SCI_LINEUPEXTEND
:
6848 case SCI_PARAUPEXTEND
:
6850 case SCI_CHARLEFTEXTEND
:
6852 case SCI_CHARRIGHTEXTEND
:
6854 case SCI_WORDLEFTEXTEND
:
6856 case SCI_WORDRIGHTEXTEND
:
6857 case SCI_WORDLEFTEND
:
6858 case SCI_WORDLEFTENDEXTEND
:
6859 case SCI_WORDRIGHTEND
:
6860 case SCI_WORDRIGHTENDEXTEND
:
6862 case SCI_HOMEEXTEND
:
6864 case SCI_LINEENDEXTEND
:
6866 case SCI_HOMEWRAPEXTEND
:
6867 case SCI_LINEENDWRAP
:
6868 case SCI_LINEENDWRAPEXTEND
:
6869 case SCI_DOCUMENTSTART
:
6870 case SCI_DOCUMENTSTARTEXTEND
:
6871 case SCI_DOCUMENTEND
:
6872 case SCI_DOCUMENTENDEXTEND
:
6873 case SCI_SCROLLTOSTART
:
6874 case SCI_SCROLLTOEND
:
6876 case SCI_STUTTEREDPAGEUP
:
6877 case SCI_STUTTEREDPAGEUPEXTEND
:
6878 case SCI_STUTTEREDPAGEDOWN
:
6879 case SCI_STUTTEREDPAGEDOWNEXTEND
:
6882 case SCI_PAGEUPEXTEND
:
6884 case SCI_PAGEDOWNEXTEND
:
6885 case SCI_EDITTOGGLEOVERTYPE
:
6887 case SCI_DELETEBACK
:
6893 case SCI_VCHOMEEXTEND
:
6894 case SCI_VCHOMEWRAP
:
6895 case SCI_VCHOMEWRAPEXTEND
:
6896 case SCI_VCHOMEDISPLAY
:
6897 case SCI_VCHOMEDISPLAYEXTEND
:
6900 case SCI_DELWORDLEFT
:
6901 case SCI_DELWORDRIGHT
:
6902 case SCI_DELWORDRIGHTEND
:
6903 case SCI_DELLINELEFT
:
6904 case SCI_DELLINERIGHT
:
6907 case SCI_LINEDELETE
:
6908 case SCI_LINETRANSPOSE
:
6909 case SCI_LINEDUPLICATE
:
6912 case SCI_LINESCROLLDOWN
:
6913 case SCI_LINESCROLLUP
:
6914 case SCI_WORDPARTLEFT
:
6915 case SCI_WORDPARTLEFTEXTEND
:
6916 case SCI_WORDPARTRIGHT
:
6917 case SCI_WORDPARTRIGHTEXTEND
:
6918 case SCI_DELETEBACKNOTLINE
:
6919 case SCI_HOMEDISPLAY
:
6920 case SCI_HOMEDISPLAYEXTEND
:
6921 case SCI_LINEENDDISPLAY
:
6922 case SCI_LINEENDDISPLAYEXTEND
:
6923 case SCI_LINEDOWNRECTEXTEND
:
6924 case SCI_LINEUPRECTEXTEND
:
6925 case SCI_CHARLEFTRECTEXTEND
:
6926 case SCI_CHARRIGHTRECTEXTEND
:
6927 case SCI_HOMERECTEXTEND
:
6928 case SCI_VCHOMERECTEXTEND
:
6929 case SCI_LINEENDRECTEXTEND
:
6930 case SCI_PAGEUPRECTEXTEND
:
6931 case SCI_PAGEDOWNRECTEXTEND
:
6932 case SCI_SELECTIONDUPLICATE
:
6933 return KeyCommand(iMessage
);
6935 case SCI_BRACEHIGHLIGHT
:
6936 SetBraceHighlight(static_cast<int>(wParam
), static_cast<int>(lParam
), STYLE_BRACELIGHT
);
6939 case SCI_BRACEHIGHLIGHTINDICATOR
:
6940 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
6941 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
6942 vs
.braceHighlightIndicator
= static_cast<int>(lParam
);
6946 case SCI_BRACEBADLIGHT
:
6947 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
6950 case SCI_BRACEBADLIGHTINDICATOR
:
6951 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
6952 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
6953 vs
.braceBadLightIndicator
= static_cast<int>(lParam
);
6957 case SCI_BRACEMATCH
:
6958 // wParam is position of char to find brace for,
6959 // lParam is maximum amount of text to restyle to find it
6960 return pdoc
->BraceMatch(static_cast<int>(wParam
), static_cast<int>(lParam
));
6962 case SCI_GETVIEWEOL
:
6965 case SCI_SETVIEWEOL
:
6966 vs
.viewEOL
= wParam
!= 0;
6967 InvalidateStyleRedraw();
6971 vs
.zoomLevel
= static_cast<int>(wParam
);
6972 InvalidateStyleRedraw();
6977 return vs
.zoomLevel
;
6979 case SCI_GETEDGECOLUMN
:
6982 case SCI_SETEDGECOLUMN
:
6983 vs
.theEdge
= static_cast<int>(wParam
);
6984 InvalidateStyleRedraw();
6987 case SCI_GETEDGEMODE
:
6988 return vs
.edgeState
;
6990 case SCI_SETEDGEMODE
:
6991 vs
.edgeState
= static_cast<int>(wParam
);
6992 InvalidateStyleRedraw();
6995 case SCI_GETEDGECOLOUR
:
6996 return vs
.edgecolour
.AsLong();
6998 case SCI_SETEDGECOLOUR
:
6999 vs
.edgecolour
= ColourDesired(static_cast<long>(wParam
));
7000 InvalidateStyleRedraw();
7003 case SCI_GETDOCPOINTER
:
7004 return reinterpret_cast<sptr_t
>(pdoc
);
7006 case SCI_SETDOCPOINTER
:
7008 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7011 case SCI_CREATEDOCUMENT
: {
7012 Document
*doc
= new Document();
7014 return reinterpret_cast<sptr_t
>(doc
);
7017 case SCI_ADDREFDOCUMENT
:
7018 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7021 case SCI_RELEASEDOCUMENT
:
7022 (reinterpret_cast<Document
*>(lParam
))->Release();
7025 case SCI_CREATELOADER
: {
7026 Document
*doc
= new Document();
7028 doc
->Allocate(static_cast<int>(wParam
));
7029 doc
->SetUndoCollection(false);
7030 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
7033 case SCI_SETMODEVENTMASK
:
7034 modEventMask
= static_cast<int>(wParam
);
7037 case SCI_GETMODEVENTMASK
:
7038 return modEventMask
;
7040 case SCI_CONVERTEOLS
:
7041 pdoc
->ConvertLineEnds(static_cast<int>(wParam
));
7042 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7045 case SCI_SETLENGTHFORENCODE
:
7046 lengthForEncode
= static_cast<int>(wParam
);
7049 case SCI_SELECTIONISRECTANGLE
:
7050 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7052 case SCI_SETSELECTIONMODE
: {
7055 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7056 sel
.selType
= Selection::selStream
;
7058 case SC_SEL_RECTANGLE
:
7059 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7060 sel
.selType
= Selection::selRectangle
;
7063 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7064 sel
.selType
= Selection::selLines
;
7067 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7068 sel
.selType
= Selection::selThin
;
7071 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7072 sel
.selType
= Selection::selStream
;
7074 InvalidateSelection(sel
.RangeMain(), true);
7077 case SCI_GETSELECTIONMODE
:
7078 switch (sel
.selType
) {
7079 case Selection::selStream
:
7080 return SC_SEL_STREAM
;
7081 case Selection::selRectangle
:
7082 return SC_SEL_RECTANGLE
;
7083 case Selection::selLines
:
7084 return SC_SEL_LINES
;
7085 case Selection::selThin
:
7088 return SC_SEL_STREAM
;
7090 case SCI_GETLINESELSTARTPOSITION
:
7091 case SCI_GETLINESELENDPOSITION
: {
7092 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(static_cast<int>(wParam
))),
7093 SelectionPosition(pdoc
->LineEnd(static_cast<int>(wParam
))));
7094 for (size_t r
=0; r
<sel
.Count(); r
++) {
7095 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7096 if (portion
.start
.IsValid()) {
7097 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
7100 return INVALID_POSITION
;
7103 case SCI_SETOVERTYPE
:
7104 inOverstrike
= wParam
!= 0;
7107 case SCI_GETOVERTYPE
:
7108 return inOverstrike
? 1 : 0;
7111 SetFocusState(wParam
!= 0);
7118 errorStatus
= static_cast<int>(wParam
);
7124 case SCI_SETMOUSEDOWNCAPTURES
:
7125 mouseDownCaptures
= wParam
!= 0;
7128 case SCI_GETMOUSEDOWNCAPTURES
:
7129 return mouseDownCaptures
;
7132 cursorMode
= static_cast<int>(wParam
);
7133 DisplayCursor(Window::cursorText
);
7139 case SCI_SETCONTROLCHARSYMBOL
:
7140 vs
.controlCharSymbol
= static_cast<int>(wParam
);
7141 InvalidateStyleRedraw();
7144 case SCI_GETCONTROLCHARSYMBOL
:
7145 return vs
.controlCharSymbol
;
7147 case SCI_SETREPRESENTATION
:
7148 reprs
.SetRepresentation(reinterpret_cast<const char *>(wParam
), CharPtrFromSPtr(lParam
));
7151 case SCI_GETREPRESENTATION
: {
7152 const Representation
*repr
= reprs
.RepresentationFromCharacter(
7153 reinterpret_cast<const char *>(wParam
), UTF8MaxBytes
);
7155 return StringResult(lParam
, repr
->stringRep
.c_str());
7160 case SCI_CLEARREPRESENTATION
:
7161 reprs
.ClearRepresentation(reinterpret_cast<const char *>(wParam
));
7164 case SCI_STARTRECORD
:
7165 recordingMacro
= true;
7168 case SCI_STOPRECORD
:
7169 recordingMacro
= false;
7172 case SCI_MOVECARETINSIDEVIEW
:
7173 MoveCaretInsideView();
7176 case SCI_SETFOLDMARGINCOLOUR
:
7177 vs
.foldmarginColour
= ColourOptional(wParam
, lParam
);
7178 InvalidateStyleRedraw();
7181 case SCI_SETFOLDMARGINHICOLOUR
:
7182 vs
.foldmarginHighlightColour
= ColourOptional(wParam
, lParam
);
7183 InvalidateStyleRedraw();
7186 case SCI_SETHOTSPOTACTIVEFORE
:
7187 vs
.hotspotColours
.fore
= ColourOptional(wParam
, lParam
);
7188 InvalidateStyleRedraw();
7191 case SCI_GETHOTSPOTACTIVEFORE
:
7192 return vs
.hotspotColours
.fore
.AsLong();
7194 case SCI_SETHOTSPOTACTIVEBACK
:
7195 vs
.hotspotColours
.back
= ColourOptional(wParam
, lParam
);
7196 InvalidateStyleRedraw();
7199 case SCI_GETHOTSPOTACTIVEBACK
:
7200 return vs
.hotspotColours
.back
.AsLong();
7202 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7203 vs
.hotspotUnderline
= wParam
!= 0;
7204 InvalidateStyleRedraw();
7207 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7208 return vs
.hotspotUnderline
? 1 : 0;
7210 case SCI_SETHOTSPOTSINGLELINE
:
7211 vs
.hotspotSingleLine
= wParam
!= 0;
7212 InvalidateStyleRedraw();
7215 case SCI_GETHOTSPOTSINGLELINE
:
7216 return vs
.hotspotSingleLine
? 1 : 0;
7218 case SCI_SETPASTECONVERTENDINGS
:
7219 convertPastes
= wParam
!= 0;
7222 case SCI_GETPASTECONVERTENDINGS
:
7223 return convertPastes
? 1 : 0;
7225 case SCI_GETCHARACTERPOINTER
:
7226 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
7228 case SCI_GETRANGEPOINTER
:
7229 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7231 case SCI_GETGAPPOSITION
:
7232 return pdoc
->GapPosition();
7234 case SCI_SETEXTRAASCENT
:
7235 vs
.extraAscent
= static_cast<int>(wParam
);
7236 InvalidateStyleRedraw();
7239 case SCI_GETEXTRAASCENT
:
7240 return vs
.extraAscent
;
7242 case SCI_SETEXTRADESCENT
:
7243 vs
.extraDescent
= static_cast<int>(wParam
);
7244 InvalidateStyleRedraw();
7247 case SCI_GETEXTRADESCENT
:
7248 return vs
.extraDescent
;
7250 case SCI_MARGINSETSTYLEOFFSET
:
7251 vs
.marginStyleOffset
= static_cast<int>(wParam
);
7252 InvalidateStyleRedraw();
7255 case SCI_MARGINGETSTYLEOFFSET
:
7256 return vs
.marginStyleOffset
;
7258 case SCI_SETMARGINOPTIONS
:
7259 marginOptions
= static_cast<int>(wParam
);
7262 case SCI_GETMARGINOPTIONS
:
7263 return marginOptions
;
7265 case SCI_MARGINSETTEXT
:
7266 pdoc
->MarginSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7269 case SCI_MARGINGETTEXT
: {
7270 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7271 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7274 case SCI_MARGINSETSTYLE
:
7275 pdoc
->MarginSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7278 case SCI_MARGINGETSTYLE
: {
7279 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7283 case SCI_MARGINSETSTYLES
:
7284 pdoc
->MarginSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7287 case SCI_MARGINGETSTYLES
: {
7288 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7289 return BytesResult(lParam
, st
.styles
, st
.length
);
7292 case SCI_MARGINTEXTCLEARALL
:
7293 pdoc
->MarginClearAll();
7296 case SCI_ANNOTATIONSETTEXT
:
7297 pdoc
->AnnotationSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7300 case SCI_ANNOTATIONGETTEXT
: {
7301 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7302 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7305 case SCI_ANNOTATIONGETSTYLE
: {
7306 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7310 case SCI_ANNOTATIONSETSTYLE
:
7311 pdoc
->AnnotationSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7314 case SCI_ANNOTATIONSETSTYLES
:
7315 pdoc
->AnnotationSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7318 case SCI_ANNOTATIONGETSTYLES
: {
7319 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7320 return BytesResult(lParam
, st
.styles
, st
.length
);
7323 case SCI_ANNOTATIONGETLINES
:
7324 return pdoc
->AnnotationLines(static_cast<int>(wParam
));
7326 case SCI_ANNOTATIONCLEARALL
:
7327 pdoc
->AnnotationClearAll();
7330 case SCI_ANNOTATIONSETVISIBLE
:
7331 SetAnnotationVisible(static_cast<int>(wParam
));
7334 case SCI_ANNOTATIONGETVISIBLE
:
7335 return vs
.annotationVisible
;
7337 case SCI_ANNOTATIONSETSTYLEOFFSET
:
7338 vs
.annotationStyleOffset
= static_cast<int>(wParam
);
7339 InvalidateStyleRedraw();
7342 case SCI_ANNOTATIONGETSTYLEOFFSET
:
7343 return vs
.annotationStyleOffset
;
7345 case SCI_RELEASEALLEXTENDEDSTYLES
:
7346 vs
.ReleaseAllExtendedStyles();
7349 case SCI_ALLOCATEEXTENDEDSTYLES
:
7350 return vs
.AllocateExtendedStyles(static_cast<int>(wParam
));
7352 case SCI_ADDUNDOACTION
:
7353 pdoc
->AddUndoAction(static_cast<int>(wParam
), lParam
& UNDO_MAY_COALESCE
);
7356 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH
:
7357 mouseSelectionRectangularSwitch
= wParam
!= 0;
7360 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH
:
7361 return mouseSelectionRectangularSwitch
;
7363 case SCI_SETMULTIPLESELECTION
:
7364 multipleSelection
= wParam
!= 0;
7368 case SCI_GETMULTIPLESELECTION
:
7369 return multipleSelection
;
7371 case SCI_SETADDITIONALSELECTIONTYPING
:
7372 additionalSelectionTyping
= wParam
!= 0;
7376 case SCI_GETADDITIONALSELECTIONTYPING
:
7377 return additionalSelectionTyping
;
7379 case SCI_SETMULTIPASTE
:
7380 multiPasteMode
= static_cast<int>(wParam
);
7383 case SCI_GETMULTIPASTE
:
7384 return multiPasteMode
;
7386 case SCI_SETADDITIONALCARETSBLINK
:
7387 view
.additionalCaretsBlink
= wParam
!= 0;
7391 case SCI_GETADDITIONALCARETSBLINK
:
7392 return view
.additionalCaretsBlink
;
7394 case SCI_SETADDITIONALCARETSVISIBLE
:
7395 view
.additionalCaretsVisible
= wParam
!= 0;
7399 case SCI_GETADDITIONALCARETSVISIBLE
:
7400 return view
.additionalCaretsVisible
;
7402 case SCI_GETSELECTIONS
:
7405 case SCI_GETSELECTIONEMPTY
:
7408 case SCI_CLEARSELECTIONS
:
7413 case SCI_SETSELECTION
:
7414 sel
.SetSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7418 case SCI_ADDSELECTION
:
7419 sel
.AddSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7423 case SCI_DROPSELECTIONN
:
7424 sel
.DropSelection(static_cast<int>(wParam
));
7428 case SCI_SETMAINSELECTION
:
7429 sel
.SetMain(static_cast<int>(wParam
));
7433 case SCI_GETMAINSELECTION
:
7436 case SCI_SETSELECTIONNCARET
:
7437 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7441 case SCI_GETSELECTIONNCARET
:
7442 return sel
.Range(wParam
).caret
.Position();
7444 case SCI_SETSELECTIONNANCHOR
:
7445 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7448 case SCI_GETSELECTIONNANCHOR
:
7449 return sel
.Range(wParam
).anchor
.Position();
7451 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
7452 sel
.Range(wParam
).caret
.SetVirtualSpace(static_cast<int>(lParam
));
7456 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
7457 return sel
.Range(wParam
).caret
.VirtualSpace();
7459 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
7460 sel
.Range(wParam
).anchor
.SetVirtualSpace(static_cast<int>(lParam
));
7464 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
7465 return sel
.Range(wParam
).anchor
.VirtualSpace();
7467 case SCI_SETSELECTIONNSTART
:
7468 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7472 case SCI_GETSELECTIONNSTART
:
7473 return sel
.Range(wParam
).Start().Position();
7475 case SCI_SETSELECTIONNEND
:
7476 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7480 case SCI_GETSELECTIONNEND
:
7481 return sel
.Range(wParam
).End().Position();
7483 case SCI_SETRECTANGULARSELECTIONCARET
:
7484 if (!sel
.IsRectangular())
7486 sel
.selType
= Selection::selRectangle
;
7487 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
7488 SetRectangularRange();
7492 case SCI_GETRECTANGULARSELECTIONCARET
:
7493 return sel
.Rectangular().caret
.Position();
7495 case SCI_SETRECTANGULARSELECTIONANCHOR
:
7496 if (!sel
.IsRectangular())
7498 sel
.selType
= Selection::selRectangle
;
7499 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
7500 SetRectangularRange();
7504 case SCI_GETRECTANGULARSELECTIONANCHOR
:
7505 return sel
.Rectangular().anchor
.Position();
7507 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7508 if (!sel
.IsRectangular())
7510 sel
.selType
= Selection::selRectangle
;
7511 sel
.Rectangular().caret
.SetVirtualSpace(static_cast<int>(wParam
));
7512 SetRectangularRange();
7516 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7517 return sel
.Rectangular().caret
.VirtualSpace();
7519 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7520 if (!sel
.IsRectangular())
7522 sel
.selType
= Selection::selRectangle
;
7523 sel
.Rectangular().anchor
.SetVirtualSpace(static_cast<int>(wParam
));
7524 SetRectangularRange();
7528 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7529 return sel
.Rectangular().anchor
.VirtualSpace();
7531 case SCI_SETVIRTUALSPACEOPTIONS
:
7532 virtualSpaceOptions
= static_cast<int>(wParam
);
7535 case SCI_GETVIRTUALSPACEOPTIONS
:
7536 return virtualSpaceOptions
;
7538 case SCI_SETADDITIONALSELFORE
:
7539 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(wParam
));
7540 InvalidateStyleRedraw();
7543 case SCI_SETADDITIONALSELBACK
:
7544 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(wParam
));
7545 InvalidateStyleRedraw();
7548 case SCI_SETADDITIONALSELALPHA
:
7549 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7550 InvalidateStyleRedraw();
7553 case SCI_GETADDITIONALSELALPHA
:
7554 return vs
.selAdditionalAlpha
;
7556 case SCI_SETADDITIONALCARETFORE
:
7557 vs
.additionalCaretColour
= ColourDesired(static_cast<long>(wParam
));
7558 InvalidateStyleRedraw();
7561 case SCI_GETADDITIONALCARETFORE
:
7562 return vs
.additionalCaretColour
.AsLong();
7564 case SCI_ROTATESELECTION
:
7566 InvalidateSelection(sel
.RangeMain(), true);
7569 case SCI_SWAPMAINANCHORCARET
:
7570 InvalidateSelection(sel
.RangeMain());
7571 sel
.RangeMain() = SelectionRange(sel
.RangeMain().anchor
, sel
.RangeMain().caret
);
7574 case SCI_CHANGELEXERSTATE
:
7575 pdoc
->ChangeLexerState(static_cast<int>(wParam
), static_cast<int>(lParam
));
7578 case SCI_SETIDENTIFIER
:
7579 SetCtrlID(static_cast<int>(wParam
));
7582 case SCI_GETIDENTIFIER
:
7585 case SCI_SETTECHNOLOGY
:
7586 // No action by default
7589 case SCI_GETTECHNOLOGY
:
7592 case SCI_COUNTCHARACTERS
:
7593 return pdoc
->CountCharacters(static_cast<int>(wParam
), static_cast<int>(lParam
));
7596 return DefWndProc(iMessage
, wParam
, lParam
);
7598 //Platform::DebugPrintf("end wnd proc\n");