1 // Scintilla source code edit control
3 ** Main code for the edit control.
5 // Copyright 1998-2011 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
25 #include "Scintilla.h"
27 #include "StringCopy.h"
29 #include "SplitVector.h"
30 #include "Partitioning.h"
31 #include "RunStyles.h"
32 #include "ContractionState.h"
33 #include "CellBuffer.h"
36 #include "Indicator.h"
38 #include "LineMarker.h"
40 #include "ViewStyle.h"
41 #include "CharClassify.h"
42 #include "Decoration.h"
43 #include "CaseFolder.h"
45 #include "UniConversion.h"
46 #include "Selection.h"
47 #include "PositionCache.h"
48 #include "EditModel.h"
49 #include "MarginView.h"
54 using namespace Scintilla
;
58 return whether this modification represents an operation that
59 may reasonably be deferred (not done now OR [possibly] at all)
61 static bool CanDeferToLastStep(const DocModification
&mh
) {
62 if (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
))
63 return true; // CAN skip
64 if (!(mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)))
65 return false; // MUST do
66 if (mh
.modificationType
& SC_MULTISTEPUNDOREDO
)
67 return true; // CAN skip
68 return false; // PRESUMABLY must do
71 static bool CanEliminate(const DocModification
&mh
) {
73 (mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) != 0;
77 return whether this modification represents the FINAL step
78 in a [possibly lengthy] multi-step Undo/Redo sequence
80 static bool IsLastStep(const DocModification
&mh
) {
82 (mh
.modificationType
& (SC_PERFORMED_UNDO
| SC_PERFORMED_REDO
)) != 0
83 && (mh
.modificationType
& SC_MULTISTEPUNDOREDO
) != 0
84 && (mh
.modificationType
& SC_LASTSTEPINUNDOREDO
) != 0
85 && (mh
.modificationType
& SC_MULTILINEUNDOREDO
) != 0;
89 ticking(false), ticksToWait(0), tickerID(0) {}
92 state(false), idlerID(0) {}
94 static inline bool IsAllSpacesOrTabs(const char *s
, unsigned int len
) {
95 for (unsigned int i
= 0; i
< len
; i
++) {
96 // This is safe because IsSpaceOrTab() will return false for null terminators
97 if (!IsSpaceOrTab(s
[i
]))
108 technology
= SC_TECHNOLOGY_DEFAULT
;
109 scaleRGBAImage
= 100.0f
;
111 cursorMode
= SC_CURSORNORMAL
;
115 mouseDownCaptures
= true;
116 mouseWheelCaptures
= true;
119 doubleClickCloseThreshold
= Point(3, 3);
120 dwellDelay
= SC_TIME_FOREVER
;
121 ticksToDwell
= SC_TIME_FOREVER
;
126 dropWentOutside
= false;
127 posDrop
= SelectionPosition(invalidPosition
);
128 hotSpotClickPos
= INVALID_POSITION
;
129 selectionType
= selChar
;
133 originalAnchorPos
= 0;
134 wordSelectAnchorStartPos
= 0;
135 wordSelectAnchorEndPos
= 0;
136 wordSelectInitialCaretPos
= -1;
138 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
141 caretYPolicy
= CARET_EVEN
;
150 horizontalScrollBarVisible
= true;
152 verticalScrollBarVisible
= true;
153 endAtLastLine
= true;
154 caretSticky
= SC_CARETSTICKY_OFF
;
155 marginOptions
= SC_MARGINOPTION_NONE
;
156 mouseSelectionRectangularSwitch
= false;
157 multipleSelection
= false;
158 additionalSelectionTyping
= false;
159 multiPasteMode
= SC_MULTIPASTE_ONCE
;
160 virtualSpaceOptions
= SCVS_NONE
;
169 lengthForEncode
= -1;
172 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
174 paintState
= notPainting
;
175 paintAbandonedByStyling
= false;
176 paintingAllText
= false;
177 willRedrawAll
= false;
178 idleStyling
= SC_IDLESTYLING_NONE
;
179 needIdleStyling
= false;
181 modEventMask
= SC_MODEVENTMASKALL
;
183 pdoc
->AddWatcher(this, 0);
185 recordingMacro
= false;
188 convertPastes
= true;
190 SetRepresentations();
194 pdoc
->RemoveWatcher(this, 0);
198 void Editor::Finalise() {
203 void Editor::SetRepresentations() {
207 const char *reps
[] = {
208 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
209 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
210 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
211 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
213 for (size_t j
=0; j
< ELEMENTS(reps
); j
++) {
214 char c
[2] = { static_cast<char>(j
), 0 };
215 reprs
.SetRepresentation(c
, reps
[j
]);
219 // As well as Unicode mode, ISO-8859-1 should use these
220 if (IsUnicodeMode()) {
221 const char *repsC1
[] = {
222 "PAD", "HOP", "BPH", "NBH", "IND", "NEL", "SSA", "ESA",
223 "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
224 "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
225 "SOS", "SGCI", "SCI", "CSI", "ST", "OSC", "PM", "APC"
227 for (size_t j
=0; j
< ELEMENTS(repsC1
); j
++) {
228 char c1
[3] = { '\xc2', static_cast<char>(0x80+j
), 0 };
229 reprs
.SetRepresentation(c1
, repsC1
[j
]);
231 reprs
.SetRepresentation("\xe2\x80\xa8", "LS");
232 reprs
.SetRepresentation("\xe2\x80\xa9", "PS");
235 // UTF-8 invalid bytes
236 if (IsUnicodeMode()) {
237 for (int k
=0x80; k
< 0x100; k
++) {
238 char hiByte
[2] = { static_cast<char>(k
), 0 };
240 sprintf(hexits
, "x%2X", k
);
241 reprs
.SetRepresentation(hiByte
, hexits
);
246 void Editor::DropGraphics(bool freeObjects
) {
247 marginView
.DropGraphics(freeObjects
);
248 view
.DropGraphics(freeObjects
);
251 void Editor::AllocateGraphics() {
252 marginView
.AllocateGraphics(vs
);
253 view
.AllocateGraphics(vs
);
256 void Editor::InvalidateStyleData() {
258 vs
.technology
= technology
;
261 view
.llc
.Invalidate(LineLayout::llInvalid
);
262 view
.posCache
.Clear();
265 void Editor::InvalidateStyleRedraw() {
267 InvalidateStyleData();
271 void Editor::RefreshStyleData() {
274 AutoSurface
surface(this);
276 vs
.Refresh(*surface
, pdoc
->tabInChars
);
279 SetRectangularRange();
283 Point
Editor::GetVisibleOriginInMain() const {
287 PointDocument
Editor::DocumentPointFromView(Point ptView
) const {
288 PointDocument
ptDocument(ptView
);
289 if (wMargin
.GetID()) {
290 Point ptOrigin
= GetVisibleOriginInMain();
291 ptDocument
.x
+= ptOrigin
.x
;
292 ptDocument
.y
+= ptOrigin
.y
;
294 ptDocument
.x
+= xOffset
;
295 ptDocument
.y
+= topLine
* vs
.lineHeight
;
300 int Editor::TopLineOfMain() const {
307 PRectangle
Editor::GetClientRectangle() const {
309 return win
.GetClientPosition();
312 PRectangle
Editor::GetClientDrawingRectangle() {
313 return GetClientRectangle();
316 PRectangle
Editor::GetTextRectangle() const {
317 PRectangle rc
= GetClientRectangle();
318 rc
.left
+= vs
.textStart
;
319 rc
.right
-= vs
.rightMarginWidth
;
323 int Editor::LinesOnScreen() const {
324 PRectangle rcClient
= GetClientRectangle();
325 int htClient
= static_cast<int>(rcClient
.bottom
- rcClient
.top
);
326 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
327 return htClient
/ vs
.lineHeight
;
330 int Editor::LinesToScroll() const {
331 int retVal
= LinesOnScreen() - 1;
338 int Editor::MaxScrollPos() const {
339 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
340 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
341 int retVal
= cs
.LinesDisplayed();
343 retVal
-= LinesOnScreen();
354 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
355 if (sp
.Position() < 0) {
356 return SelectionPosition(0);
357 } else if (sp
.Position() > pdoc
->Length()) {
358 return SelectionPosition(pdoc
->Length());
360 // If not at end of line then set offset to 0
361 if (!pdoc
->IsLineEndPosition(sp
.Position()))
362 sp
.SetVirtualSpace(0);
367 Point
Editor::LocationFromPosition(SelectionPosition pos
, PointEnd pe
) {
369 AutoSurface
surface(this);
370 return view
.LocationFromPosition(surface
, *this, pos
, topLine
, vs
, pe
);
373 Point
Editor::LocationFromPosition(int pos
, PointEnd pe
) {
374 return LocationFromPosition(SelectionPosition(pos
), pe
);
377 int Editor::XFromPosition(int pos
) {
378 Point pt
= LocationFromPosition(pos
);
379 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
382 int Editor::XFromPosition(SelectionPosition sp
) {
383 Point pt
= LocationFromPosition(sp
);
384 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
387 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
389 AutoSurface
surface(this);
391 if (canReturnInvalid
) {
392 PRectangle rcClient
= GetTextRectangle();
393 // May be in scroll view coordinates so translate back to main view
394 Point ptOrigin
= GetVisibleOriginInMain();
395 rcClient
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
396 if (!rcClient
.Contains(pt
))
397 return SelectionPosition(INVALID_POSITION
);
398 if (pt
.x
< vs
.textStart
)
399 return SelectionPosition(INVALID_POSITION
);
401 return SelectionPosition(INVALID_POSITION
);
403 PointDocument ptdoc
= DocumentPointFromView(pt
);
404 return view
.SPositionFromLocation(surface
, *this, ptdoc
, canReturnInvalid
, charPosition
, virtualSpace
, vs
);
407 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
408 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
412 * Find the document position corresponding to an x coordinate on a particular document line.
413 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
414 * This method is used for rectangular selections and does not work on wrapped lines.
416 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
418 if (lineDoc
>= pdoc
->LinesTotal())
419 return SelectionPosition(pdoc
->Length());
420 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
421 AutoSurface
surface(this);
422 return view
.SPositionFromLineX(surface
, *this, lineDoc
, x
, vs
);
425 int Editor::PositionFromLineX(int lineDoc
, int x
) {
426 return SPositionFromLineX(lineDoc
, x
).Position();
429 int Editor::LineFromLocation(Point pt
) const {
430 return cs
.DocFromDisplay(static_cast<int>(pt
.y
) / vs
.lineHeight
+ topLine
);
433 void Editor::SetTopLine(int topLineNew
) {
434 if ((topLine
!= topLineNew
) && (topLineNew
>= 0)) {
435 topLine
= topLineNew
;
436 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
438 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
442 * If painting then abandon the painting because a wider redraw is needed.
443 * @return true if calling code should stop drawing.
445 bool Editor::AbandonPaint() {
446 if ((paintState
== painting
) && !paintingAllText
) {
447 paintState
= paintAbandoned
;
449 return paintState
== paintAbandoned
;
452 void Editor::RedrawRect(PRectangle rc
) {
453 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
455 // Clip the redraw rectangle into the client area
456 PRectangle rcClient
= GetClientRectangle();
457 if (rc
.top
< rcClient
.top
)
458 rc
.top
= rcClient
.top
;
459 if (rc
.bottom
> rcClient
.bottom
)
460 rc
.bottom
= rcClient
.bottom
;
461 if (rc
.left
< rcClient
.left
)
462 rc
.left
= rcClient
.left
;
463 if (rc
.right
> rcClient
.right
)
464 rc
.right
= rcClient
.right
;
466 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
467 wMain
.InvalidateRectangle(rc
);
471 void Editor::DiscardOverdraw() {
472 // Overridden on platforms that may draw outside visible area.
475 void Editor::Redraw() {
476 //Platform::DebugPrintf("Redraw all\n");
477 PRectangle rcClient
= GetClientRectangle();
478 wMain
.InvalidateRectangle(rcClient
);
480 wMargin
.InvalidateAll();
481 //wMain.InvalidateAll();
484 void Editor::RedrawSelMargin(int line
, bool allAfter
) {
485 const bool markersInText
= vs
.maskInLine
|| vs
.maskDrawInText
;
486 if (!wMargin
.GetID() || markersInText
) { // May affect text area so may need to abandon and retry
487 if (AbandonPaint()) {
491 if (wMargin
.GetID() && markersInText
) {
495 PRectangle rcMarkers
= GetClientRectangle();
496 if (!markersInText
) {
497 // Normal case: just draw the margin
498 rcMarkers
.right
= rcMarkers
.left
+ vs
.fixedColumnWidth
;
501 PRectangle rcLine
= RectangleFromRange(Range(pdoc
->LineStart(line
)), 0);
503 // Inflate line rectangle if there are image markers with height larger than line height
504 if (vs
.largestMarkerHeight
> vs
.lineHeight
) {
505 int delta
= (vs
.largestMarkerHeight
- vs
.lineHeight
+ 1) / 2;
507 rcLine
.bottom
+= delta
;
508 if (rcLine
.top
< rcMarkers
.top
)
509 rcLine
.top
= rcMarkers
.top
;
510 if (rcLine
.bottom
> rcMarkers
.bottom
)
511 rcLine
.bottom
= rcMarkers
.bottom
;
514 rcMarkers
.top
= rcLine
.top
;
516 rcMarkers
.bottom
= rcLine
.bottom
;
517 if (rcMarkers
.Empty())
520 if (wMargin
.GetID()) {
521 Point ptOrigin
= GetVisibleOriginInMain();
522 rcMarkers
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
523 wMargin
.InvalidateRectangle(rcMarkers
);
525 wMain
.InvalidateRectangle(rcMarkers
);
529 PRectangle
Editor::RectangleFromRange(Range r
, int overlap
) {
530 const int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.First()));
531 const int maxLine
= cs
.DisplayLastFromDoc(pdoc
->LineFromPosition(r
.Last()));
532 const PRectangle rcClientDrawing
= GetClientDrawingRectangle();
534 const int leftTextOverlap
= ((xOffset
== 0) && (vs
.leftMarginWidth
> 0)) ? 1 : 0;
535 rc
.left
= static_cast<XYPOSITION
>(vs
.textStart
- leftTextOverlap
);
536 rc
.top
= static_cast<XYPOSITION
>((minLine
- TopLineOfMain()) * vs
.lineHeight
- overlap
);
537 if (rc
.top
< rcClientDrawing
.top
)
538 rc
.top
= rcClientDrawing
.top
;
539 // Extend to right of prepared area if any to prevent artifacts from caret line highlight
540 rc
.right
= rcClientDrawing
.right
;
541 rc
.bottom
= static_cast<XYPOSITION
>((maxLine
- TopLineOfMain() + 1) * vs
.lineHeight
+ overlap
);
546 void Editor::InvalidateRange(int start
, int end
) {
547 RedrawRect(RectangleFromRange(Range(start
, end
), view
.LinesOverlap() ? vs
.lineOverlap
: 0));
550 int Editor::CurrentPosition() const {
551 return sel
.MainCaret();
554 bool Editor::SelectionEmpty() const {
558 SelectionPosition
Editor::SelectionStart() {
559 return sel
.RangeMain().Start();
562 SelectionPosition
Editor::SelectionEnd() {
563 return sel
.RangeMain().End();
566 void Editor::SetRectangularRange() {
567 if (sel
.IsRectangular()) {
568 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
569 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
570 if (sel
.selType
== Selection::selThin
) {
573 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
574 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
575 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
576 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
577 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
578 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
579 range
.ClearVirtualSpace();
580 if (line
== lineAnchorRect
)
581 sel
.SetSelection(range
);
583 sel
.AddSelectionWithoutTrim(range
);
588 void Editor::ThinRectangularRange() {
589 if (sel
.IsRectangular()) {
590 sel
.selType
= Selection::selThin
;
591 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
592 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
594 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
596 SetRectangularRange();
600 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
601 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
602 invalidateWholeSelection
= true;
604 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
605 // +1 for lastAffected ensures caret repainted
606 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
607 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
608 if (invalidateWholeSelection
) {
609 for (size_t r
=0; r
<sel
.Count(); r
++) {
610 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
611 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
612 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
613 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
616 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
617 InvalidateRange(firstAffected
, lastAffected
);
620 void Editor::InvalidateWholeSelection() {
621 InvalidateSelection(sel
.RangeMain(), true);
624 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
625 currentPos_
= ClampPositionIntoDocument(currentPos_
);
626 anchor_
= ClampPositionIntoDocument(anchor_
);
627 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
628 /* For Line selection - ensure the anchor and caret are always
629 at the beginning and end of the region lines. */
630 if (sel
.selType
== Selection::selLines
) {
631 if (currentPos_
> anchor_
) {
632 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
633 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
635 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
636 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
639 SelectionRange
rangeNew(currentPos_
, anchor_
);
640 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
641 InvalidateSelection(rangeNew
);
643 sel
.RangeMain() = rangeNew
;
644 SetRectangularRange();
646 SetHoverIndicatorPosition(sel
.MainCaret());
648 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
651 QueueIdleWork(WorkNeeded::workUpdateUI
);
654 void Editor::SetSelection(int currentPos_
, int anchor_
) {
655 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
658 // Just move the caret on the main selection
659 void Editor::SetSelection(SelectionPosition currentPos_
) {
660 currentPos_
= ClampPositionIntoDocument(currentPos_
);
661 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
662 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
663 InvalidateSelection(SelectionRange(currentPos_
));
665 if (sel
.IsRectangular()) {
667 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
668 SetRectangularRange();
671 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
674 SetHoverIndicatorPosition(sel
.MainCaret());
676 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
679 QueueIdleWork(WorkNeeded::workUpdateUI
);
682 void Editor::SetSelection(int currentPos_
) {
683 SetSelection(SelectionPosition(currentPos_
));
686 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
687 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
688 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
689 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
690 InvalidateSelection(rangeNew
);
693 sel
.RangeMain() = rangeNew
;
694 SetRectangularRange();
696 SetHoverIndicatorPosition(sel
.MainCaret());
698 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
701 QueueIdleWork(WorkNeeded::workUpdateUI
);
704 void Editor::SetEmptySelection(int currentPos_
) {
705 SetEmptySelection(SelectionPosition(currentPos_
));
708 void Editor::MultipleSelectAdd(AddNumber addNumber
) {
709 if (SelectionEmpty() || !multipleSelection
) {
710 // Select word at caret
711 const int startWord
= pdoc
->ExtendWordSelect(sel
.MainCaret(), -1, true);
712 const int endWord
= pdoc
->ExtendWordSelect(startWord
, 1, true);
713 TrimAndSetSelection(endWord
, startWord
);
717 if (!pdoc
->HasCaseFolder())
718 pdoc
->SetCaseFolder(CaseFolderForEncoding());
720 const Range
rangeMainSelection(sel
.RangeMain().Start().Position(), sel
.RangeMain().End().Position());
721 const std::string selectedText
= RangeText(rangeMainSelection
.start
, rangeMainSelection
.end
);
723 const Range
rangeTarget(targetStart
, targetEnd
);
724 std::vector
<Range
> searchRanges
;
725 // Search should be over the target range excluding the current selection so
726 // may need to search 2 ranges, after the selection then before the selection.
727 if (rangeTarget
.Overlaps(rangeMainSelection
)) {
728 // Common case is that the selection is completely within the target but
729 // may also have overlap at start or end.
730 if (rangeMainSelection
.end
< rangeTarget
.end
)
731 searchRanges
.push_back(Range(rangeMainSelection
.end
, rangeTarget
.end
));
732 if (rangeTarget
.start
< rangeMainSelection
.start
)
733 searchRanges
.push_back(Range(rangeTarget
.start
, rangeMainSelection
.start
));
736 searchRanges
.push_back(rangeTarget
);
739 for (std::vector
<Range
>::const_iterator it
= searchRanges
.begin(); it
!= searchRanges
.end(); ++it
) {
740 int searchStart
= it
->start
;
741 const int searchEnd
= it
->end
;
743 int lengthFound
= static_cast<int>(selectedText
.length());
744 int pos
= static_cast<int>(pdoc
->FindText(searchStart
, searchEnd
,
745 selectedText
.c_str(), searchFlags
, &lengthFound
));
747 sel
.AddSelection(SelectionRange(pos
+ lengthFound
, pos
));
748 ScrollRange(sel
.RangeMain());
750 if (addNumber
== addOne
)
752 searchStart
= pos
+ lengthFound
;
761 bool Editor::RangeContainsProtected(int start
, int end
) const {
762 if (vs
.ProtectionActive()) {
768 for (int pos
= start
; pos
< end
; pos
++) {
769 if (vs
.styles
[pdoc
->StyleIndexAt(pos
)].IsProtected())
776 bool Editor::SelectionContainsProtected() {
777 for (size_t r
=0; r
<sel
.Count(); r
++) {
778 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
779 sel
.Range(r
).End().Position())) {
787 * Asks document to find a good position and then moves out of any invisible positions.
789 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
790 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
793 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
794 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
795 if (posMoved
!= pos
.Position())
796 pos
.SetPosition(posMoved
);
797 if (vs
.ProtectionActive()) {
799 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleIndexAt(pos
.Position() - 1)].IsProtected()) {
800 while ((pos
.Position() < pdoc
->Length()) &&
801 (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position())].IsProtected()))
804 } else if (moveDir
< 0) {
805 if (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position())].IsProtected()) {
806 while ((pos
.Position() > 0) &&
807 (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position() - 1)].IsProtected()))
815 void Editor::MovedCaret(SelectionPosition newPos
, SelectionPosition previousPos
, bool ensureVisible
) {
816 const int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
818 // In case in need of wrapping to ensure DisplayFromDoc works.
819 if (currentLine
>= wrapPending
.start
)
820 WrapLines(WrapScope::wsAll
);
821 XYScrollPosition newXY
= XYScrollToMakeVisible(
822 SelectionRange(posDrag
.IsValid() ? posDrag
: newPos
), xysDefault
);
823 if (previousPos
.IsValid() && (newXY
.xOffset
== xOffset
)) {
824 // simple vertical scroll then invalidate
825 ScrollTo(newXY
.topLine
);
826 InvalidateSelection(SelectionRange(previousPos
), true);
832 ShowCaretAtCurrentPosition();
836 SetHoverIndicatorPosition(sel
.MainCaret());
837 QueueIdleWork(WorkNeeded::workUpdateUI
);
839 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
844 void Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
845 const SelectionPosition spCaret
= ((sel
.Count() == 1) && sel
.Empty()) ?
846 sel
.Last() : SelectionPosition(INVALID_POSITION
);
848 int delta
= newPos
.Position() - sel
.MainCaret();
849 newPos
= ClampPositionIntoDocument(newPos
);
850 newPos
= MovePositionOutsideChar(newPos
, delta
);
851 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
852 // Can't turn into multiple selection so clear additional selections
853 InvalidateSelection(SelectionRange(newPos
), true);
854 sel
.DropAdditionalRanges();
856 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
857 // Switching to rectangular
858 InvalidateSelection(sel
.RangeMain(), false);
859 SelectionRange rangeMain
= sel
.RangeMain();
861 sel
.Rectangular() = rangeMain
;
863 if (selt
!= Selection::noSel
) {
866 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
867 SetSelection(newPos
);
869 SetEmptySelection(newPos
);
872 MovedCaret(newPos
, spCaret
, ensureVisible
);
875 void Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
876 MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
879 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
880 pos
= ClampPositionIntoDocument(pos
);
881 pos
= MovePositionOutsideChar(pos
, moveDir
);
882 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
883 if (cs
.GetVisible(lineDoc
)) {
886 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
888 // lineDisplay is already line before fold as lines in fold use display line of line after fold
889 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
890 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
892 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
893 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
898 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
899 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
902 Point
Editor::PointMainCaret() {
903 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
907 * Choose the x position that the caret will try to stick to
908 * as it moves up and down.
910 void Editor::SetLastXChosen() {
911 Point pt
= PointMainCaret();
912 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
915 void Editor::ScrollTo(int line
, bool moveThumb
) {
916 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
917 if (topLineNew
!= topLine
) {
918 // Try to optimise small scrolls
920 int linesToMove
= topLine
- topLineNew
;
921 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
922 willRedrawAll
= !performBlit
;
924 SetTopLine(topLineNew
);
925 // Optimize by styling the view as this will invalidate any needed area
926 // which could abort the initial paint if discovered later.
927 StyleAreaBounded(GetClientRectangle(), true);
929 // Perform redraw rather than scroll if many lines would be redrawn anyway.
931 ScrollText(linesToMove
);
935 willRedrawAll
= false;
940 SetVerticalScrollPos();
945 void Editor::ScrollText(int /* linesToMove */) {
946 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
950 void Editor::HorizontalScrollTo(int xPos
) {
951 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
954 if (!Wrapping() && (xOffset
!= xPos
)) {
956 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
957 SetHorizontalScrollPos();
958 RedrawRect(GetClientRectangle());
962 void Editor::VerticalCentreCaret() {
963 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
964 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
965 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
966 if (topLine
!= newTop
) {
967 SetTopLine(newTop
> 0 ? newTop
: 0);
968 RedrawRect(GetClientRectangle());
972 // Avoid 64 bit compiler warnings.
973 // Scintilla does not support text buffers larger than 2**31
974 static int istrlen(const char *s
) {
975 return static_cast<int>(s
? strlen(s
) : 0);
978 void Editor::MoveSelectedLines(int lineDelta
) {
980 // if selection doesn't start at the beginning of the line, set the new start
981 int selectionStart
= SelectionStart().Position();
982 int startLine
= pdoc
->LineFromPosition(selectionStart
);
983 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
984 selectionStart
= beginningOfStartLine
;
986 // if selection doesn't end at the beginning of a line greater than that of the start,
987 // then set it at the beginning of the next one
988 int selectionEnd
= SelectionEnd().Position();
989 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
990 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
991 bool appendEol
= false;
992 if (selectionEnd
> beginningOfEndLine
993 || selectionStart
== selectionEnd
) {
994 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
995 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
998 // if there's nowhere for the selection to move
999 // (i.e. at the beginning going up or at the end going down),
1000 // stop it right there!
1001 if ((selectionStart
== 0 && lineDelta
< 0)
1002 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
1003 || selectionStart
== selectionEnd
) {
1009 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
1010 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
1012 selectionEnd
= CurrentPosition();
1014 SetSelection(selectionStart
, selectionEnd
);
1016 SelectionText selectedText
;
1017 CopySelectionRange(&selectedText
);
1019 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
1020 Point currentLocation
= LocationFromPosition(CurrentPosition());
1021 int currentLine
= LineFromLocation(currentLocation
);
1024 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
1027 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1028 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
1029 pdoc
->InsertString(pdoc
->Length(), eol
, istrlen(eol
));
1030 GoToLine(currentLine
+ lineDelta
);
1032 selectionLength
= pdoc
->InsertString(CurrentPosition(), selectedText
.Data(), selectionLength
);
1034 const int lengthInserted
= pdoc
->InsertString(CurrentPosition() + selectionLength
, eol
, istrlen(eol
));
1035 selectionLength
+= lengthInserted
;
1037 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
1040 void Editor::MoveSelectedLinesUp() {
1041 MoveSelectedLines(-1);
1044 void Editor::MoveSelectedLinesDown() {
1045 MoveSelectedLines(1);
1048 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1049 PRectangle rcClient
= GetTextRectangle();
1050 Point pt
= PointMainCaret();
1051 if (pt
.y
< rcClient
.top
) {
1052 MovePositionTo(SPositionFromLocation(
1053 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
)),
1054 false, false, UserVirtualSpace()),
1055 Selection::noSel
, ensureVisible
);
1056 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1057 int yOfLastLineFullyDisplayed
= static_cast<int>(rcClient
.top
) + (LinesOnScreen() - 1) * vs
.lineHeight
;
1058 MovePositionTo(SPositionFromLocation(
1059 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
) + yOfLastLineFullyDisplayed
),
1060 false, false, UserVirtualSpace()),
1061 Selection::noSel
, ensureVisible
);
1065 int Editor::DisplayFromPosition(int pos
) {
1066 AutoSurface
surface(this);
1067 return view
.DisplayFromPosition(surface
, *this, pos
, vs
);
1071 * Ensure the caret is reasonably visible in context.
1073 Caret policy in SciTE
1075 If slop is set, we can define a slop value.
1076 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1077 This zone is defined as a number of pixels near the vertical margins,
1078 and as a number of lines near the horizontal margins.
1079 By keeping the caret away from the edges, it is seen within its context,
1080 so it is likely that the identifier that the caret is on can be completely seen,
1081 and that the current line is seen with some of the lines following it which are
1082 often dependent on that line.
1084 If strict is set, the policy is enforced... strictly.
1085 The caret is centred on the display if slop is not set,
1086 and cannot go in the UZ if slop is set.
1088 If jumps is set, the display is moved more energetically
1089 so the caret can move in the same direction longer before the policy is applied again.
1090 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1092 If even is not set, instead of having symmetrical UZs,
1093 the left and bottom UZs are extended up to right and top UZs respectively.
1094 This way, we favour the displaying of useful information: the beginning of lines,
1095 where most code reside, and the lines after the caret, eg. the body of a function.
1098 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1099 | | | | | visibility or going into the UZ) display is...
1100 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1101 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1102 0 | 0 | 0 | 1 | Yes | moved by one position
1103 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1104 0 | 0 | 1 | 1 | Yes | centred on the caret
1105 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1106 0 | 1 | - | 1 | No, caret is always centred | -
1107 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1108 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1109 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1110 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1111 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1112 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1113 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1116 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const SelectionRange
&range
, const XYScrollOptions options
) {
1117 PRectangle rcClient
= GetTextRectangle();
1118 Point pt
= LocationFromPosition(range
.caret
);
1119 Point ptAnchor
= LocationFromPosition(range
.anchor
);
1120 const Point ptOrigin
= GetVisibleOriginInMain();
1123 ptAnchor
.x
+= ptOrigin
.x
;
1124 ptAnchor
.y
+= ptOrigin
.y
;
1125 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1127 XYScrollPosition
newXY(xOffset
, topLine
);
1128 if (rcClient
.Empty()) {
1132 // Vertical positioning
1133 if ((options
& xysVertical
) && (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1134 const int lineCaret
= DisplayFromPosition(range
.caret
.Position());
1135 const int linesOnScreen
= LinesOnScreen();
1136 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1137 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1138 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1139 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1140 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1142 // It should be possible to scroll the window to show the caret,
1143 // but this fails to remove the caret on GTK+
1144 if (bSlop
) { // A margin is defined
1147 int yMarginT
, yMarginB
;
1148 if (!(options
& xysUseMargin
)) {
1149 // In drag mode, avoid moves
1150 // otherwise, a double click will select several lines.
1151 yMarginT
= yMarginB
= 0;
1153 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1154 // a maximum of slightly less than half the heigth of the text area.
1155 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1157 yMarginB
= yMarginT
;
1159 yMarginB
= linesOnScreen
- yMarginT
- 1;
1165 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1169 yMoveB
= linesOnScreen
- yMoveT
- 1;
1171 if (lineCaret
< topLine
+ yMarginT
) {
1172 // Caret goes too high
1173 newXY
.topLine
= lineCaret
- yMoveT
;
1174 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1175 // Caret goes too low
1176 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1178 } else { // Not strict
1179 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1180 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1184 yMoveB
= linesOnScreen
- yMoveT
- 1;
1186 if (lineCaret
< topLine
) {
1187 // Caret goes too high
1188 newXY
.topLine
= lineCaret
- yMoveT
;
1189 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1190 // Caret goes too low
1191 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1195 if (!bStrict
&& !bJump
) {
1197 if (lineCaret
< topLine
) {
1198 // Caret goes too high
1199 newXY
.topLine
= lineCaret
;
1200 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1201 // Caret goes too low
1203 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1205 newXY
.topLine
= lineCaret
;
1208 } else { // Strict or going out of display
1210 // Always center caret
1211 newXY
.topLine
= lineCaret
- halfScreen
;
1213 // Always put caret on top of display
1214 newXY
.topLine
= lineCaret
;
1218 if (!(range
.caret
== range
.anchor
)) {
1219 const int lineAnchor
= DisplayFromPosition(range
.anchor
.Position());
1220 if (lineAnchor
< lineCaret
) {
1221 // Shift up to show anchor or as much of range as possible
1222 newXY
.topLine
= std::min(newXY
.topLine
, lineAnchor
);
1223 newXY
.topLine
= std::max(newXY
.topLine
, lineCaret
- LinesOnScreen());
1225 // Shift down to show anchor or as much of range as possible
1226 newXY
.topLine
= std::max(newXY
.topLine
, lineAnchor
- LinesOnScreen());
1227 newXY
.topLine
= std::min(newXY
.topLine
, lineCaret
);
1230 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1233 // Horizontal positioning
1234 if ((options
& xysHorizontal
) && !Wrapping()) {
1235 const int halfScreen
= Platform::Maximum(static_cast<int>(rcClient
.Width()) - 4, 4) / 2;
1236 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1237 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1238 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1239 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1241 if (bSlop
) { // A margin is defined
1244 int xMarginL
, xMarginR
;
1245 if (!(options
& xysUseMargin
)) {
1246 // In drag mode, avoid moves unless very near of the margin
1247 // otherwise, a simple click will select text.
1248 xMarginL
= xMarginR
= 2;
1250 // xMargin must equal to caretXSlop, with a minimum of 2 and
1251 // a maximum of slightly less than half the width of the text area.
1252 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1254 xMarginL
= xMarginR
;
1256 xMarginL
= static_cast<int>(rcClient
.Width()) - xMarginR
- 4;
1259 if (bJump
&& bEven
) {
1260 // Jump is used only in even mode
1261 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1263 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1265 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1266 // Caret is on the left of the display
1267 if (bJump
&& bEven
) {
1268 newXY
.xOffset
-= xMoveL
;
1270 // Move just enough to allow to display the caret
1271 newXY
.xOffset
-= static_cast<int>((rcClient
.left
+ xMarginL
) - pt
.x
);
1273 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1274 // Caret is on the right of the display
1275 if (bJump
&& bEven
) {
1276 newXY
.xOffset
+= xMoveR
;
1278 // Move just enough to allow to display the caret
1279 newXY
.xOffset
+= static_cast<int>(pt
.x
- (rcClient
.right
- xMarginR
) + 1);
1282 } else { // Not strict
1283 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1284 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1288 xMoveL
= static_cast<int>(rcClient
.Width()) - xMoveR
- 4;
1290 if (pt
.x
< rcClient
.left
) {
1291 // Caret is on the left of the display
1292 newXY
.xOffset
-= xMoveL
;
1293 } else if (pt
.x
>= rcClient
.right
) {
1294 // Caret is on the right of the display
1295 newXY
.xOffset
+= xMoveR
;
1300 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1301 // Strict or going out of display
1304 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.left
- halfScreen
);
1306 // Put caret on right
1307 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
+ 1);
1310 // Move just enough to allow to display the caret
1311 if (pt
.x
< rcClient
.left
) {
1312 // Caret is on the left of the display
1314 newXY
.xOffset
-= static_cast<int>(rcClient
.left
- pt
.x
);
1316 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1318 } else if (pt
.x
>= rcClient
.right
) {
1319 // Caret is on the right of the display
1320 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1324 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1325 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1326 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 2;
1327 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1328 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 2;
1329 if ((vs
.caretStyle
== CARETSTYLE_BLOCK
) || view
.imeCaretBlockOverride
) {
1330 // Ensure we can see a good portion of the block caret
1331 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1334 if (!(range
.caret
== range
.anchor
)) {
1335 if (ptAnchor
.x
< pt
.x
) {
1336 // Shift to left to show anchor or as much of range as possible
1337 int maxOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.left
) - 1;
1338 int minOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 1;
1339 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1340 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1342 // Shift to right to show anchor or as much of range as possible
1343 int minOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.right
) + 1;
1344 int maxOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 1;
1345 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1346 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1349 if (newXY
.xOffset
< 0) {
1357 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1358 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1359 if (newXY
.topLine
!= topLine
) {
1360 SetTopLine(newXY
.topLine
);
1361 SetVerticalScrollPos();
1363 if (newXY
.xOffset
!= xOffset
) {
1364 xOffset
= newXY
.xOffset
;
1365 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1366 if (newXY
.xOffset
> 0) {
1367 PRectangle rcText
= GetTextRectangle();
1368 if (horizontalScrollBarVisible
&&
1369 rcText
.Width() + xOffset
> scrollWidth
) {
1370 scrollWidth
= xOffset
+ static_cast<int>(rcText
.Width());
1374 SetHorizontalScrollPos();
1377 UpdateSystemCaret();
1381 void Editor::ScrollRange(SelectionRange range
) {
1382 SetXYScroll(XYScrollToMakeVisible(range
, xysDefault
));
1385 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1386 SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
),
1387 static_cast<XYScrollOptions
>((useMargin
?xysUseMargin
:0)|(vert
?xysVertical
:0)|(horiz
?xysHorizontal
:0))));
1390 void Editor::ShowCaretAtCurrentPosition() {
1392 caret
.active
= true;
1394 if (FineTickerAvailable()) {
1395 FineTickerCancel(tickCaret
);
1396 if (caret
.period
> 0)
1397 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1402 caret
.active
= false;
1404 if (FineTickerAvailable()) {
1405 FineTickerCancel(tickCaret
);
1411 void Editor::DropCaret() {
1412 caret
.active
= false;
1413 if (FineTickerAvailable()) {
1414 FineTickerCancel(tickCaret
);
1419 void Editor::CaretSetPeriod(int period
) {
1420 if (caret
.period
!= period
) {
1421 caret
.period
= period
;
1423 if (FineTickerAvailable()) {
1424 FineTickerCancel(tickCaret
);
1425 if ((caret
.active
) && (caret
.period
> 0))
1426 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1432 void Editor::InvalidateCaret() {
1433 if (posDrag
.IsValid()) {
1434 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1436 for (size_t r
=0; r
<sel
.Count(); r
++) {
1437 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1440 UpdateSystemCaret();
1443 void Editor::NotifyCaretMove() {
1446 void Editor::UpdateSystemCaret() {
1449 bool Editor::Wrapping() const {
1450 return vs
.wrapState
!= eWrapNone
;
1453 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1454 //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd);
1455 if (wrapPending
.AddRange(docLineStart
, docLineEnd
)) {
1456 view
.llc
.Invalidate(LineLayout::llPositions
);
1458 // Wrap lines during idle.
1459 if (Wrapping() && wrapPending
.NeedsWrap()) {
1464 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1465 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(lineToWrap
, *this));
1466 int linesWrapped
= 1;
1468 view
.LayoutLine(*this, lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1469 linesWrapped
= ll
->lines
;
1471 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1472 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1475 // Perform wrapping for a subset of the lines needing wrapping.
1476 // wsAll: wrap all lines which need wrapping in this single call
1477 // wsVisible: wrap currently visible lines
1478 // wsIdle: wrap one page + 100 lines
1479 // Return true if wrapping occurred.
1480 bool Editor::WrapLines(WrapScope ws
) {
1481 int goodTopLine
= topLine
;
1482 bool wrapOccurred
= false;
1484 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1485 wrapWidth
= LineLayout::wrapWidthInfinite
;
1486 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1487 cs
.SetHeight(lineDoc
, 1 +
1488 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1490 wrapOccurred
= true;
1492 wrapPending
.Reset();
1494 } else if (wrapPending
.NeedsWrap()) {
1495 wrapPending
.start
= std::min(wrapPending
.start
, pdoc
->LinesTotal());
1496 if (!SetIdle(true)) {
1497 // Idle processing not supported so full wrap required.
1498 ws
= WrapScope::wsAll
;
1500 // Decide where to start wrapping
1501 int lineToWrap
= wrapPending
.start
;
1502 int lineToWrapEnd
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1503 const int lineDocTop
= cs
.DocFromDisplay(topLine
);
1504 const int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1505 if (ws
== WrapScope::wsVisible
) {
1506 lineToWrap
= Platform::Clamp(lineDocTop
-5, wrapPending
.start
, pdoc
->LinesTotal());
1507 // Priority wrap to just after visible area.
1508 // Since wrapping could reduce display lines, treat each
1509 // as taking only one display line.
1510 lineToWrapEnd
= lineDocTop
;
1511 int lines
= LinesOnScreen() + 1;
1512 while ((lineToWrapEnd
< cs
.LinesInDoc()) && (lines
>0)) {
1513 if (cs
.GetVisible(lineToWrapEnd
))
1517 // .. and if the paint window is outside pending wraps
1518 if ((lineToWrap
> wrapPending
.end
) || (lineToWrapEnd
< wrapPending
.start
)) {
1519 // Currently visible text does not need wrapping
1522 } else if (ws
== WrapScope::wsIdle
) {
1523 lineToWrapEnd
= lineToWrap
+ LinesOnScreen() + 100;
1525 const int lineEndNeedWrap
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1526 lineToWrapEnd
= std::min(lineToWrapEnd
, lineEndNeedWrap
);
1528 // Ensure all lines being wrapped are styled.
1529 pdoc
->EnsureStyledTo(pdoc
->LineStart(lineToWrapEnd
));
1531 if (lineToWrap
< lineToWrapEnd
) {
1533 PRectangle rcTextArea
= GetClientRectangle();
1534 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1535 rcTextArea
.right
-= vs
.rightMarginWidth
;
1536 wrapWidth
= static_cast<int>(rcTextArea
.Width());
1538 AutoSurface
surface(this);
1540 //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd);
1542 while (lineToWrap
< lineToWrapEnd
) {
1543 if (WrapOneLine(surface
, lineToWrap
)) {
1544 wrapOccurred
= true;
1546 wrapPending
.Wrapped(lineToWrap
);
1550 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
) + std::min(subLineTop
, cs
.GetHeight(lineDocTop
)-1);
1554 // If wrapping is done, bring it to resting position
1555 if (wrapPending
.start
>= lineEndNeedWrap
) {
1556 wrapPending
.Reset();
1562 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1563 SetVerticalScrollPos();
1566 return wrapOccurred
;
1569 void Editor::LinesJoin() {
1570 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1572 bool prevNonWS
= true;
1573 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1574 if (pdoc
->IsPositionInLineEnd(pos
)) {
1575 targetEnd
-= pdoc
->LenChar(pos
);
1578 // Ensure at least one space separating previous lines
1579 const int lengthInserted
= pdoc
->InsertString(pos
, " ", 1);
1580 targetEnd
+= lengthInserted
;
1583 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1589 const char *Editor::StringFromEOLMode(int eolMode
) {
1590 if (eolMode
== SC_EOL_CRLF
) {
1592 } else if (eolMode
== SC_EOL_CR
) {
1599 void Editor::LinesSplit(int pixelWidth
) {
1600 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1601 if (pixelWidth
== 0) {
1602 PRectangle rcText
= GetTextRectangle();
1603 pixelWidth
= static_cast<int>(rcText
.Width());
1605 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1606 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1607 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1609 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1610 AutoSurface
surface(this);
1611 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
1612 if (surface
&& ll
) {
1613 unsigned int posLineStart
= pdoc
->LineStart(line
);
1614 view
.LayoutLine(*this, line
, surface
, vs
, ll
, pixelWidth
);
1615 int lengthInsertedTotal
= 0;
1616 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1617 const int lengthInserted
= pdoc
->InsertString(
1618 static_cast<int>(posLineStart
+ lengthInsertedTotal
+
1619 ll
->LineStart(subLine
)),
1621 targetEnd
+= lengthInserted
;
1622 lengthInsertedTotal
+= lengthInserted
;
1625 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1630 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1631 if (vs
.fixedColumnWidth
== 0)
1636 RefreshPixMaps(surfWindow
);
1638 // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished
1639 // at this point. The Initialised call checks for this case and sets the status
1640 // to be bad which avoids crashes in following calls.
1641 if (!surfWindow
->Initialised()) {
1645 PRectangle rcMargin
= GetClientRectangle();
1646 Point ptOrigin
= GetVisibleOriginInMain();
1647 rcMargin
.Move(0, -ptOrigin
.y
);
1649 rcMargin
.right
= static_cast<XYPOSITION
>(vs
.fixedColumnWidth
);
1651 if (!rc
.Intersects(rcMargin
))
1655 if (view
.bufferedDraw
) {
1656 surface
= marginView
.pixmapSelMargin
;
1658 surface
= surfWindow
;
1661 // Clip vertically to paint area to avoid drawing line numbers
1662 if (rcMargin
.bottom
> rc
.bottom
)
1663 rcMargin
.bottom
= rc
.bottom
;
1664 if (rcMargin
.top
< rc
.top
)
1665 rcMargin
.top
= rc
.top
;
1667 marginView
.PaintMargin(surface
, topLine
, rc
, rcMargin
, *this, vs
);
1669 if (view
.bufferedDraw
) {
1670 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *marginView
.pixmapSelMargin
);
1674 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
1675 view
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1676 marginView
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1677 if (view
.bufferedDraw
) {
1678 PRectangle rcClient
= GetClientRectangle();
1679 if (!view
.pixmapLine
->Initialised()) {
1681 view
.pixmapLine
->InitPixMap(static_cast<int>(rcClient
.Width()), vs
.lineHeight
,
1682 surfaceWindow
, wMain
.GetID());
1684 if (!marginView
.pixmapSelMargin
->Initialised()) {
1685 marginView
.pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1686 static_cast<int>(rcClient
.Height()), surfaceWindow
, wMain
.GetID());
1691 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1692 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1693 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1697 if (paintState
== paintAbandoned
)
1698 return; // Scroll bars may have changed so need redraw
1699 RefreshPixMaps(surfaceWindow
);
1701 paintAbandonedByStyling
= false;
1703 StyleAreaBounded(rcArea
, false);
1705 PRectangle rcClient
= GetClientRectangle();
1706 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1707 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1709 if (NotifyUpdateUI()) {
1711 RefreshPixMaps(surfaceWindow
);
1714 // Wrap the visible lines if needed.
1715 if (WrapLines(WrapScope::wsVisible
)) {
1716 // The wrapping process has changed the height of some lines so
1717 // abandon this paint for a complete repaint.
1718 if (AbandonPaint()) {
1721 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
1723 PLATFORM_ASSERT(marginView
.pixmapSelPattern
->Initialised());
1725 if (!view
.bufferedDraw
)
1726 surfaceWindow
->SetClip(rcArea
);
1728 if (paintState
!= paintAbandoned
) {
1729 if (vs
.marginInside
) {
1730 PaintSelMargin(surfaceWindow
, rcArea
);
1731 PRectangle rcRightMargin
= rcClient
;
1732 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1733 if (rcArea
.Intersects(rcRightMargin
)) {
1734 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1736 } else { // Else separate view so separate paint event but leftMargin included to allow overlap
1737 PRectangle rcLeftMargin
= rcArea
;
1738 rcLeftMargin
.left
= 0;
1739 rcLeftMargin
.right
= rcLeftMargin
.left
+ vs
.leftMarginWidth
;
1740 if (rcArea
.Intersects(rcLeftMargin
)) {
1741 surfaceWindow
->FillRectangle(rcLeftMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1746 if (paintState
== paintAbandoned
) {
1747 // Either styling or NotifyUpdateUI noticed that painting is needed
1748 // outside the current painting rectangle
1749 //Platform::DebugPrintf("Abandoning paint\n");
1751 if (paintAbandonedByStyling
) {
1752 // Styling has spilled over a line end, such as occurs by starting a multiline
1753 // comment. The width of subsequent text may have changed, so rewrap.
1754 NeedWrapping(cs
.DocFromDisplay(topLine
));
1760 view
.PaintText(surfaceWindow
, *this, rcArea
, rcClient
, vs
);
1762 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
1763 if (FineTickerAvailable()) {
1764 scrollWidth
= view
.lineWidthMaxSeen
;
1765 if (!FineTickerRunning(tickWiden
)) {
1766 FineTickerStart(tickWiden
, 50, 5);
1774 // This is mostly copied from the Paint method but with some things omitted
1775 // such as the margin markers, line numbers, selection and caret
1776 // Should be merged back into a combined Draw method.
1777 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
1781 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
1784 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
1785 if (!surfaceMeasure
) {
1788 return view
.FormatRange(draw
, pfr
, surface
, surfaceMeasure
, *this, vs
);
1791 int Editor::TextWidth(int style
, const char *text
) {
1793 AutoSurface
surface(this);
1795 return static_cast<int>(surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
)));
1801 // Empty method is overridden on GTK+ to show / hide scrollbars
1802 void Editor::ReconfigureScrollBars() {}
1804 void Editor::SetScrollBars() {
1807 int nMax
= MaxScrollPos();
1808 int nPage
= LinesOnScreen();
1809 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
1814 // TODO: ensure always showing as many lines as possible
1815 // May not be, if, for example, window made larger
1816 if (topLine
> MaxScrollPos()) {
1817 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1818 SetVerticalScrollPos();
1822 if (!AbandonPaint())
1825 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1828 void Editor::ChangeSize() {
1829 DropGraphics(false);
1832 PRectangle rcTextArea
= GetClientRectangle();
1833 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1834 rcTextArea
.right
-= vs
.rightMarginWidth
;
1835 if (wrapWidth
!= rcTextArea
.Width()) {
1842 int Editor::RealizeVirtualSpace(int position
, unsigned int virtualSpace
) {
1843 if (virtualSpace
> 0) {
1844 const int line
= pdoc
->LineFromPosition(position
);
1845 const int indent
= pdoc
->GetLineIndentPosition(line
);
1846 if (indent
== position
) {
1847 return pdoc
->SetLineIndentation(line
, pdoc
->GetLineIndentation(line
) + virtualSpace
);
1849 std::string
spaceText(virtualSpace
, ' ');
1850 const int lengthInserted
= pdoc
->InsertString(position
, spaceText
.c_str(), virtualSpace
);
1851 position
+= lengthInserted
;
1857 SelectionPosition
Editor::RealizeVirtualSpace(const SelectionPosition
&position
) {
1858 // Return the new position with no virtual space
1859 return SelectionPosition(RealizeVirtualSpace(position
.Position(), position
.VirtualSpace()));
1862 void Editor::AddChar(char ch
) {
1869 void Editor::FilterSelections() {
1870 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
1871 InvalidateWholeSelection();
1872 sel
.DropAdditionalRanges();
1876 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
1877 void Editor::AddCharUTF(const char *s
, unsigned int len
, bool treatAsDBCS
) {
1880 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1882 // Vector elements point into selection in order to change selection.
1883 std::vector
<SelectionRange
*> selPtrs
;
1884 for (size_t r
= 0; r
< sel
.Count(); r
++) {
1885 selPtrs
.push_back(&sel
.Range(r
));
1887 // Order selections by position in document.
1888 std::sort(selPtrs
.begin(), selPtrs
.end(),
1889 [](const SelectionRange
*a
, const SelectionRange
*b
) {return *a
< *b
;});
1891 // Loop in reverse to avoid disturbing positions of selections yet to be processed.
1892 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
1893 rit
!= selPtrs
.rend(); ++rit
) {
1894 SelectionRange
*currentSel
= *rit
;
1895 if (!RangeContainsProtected(currentSel
->Start().Position(),
1896 currentSel
->End().Position())) {
1897 int positionInsert
= currentSel
->Start().Position();
1898 if (!currentSel
->Empty()) {
1899 if (currentSel
->Length()) {
1900 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
1901 currentSel
->ClearVirtualSpace();
1903 // Range is all virtual so collapse to start of virtual space
1904 currentSel
->MinimizeVirtualSpace();
1906 } else if (inOverstrike
) {
1907 if (positionInsert
< pdoc
->Length()) {
1908 if (!pdoc
->IsPositionInLineEnd(positionInsert
)) {
1909 pdoc
->DelChar(positionInsert
);
1910 currentSel
->ClearVirtualSpace();
1914 positionInsert
= RealizeVirtualSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
1915 const int lengthInserted
= pdoc
->InsertString(positionInsert
, s
, len
);
1916 if (lengthInserted
> 0) {
1917 currentSel
->caret
.SetPosition(positionInsert
+ lengthInserted
);
1918 currentSel
->anchor
.SetPosition(positionInsert
+ lengthInserted
);
1920 currentSel
->ClearVirtualSpace();
1921 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1923 AutoSurface
surface(this);
1925 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
1927 SetVerticalScrollPos();
1938 ThinRectangularRange();
1939 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1940 EnsureCaretVisible();
1941 // Avoid blinking during rapid typing:
1942 ShowCaretAtCurrentPosition();
1943 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
1944 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
1949 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
1950 static_cast<unsigned char>(s
[1]));
1951 } else if (len
> 0) {
1952 int byte
= static_cast<unsigned char>(s
[0]);
1953 if ((byte
< 0xC0) || (1 == len
)) {
1954 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1955 // characters when not in UTF-8 mode.
1956 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1957 // characters representing themselves.
1959 unsigned int utf32
[1] = { 0 };
1960 UTF32FromUTF8(s
, len
, utf32
, ELEMENTS(utf32
));
1966 if (recordingMacro
) {
1967 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
1971 void Editor::ClearBeforeTentativeStart() {
1972 // Make positions for the first composition string.
1974 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1975 for (size_t r
= 0; r
<sel
.Count(); r
++) {
1976 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1977 sel
.Range(r
).End().Position())) {
1978 int positionInsert
= sel
.Range(r
).Start().Position();
1979 if (!sel
.Range(r
).Empty()) {
1980 if (sel
.Range(r
).Length()) {
1981 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1982 sel
.Range(r
).ClearVirtualSpace();
1984 // Range is all virtual so collapse to start of virtual space
1985 sel
.Range(r
).MinimizeVirtualSpace();
1988 RealizeVirtualSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
1989 sel
.Range(r
).ClearVirtualSpace();
1994 void Editor::InsertPaste(const char *text
, int len
) {
1995 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
1996 SelectionPosition selStart
= sel
.Start();
1997 selStart
= RealizeVirtualSpace(selStart
);
1998 const int lengthInserted
= pdoc
->InsertString(selStart
.Position(), text
, len
);
1999 if (lengthInserted
> 0) {
2000 SetEmptySelection(selStart
.Position() + lengthInserted
);
2003 // SC_MULTIPASTE_EACH
2004 for (size_t r
=0; r
<sel
.Count(); r
++) {
2005 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
2006 sel
.Range(r
).End().Position())) {
2007 int positionInsert
= sel
.Range(r
).Start().Position();
2008 if (!sel
.Range(r
).Empty()) {
2009 if (sel
.Range(r
).Length()) {
2010 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
2011 sel
.Range(r
).ClearVirtualSpace();
2013 // Range is all virtual so collapse to start of virtual space
2014 sel
.Range(r
).MinimizeVirtualSpace();
2017 positionInsert
= RealizeVirtualSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
2018 const int lengthInserted
= pdoc
->InsertString(positionInsert
, text
, len
);
2019 if (lengthInserted
> 0) {
2020 sel
.Range(r
).caret
.SetPosition(positionInsert
+ lengthInserted
);
2021 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ lengthInserted
);
2023 sel
.Range(r
).ClearVirtualSpace();
2029 void Editor::InsertPasteShape(const char *text
, int len
, PasteShape shape
) {
2030 std::string convertedText
;
2031 if (convertPastes
) {
2032 // Convert line endings of the paste into our local line-endings mode
2033 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
2034 len
= static_cast<int>(convertedText
.length());
2035 text
= convertedText
.c_str();
2037 if (shape
== pasteRectangular
) {
2038 PasteRectangular(sel
.Start(), text
, len
);
2040 if (shape
== pasteLine
) {
2041 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
2042 int lengthInserted
= pdoc
->InsertString(insertPos
, text
, len
);
2043 // add the newline if necessary
2044 if ((len
> 0) && (text
[len
- 1] != '\n' && text
[len
- 1] != '\r')) {
2045 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
2046 int length
= static_cast<int>(strlen(endline
));
2047 lengthInserted
+= pdoc
->InsertString(insertPos
+ lengthInserted
, endline
, length
);
2049 if (sel
.MainCaret() == insertPos
) {
2050 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
2053 InsertPaste(text
, len
);
2058 void Editor::ClearSelection(bool retainMultipleSelections
) {
2059 if (!sel
.IsRectangular() && !retainMultipleSelections
)
2062 for (size_t r
=0; r
<sel
.Count(); r
++) {
2063 if (!sel
.Range(r
).Empty()) {
2064 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
2065 sel
.Range(r
).End().Position())) {
2066 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
2067 sel
.Range(r
).Length());
2068 sel
.Range(r
) = SelectionRange(sel
.Range(r
).Start());
2072 ThinRectangularRange();
2073 sel
.RemoveDuplicates();
2075 SetHoverIndicatorPosition(sel
.MainCaret());
2078 void Editor::ClearAll() {
2081 if (0 != pdoc
->Length()) {
2082 pdoc
->DeleteChars(0, pdoc
->Length());
2084 if (!pdoc
->IsReadOnly()) {
2086 pdoc
->AnnotationClearAll();
2087 pdoc
->MarginClearAll();
2091 view
.ClearAllTabstops();
2095 SetVerticalScrollPos();
2096 InvalidateStyleRedraw();
2099 void Editor::ClearDocumentStyle() {
2100 Decoration
*deco
= pdoc
->decorations
.root
;
2102 // Save next in case deco deleted
2103 Decoration
*decoNext
= deco
->next
;
2104 if (deco
->indicator
< INDIC_CONTAINER
) {
2105 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
2106 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
2110 pdoc
->StartStyling(0, '\377');
2111 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2113 SetAnnotationHeights(0, pdoc
->LinesTotal());
2114 pdoc
->ClearLevels();
2117 void Editor::CopyAllowLine() {
2118 SelectionText selectedText
;
2119 CopySelectionRange(&selectedText
, true);
2120 CopyToClipboard(selectedText
);
2123 void Editor::Cut() {
2124 pdoc
->CheckReadOnly();
2125 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2131 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
2132 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2136 sel
.RangeMain() = SelectionRange(pos
);
2137 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2139 sel
.RangeMain().caret
= RealizeVirtualSpace(sel
.RangeMain().caret
);
2140 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
2141 bool prevCr
= false;
2142 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
2144 for (int i
= 0; i
< len
; i
++) {
2145 if (IsEOLChar(ptr
[i
])) {
2146 if ((ptr
[i
] == '\r') || (!prevCr
))
2148 if (line
>= pdoc
->LinesTotal()) {
2149 if (pdoc
->eolMode
!= SC_EOL_LF
)
2150 pdoc
->InsertString(pdoc
->Length(), "\r", 1);
2151 if (pdoc
->eolMode
!= SC_EOL_CR
)
2152 pdoc
->InsertString(pdoc
->Length(), "\n", 1);
2154 // Pad the end of lines with spaces if required
2155 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
2156 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
2157 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
2159 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), " ", 1);
2160 sel
.RangeMain().caret
.Add(lengthInserted
);
2163 prevCr
= ptr
[i
] == '\r';
2165 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
2166 sel
.RangeMain().caret
.Add(lengthInserted
);
2170 SetEmptySelection(pos
);
2173 bool Editor::CanPaste() {
2174 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
2177 void Editor::Clear() {
2178 // If multiple selections, don't delete EOLS
2180 bool singleVirtual
= false;
2181 if ((sel
.Count() == 1) &&
2182 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
2183 sel
.RangeMain().Start().VirtualSpace()) {
2184 singleVirtual
= true;
2186 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
2187 for (size_t r
=0; r
<sel
.Count(); r
++) {
2188 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
2189 if (sel
.Range(r
).Start().VirtualSpace()) {
2190 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
2191 sel
.Range(r
) = SelectionRange(RealizeVirtualSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
2193 sel
.Range(r
) = SelectionRange(RealizeVirtualSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
2195 if ((sel
.Count() == 1) || !pdoc
->IsPositionInLineEnd(sel
.Range(r
).caret
.Position())) {
2196 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
2197 sel
.Range(r
).ClearVirtualSpace();
2198 } // else multiple selection so don't eat line ends
2200 sel
.Range(r
).ClearVirtualSpace();
2206 sel
.RemoveDuplicates();
2207 ShowCaretAtCurrentPosition(); // Avoid blinking
2210 void Editor::SelectAll() {
2212 SetSelection(0, pdoc
->Length());
2216 void Editor::Undo() {
2217 if (pdoc
->CanUndo()) {
2219 int newPos
= pdoc
->Undo();
2221 SetEmptySelection(newPos
);
2222 EnsureCaretVisible();
2226 void Editor::Redo() {
2227 if (pdoc
->CanRedo()) {
2228 int newPos
= pdoc
->Redo();
2230 SetEmptySelection(newPos
);
2231 EnsureCaretVisible();
2235 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2237 if (!sel
.IsRectangular())
2239 if (sel
.IsRectangular())
2240 allowLineStartDeletion
= false;
2241 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
2243 for (size_t r
=0; r
<sel
.Count(); r
++) {
2244 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
2245 if (sel
.Range(r
).caret
.VirtualSpace()) {
2246 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
2247 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
2249 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2250 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
2251 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2252 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
2253 UndoGroup
ugInner(pdoc
, !ug
.Needed());
2254 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2255 int indentationStep
= pdoc
->IndentSize();
2256 int indentationChange
= indentation
% indentationStep
;
2257 if (indentationChange
== 0)
2258 indentationChange
= indentationStep
;
2259 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationChange
);
2260 // SetEmptySelection
2261 sel
.Range(r
) = SelectionRange(posSelect
);
2263 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
2268 sel
.Range(r
).ClearVirtualSpace();
2271 ThinRectangularRange();
2275 sel
.RemoveDuplicates();
2276 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
2277 // Avoid blinking during rapid typing:
2278 ShowCaretAtCurrentPosition();
2281 int Editor::ModifierFlags(bool shift
, bool ctrl
, bool alt
, bool meta
, bool super
) {
2283 (shift
? SCI_SHIFT
: 0) |
2284 (ctrl
? SCI_CTRL
: 0) |
2285 (alt
? SCI_ALT
: 0) |
2286 (meta
? SCI_META
: 0) |
2287 (super
? SCI_SUPER
: 0);
2290 void Editor::NotifyFocus(bool focus
) {
2291 SCNotification scn
= {};
2292 scn
.nmhdr
.code
= focus
? SCN_FOCUSIN
: SCN_FOCUSOUT
;
2296 void Editor::SetCtrlID(int identifier
) {
2297 ctrlID
= identifier
;
2300 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2301 SCNotification scn
= {};
2302 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2303 scn
.position
= endStyleNeeded
;
2307 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2308 NotifyStyleToNeeded(endStyleNeeded
);
2311 void Editor::NotifyLexerChanged(Document
*, void *) {
2314 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
2315 errorStatus
= status
;
2318 void Editor::NotifyChar(int ch
) {
2319 SCNotification scn
= {};
2320 scn
.nmhdr
.code
= SCN_CHARADDED
;
2325 void Editor::NotifySavePoint(bool isSavePoint
) {
2326 SCNotification scn
= {};
2328 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2330 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2335 void Editor::NotifyModifyAttempt() {
2336 SCNotification scn
= {};
2337 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2341 void Editor::NotifyDoubleClick(Point pt
, int modifiers
) {
2342 SCNotification scn
= {};
2343 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2344 scn
.line
= LineFromLocation(pt
);
2345 scn
.position
= PositionFromLocation(pt
, true);
2346 scn
.modifiers
= modifiers
;
2350 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2351 NotifyDoubleClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2354 void Editor::NotifyHotSpotDoubleClicked(int position
, int modifiers
) {
2355 SCNotification scn
= {};
2356 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
2357 scn
.position
= position
;
2358 scn
.modifiers
= modifiers
;
2362 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2363 NotifyHotSpotDoubleClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2366 void Editor::NotifyHotSpotClicked(int position
, int modifiers
) {
2367 SCNotification scn
= {};
2368 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
2369 scn
.position
= position
;
2370 scn
.modifiers
= modifiers
;
2374 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2375 NotifyHotSpotClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2378 void Editor::NotifyHotSpotReleaseClick(int position
, int modifiers
) {
2379 SCNotification scn
= {};
2380 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
2381 scn
.position
= position
;
2382 scn
.modifiers
= modifiers
;
2386 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
2387 NotifyHotSpotReleaseClick(position
, ModifierFlags(shift
, ctrl
, alt
));
2390 bool Editor::NotifyUpdateUI() {
2392 SCNotification scn
= {};
2393 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2394 scn
.updated
= needUpdateUI
;
2402 void Editor::NotifyPainted() {
2403 SCNotification scn
= {};
2404 scn
.nmhdr
.code
= SCN_PAINTED
;
2408 void Editor::NotifyIndicatorClick(bool click
, int position
, int modifiers
) {
2409 int mask
= pdoc
->decorations
.AllOnFor(position
);
2410 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
2411 SCNotification scn
= {};
2412 pdoc
->decorations
.clickNotified
= click
;
2413 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
2414 scn
.modifiers
= modifiers
;
2415 scn
.position
= position
;
2420 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
2421 NotifyIndicatorClick(click
, position
, ModifierFlags(shift
, ctrl
, alt
));
2424 bool Editor::NotifyMarginClick(Point pt
, int modifiers
) {
2425 const int marginClicked
= vs
.MarginFromLocation(pt
);
2426 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2427 int position
= pdoc
->LineStart(LineFromLocation(pt
));
2428 if ((vs
.ms
[marginClicked
].mask
& SC_MASK_FOLDERS
) && (foldAutomatic
& SC_AUTOMATICFOLD_CLICK
)) {
2429 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
2430 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
2431 int lineClick
= pdoc
->LineFromPosition(position
);
2432 if (shift
&& ctrl
) {
2433 FoldAll(SC_FOLDACTION_TOGGLE
);
2435 int levelClick
= pdoc
->GetLevel(lineClick
);
2436 if (levelClick
& SC_FOLDLEVELHEADERFLAG
) {
2438 // Ensure all children visible
2439 FoldExpand(lineClick
, SC_FOLDACTION_EXPAND
, levelClick
);
2441 FoldExpand(lineClick
, SC_FOLDACTION_TOGGLE
, levelClick
);
2444 FoldLine(lineClick
, SC_FOLDACTION_TOGGLE
);
2450 SCNotification scn
= {};
2451 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2452 scn
.modifiers
= modifiers
;
2453 scn
.position
= position
;
2454 scn
.margin
= marginClicked
;
2462 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2463 return NotifyMarginClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2466 bool Editor::NotifyMarginRightClick(Point pt
, int modifiers
) {
2467 int marginRightClicked
= vs
.MarginFromLocation(pt
);
2468 if ((marginRightClicked
>= 0) && vs
.ms
[marginRightClicked
].sensitive
) {
2469 int position
= pdoc
->LineStart(LineFromLocation(pt
));
2470 SCNotification scn
= {};
2471 scn
.nmhdr
.code
= SCN_MARGINRIGHTCLICK
;
2472 scn
.modifiers
= modifiers
;
2473 scn
.position
= position
;
2474 scn
.margin
= marginRightClicked
;
2482 void Editor::NotifyNeedShown(int pos
, int len
) {
2483 SCNotification scn
= {};
2484 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2490 void Editor::NotifyDwelling(Point pt
, bool state
) {
2491 SCNotification scn
= {};
2492 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2493 scn
.position
= PositionFromLocation(pt
, true);
2494 scn
.x
= static_cast<int>(pt
.x
+ vs
.ExternalMarginWidth());
2495 scn
.y
= static_cast<int>(pt
.y
);
2499 void Editor::NotifyZoom() {
2500 SCNotification scn
= {};
2501 scn
.nmhdr
.code
= SCN_ZOOM
;
2505 // Notifications from document
2506 void Editor::NotifyModifyAttempt(Document
*, void *) {
2507 //Platform::DebugPrintf("** Modify Attempt\n");
2508 NotifyModifyAttempt();
2511 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2512 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2513 NotifySavePoint(atSavePoint
);
2516 void Editor::CheckModificationForWrap(DocModification mh
) {
2517 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
2518 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2519 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2520 int lines
= Platform::Maximum(0, mh
.linesAdded
);
2522 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
2525 // Fix up annotation heights
2526 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
2530 // Move a position so it is still after the same character as before the insertion.
2531 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2532 if (position
> startInsertion
) {
2533 return position
+ length
;
2538 // Move a position so it is still after the same character as before the deletion if that
2539 // character is still present else after the previous surviving character.
2540 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2541 if (position
> startDeletion
) {
2542 int endDeletion
= startDeletion
+ length
;
2543 if (position
> endDeletion
) {
2544 return position
- length
;
2546 return startDeletion
;
2553 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2554 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
2555 if (paintState
== painting
) {
2556 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2558 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
2559 if (paintState
== painting
) {
2560 CheckForChangeOutsidePaint(
2561 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
2563 // Could check that change is before last visible line.
2567 if (mh
.modificationType
& SC_MOD_CHANGETABSTOPS
) {
2570 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
2571 if (paintState
== painting
) {
2572 CheckForChangeOutsidePaint(
2573 Range(mh
.position
, mh
.position
+ mh
.length
));
2578 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
2579 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2580 pdoc
->IncrementStyleClock();
2582 if (paintState
== notPainting
) {
2583 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2584 // Styling performed before this view
2587 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2590 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2591 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2594 // Move selection and brace highlights
2595 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2596 sel
.MovePositions(true, mh
.position
, mh
.length
);
2597 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2598 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2599 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2600 sel
.MovePositions(false, mh
.position
, mh
.length
);
2601 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2602 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2604 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
2605 // Some lines are hidden so may need shown.
2606 const int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2607 int endNeedShown
= mh
.position
;
2608 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2609 if (pdoc
->ContainsLineEnd(mh
.text
, mh
.length
) && (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
2610 endNeedShown
= pdoc
->LineStart(lineOfPos
+1);
2611 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2612 // If the deletion includes any EOL then we extend the need shown area.
2613 endNeedShown
= mh
.position
+ mh
.length
;
2614 int lineLast
= pdoc
->LineFromPosition(mh
.position
+mh
.length
);
2615 for (int line
= lineOfPos
+ 1; line
<= lineLast
; line
++) {
2616 const int lineMaxSubord
= pdoc
->GetLastChild(line
, -1, -1);
2617 if (lineLast
< lineMaxSubord
) {
2618 lineLast
= lineMaxSubord
;
2619 endNeedShown
= pdoc
->LineEnd(lineLast
);
2623 NeedShown(mh
.position
, endNeedShown
- mh
.position
);
2625 if (mh
.linesAdded
!= 0) {
2626 // Update contraction state for inserted and removed lines
2627 // lineOfPos should be calculated in context of state before modification, shouldn't it
2628 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2629 if (mh
.position
> pdoc
->LineStart(lineOfPos
))
2630 lineOfPos
++; // Affecting subsequent lines
2631 if (mh
.linesAdded
> 0) {
2632 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2634 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2636 view
.LinesAddedOrRemoved(lineOfPos
, mh
.linesAdded
);
2638 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
2639 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2640 if (vs
.annotationVisible
) {
2641 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
2645 CheckModificationForWrap(mh
);
2646 if (mh
.linesAdded
!= 0) {
2647 // Avoid scrolling of display if change before current display
2648 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
2649 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2650 if (newTop
!= topLine
) {
2652 SetVerticalScrollPos();
2656 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
2657 QueueIdleWork(WorkNeeded::workStyle
, pdoc
->Length());
2661 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
2662 QueueIdleWork(WorkNeeded::workStyle
, mh
.position
+ mh
.length
);
2663 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2668 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
2672 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
2673 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
2674 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
2675 // Fold changes can affect the drawing of following lines so redraw whole margin
2676 RedrawSelMargin(marginView
.highlightDelimiter
.isEnabled
? -1 : mh
.line
- 1, true);
2678 RedrawSelMargin(mh
.line
);
2682 if ((mh
.modificationType
& SC_MOD_CHANGEFOLD
) && (foldAutomatic
& SC_AUTOMATICFOLD_CHANGE
)) {
2683 FoldChanged(mh
.line
, mh
.foldLevelNow
, mh
.foldLevelPrev
);
2686 // NOW pay the piper WRT "deferred" visual updates
2687 if (IsLastStep(mh
)) {
2692 // If client wants to see this modification
2693 if (mh
.modificationType
& modEventMask
) {
2694 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
2695 // Real modification made to text of document.
2696 NotifyChange(); // Send EN_CHANGE
2699 SCNotification scn
= {};
2700 scn
.nmhdr
.code
= SCN_MODIFIED
;
2701 scn
.position
= mh
.position
;
2702 scn
.modificationType
= mh
.modificationType
;
2704 scn
.length
= mh
.length
;
2705 scn
.linesAdded
= mh
.linesAdded
;
2707 scn
.foldLevelNow
= mh
.foldLevelNow
;
2708 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2709 scn
.token
= mh
.token
;
2710 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
2715 void Editor::NotifyDeleted(Document
*, void *) {
2719 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2721 // Enumerates all macroable messages
2727 case SCI_REPLACESEL
:
2729 case SCI_INSERTTEXT
:
2730 case SCI_APPENDTEXT
:
2735 case SCI_SEARCHANCHOR
:
2736 case SCI_SEARCHNEXT
:
2737 case SCI_SEARCHPREV
:
2739 case SCI_LINEDOWNEXTEND
:
2741 case SCI_PARADOWNEXTEND
:
2743 case SCI_LINEUPEXTEND
:
2745 case SCI_PARAUPEXTEND
:
2747 case SCI_CHARLEFTEXTEND
:
2749 case SCI_CHARRIGHTEXTEND
:
2751 case SCI_WORDLEFTEXTEND
:
2753 case SCI_WORDRIGHTEXTEND
:
2754 case SCI_WORDPARTLEFT
:
2755 case SCI_WORDPARTLEFTEXTEND
:
2756 case SCI_WORDPARTRIGHT
:
2757 case SCI_WORDPARTRIGHTEXTEND
:
2758 case SCI_WORDLEFTEND
:
2759 case SCI_WORDLEFTENDEXTEND
:
2760 case SCI_WORDRIGHTEND
:
2761 case SCI_WORDRIGHTENDEXTEND
:
2763 case SCI_HOMEEXTEND
:
2765 case SCI_LINEENDEXTEND
:
2767 case SCI_HOMEWRAPEXTEND
:
2768 case SCI_LINEENDWRAP
:
2769 case SCI_LINEENDWRAPEXTEND
:
2770 case SCI_DOCUMENTSTART
:
2771 case SCI_DOCUMENTSTARTEXTEND
:
2772 case SCI_DOCUMENTEND
:
2773 case SCI_DOCUMENTENDEXTEND
:
2774 case SCI_STUTTEREDPAGEUP
:
2775 case SCI_STUTTEREDPAGEUPEXTEND
:
2776 case SCI_STUTTEREDPAGEDOWN
:
2777 case SCI_STUTTEREDPAGEDOWNEXTEND
:
2779 case SCI_PAGEUPEXTEND
:
2781 case SCI_PAGEDOWNEXTEND
:
2782 case SCI_EDITTOGGLEOVERTYPE
:
2784 case SCI_DELETEBACK
:
2789 case SCI_VCHOMEEXTEND
:
2790 case SCI_VCHOMEWRAP
:
2791 case SCI_VCHOMEWRAPEXTEND
:
2792 case SCI_VCHOMEDISPLAY
:
2793 case SCI_VCHOMEDISPLAYEXTEND
:
2794 case SCI_DELWORDLEFT
:
2795 case SCI_DELWORDRIGHT
:
2796 case SCI_DELWORDRIGHTEND
:
2797 case SCI_DELLINELEFT
:
2798 case SCI_DELLINERIGHT
:
2801 case SCI_LINEDELETE
:
2802 case SCI_LINETRANSPOSE
:
2803 case SCI_LINEDUPLICATE
:
2806 case SCI_LINESCROLLDOWN
:
2807 case SCI_LINESCROLLUP
:
2808 case SCI_DELETEBACKNOTLINE
:
2809 case SCI_HOMEDISPLAY
:
2810 case SCI_HOMEDISPLAYEXTEND
:
2811 case SCI_LINEENDDISPLAY
:
2812 case SCI_LINEENDDISPLAYEXTEND
:
2813 case SCI_SETSELECTIONMODE
:
2814 case SCI_LINEDOWNRECTEXTEND
:
2815 case SCI_LINEUPRECTEXTEND
:
2816 case SCI_CHARLEFTRECTEXTEND
:
2817 case SCI_CHARRIGHTRECTEXTEND
:
2818 case SCI_HOMERECTEXTEND
:
2819 case SCI_VCHOMERECTEXTEND
:
2820 case SCI_LINEENDRECTEXTEND
:
2821 case SCI_PAGEUPRECTEXTEND
:
2822 case SCI_PAGEDOWNRECTEXTEND
:
2823 case SCI_SELECTIONDUPLICATE
:
2824 case SCI_COPYALLOWLINE
:
2825 case SCI_VERTICALCENTRECARET
:
2826 case SCI_MOVESELECTEDLINESUP
:
2827 case SCI_MOVESELECTEDLINESDOWN
:
2828 case SCI_SCROLLTOSTART
:
2829 case SCI_SCROLLTOEND
:
2832 // Filter out all others like display changes. Also, newlines are redundant
2833 // with char insert messages.
2836 // printf("Filtered out %ld of macro recording\n", iMessage);
2840 // Send notification
2841 SCNotification scn
= {};
2842 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2843 scn
.message
= iMessage
;
2844 scn
.wParam
= wParam
;
2845 scn
.lParam
= lParam
;
2849 // Something has changed that the container should know about
2850 void Editor::ContainerNeedsUpdate(int flags
) {
2851 needUpdateUI
|= flags
;
2855 * Force scroll and keep position relative to top of window.
2857 * If stuttered = true and not already at first/last row, move to first/last row of window.
2858 * If stuttered = true and already at first/last row, scroll as normal.
2860 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
2862 SelectionPosition newPos
;
2864 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
2865 int topStutterLine
= topLine
+ caretYSlop
;
2866 int bottomStutterLine
=
2867 pdoc
->LineFromPosition(PositionFromLocation(
2868 Point::FromInts(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
2871 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
2872 topLineNew
= topLine
;
2873 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
2874 false, false, UserVirtualSpace());
2876 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
2877 topLineNew
= topLine
;
2878 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
2879 false, false, UserVirtualSpace());
2882 Point pt
= LocationFromPosition(sel
.MainCaret());
2884 topLineNew
= Platform::Clamp(
2885 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2886 newPos
= SPositionFromLocation(
2887 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(pt
.y
) + direction
* (vs
.lineHeight
* LinesToScroll())),
2888 false, false, UserVirtualSpace());
2891 if (topLineNew
!= topLine
) {
2892 SetTopLine(topLineNew
);
2893 MovePositionTo(newPos
, selt
);
2895 SetVerticalScrollPos();
2897 MovePositionTo(newPos
, selt
);
2901 void Editor::ChangeCaseOfSelection(int caseMapping
) {
2903 for (size_t r
=0; r
<sel
.Count(); r
++) {
2904 SelectionRange current
= sel
.Range(r
);
2905 SelectionRange currentNoVS
= current
;
2906 currentNoVS
.ClearVirtualSpace();
2907 size_t rangeBytes
= currentNoVS
.Length();
2908 if (rangeBytes
> 0) {
2909 std::string sText
= RangeText(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
2911 std::string sMapped
= CaseMapString(sText
, caseMapping
);
2913 if (sMapped
!= sText
) {
2914 size_t firstDifference
= 0;
2915 while (sMapped
[firstDifference
] == sText
[firstDifference
])
2917 size_t lastDifferenceText
= sText
.size() - 1;
2918 size_t lastDifferenceMapped
= sMapped
.size() - 1;
2919 while (sMapped
[lastDifferenceMapped
] == sText
[lastDifferenceText
]) {
2920 lastDifferenceText
--;
2921 lastDifferenceMapped
--;
2923 size_t endDifferenceText
= sText
.size() - 1 - lastDifferenceText
;
2925 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2926 static_cast<int>(rangeBytes
- firstDifference
- endDifferenceText
));
2927 const int lengthChange
= static_cast<int>(lastDifferenceMapped
- firstDifference
+ 1);
2928 const int lengthInserted
= pdoc
->InsertString(
2929 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2930 sMapped
.c_str() + firstDifference
,
2932 // Automatic movement changes selection so reset to exactly the same as it was.
2933 int diffSizes
= static_cast<int>(sMapped
.size() - sText
.size()) + lengthInserted
- lengthChange
;
2934 if (diffSizes
!= 0) {
2935 if (current
.anchor
> current
.caret
)
2936 current
.anchor
.Add(diffSizes
);
2938 current
.caret
.Add(diffSizes
);
2940 sel
.Range(r
) = current
;
2946 void Editor::LineTranspose() {
2947 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2951 const int startPrevious
= pdoc
->LineStart(line
- 1);
2952 const std::string linePrevious
= RangeText(startPrevious
, pdoc
->LineEnd(line
- 1));
2954 int startCurrent
= pdoc
->LineStart(line
);
2955 const std::string lineCurrent
= RangeText(startCurrent
, pdoc
->LineEnd(line
));
2957 pdoc
->DeleteChars(startCurrent
, static_cast<int>(lineCurrent
.length()));
2958 pdoc
->DeleteChars(startPrevious
, static_cast<int>(linePrevious
.length()));
2959 startCurrent
-= static_cast<int>(linePrevious
.length());
2961 startCurrent
+= pdoc
->InsertString(startPrevious
, lineCurrent
.c_str(),
2962 static_cast<int>(lineCurrent
.length()));
2963 pdoc
->InsertString(startCurrent
, linePrevious
.c_str(),
2964 static_cast<int>(linePrevious
.length()));
2965 // Move caret to start of current line
2966 MovePositionTo(SelectionPosition(startCurrent
));
2970 void Editor::Duplicate(bool forLine
) {
2975 const char *eol
= "";
2978 eol
= StringFromEOLMode(pdoc
->eolMode
);
2979 eolLen
= istrlen(eol
);
2981 for (size_t r
=0; r
<sel
.Count(); r
++) {
2982 SelectionPosition start
= sel
.Range(r
).Start();
2983 SelectionPosition end
= sel
.Range(r
).End();
2985 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2986 start
= SelectionPosition(pdoc
->LineStart(line
));
2987 end
= SelectionPosition(pdoc
->LineEnd(line
));
2989 std::string text
= RangeText(start
.Position(), end
.Position());
2990 int lengthInserted
= eolLen
;
2992 lengthInserted
= pdoc
->InsertString(end
.Position(), eol
, eolLen
);
2993 pdoc
->InsertString(end
.Position() + lengthInserted
, text
.c_str(), static_cast<int>(text
.length()));
2995 if (sel
.Count() && sel
.IsRectangular()) {
2996 SelectionPosition last
= sel
.Last();
2998 int line
= pdoc
->LineFromPosition(last
.Position());
2999 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
3001 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
3002 sel
.Rectangular().anchor
= last
;
3004 sel
.Rectangular().caret
= last
;
3005 SetRectangularRange();
3009 void Editor::CancelModes() {
3010 sel
.SetMoveExtends(false);
3013 void Editor::NewLine() {
3014 InvalidateWholeSelection();
3015 if (sel
.IsRectangular() || !additionalSelectionTyping
) {
3016 // Remove non-main ranges
3017 sel
.DropAdditionalRanges();
3020 UndoGroup
ug(pdoc
, !sel
.Empty() || (sel
.Count() > 1));
3027 // Insert each line end
3028 size_t countInsertions
= 0;
3029 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3030 sel
.Range(r
).ClearVirtualSpace();
3031 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3032 const int positionInsert
= sel
.Range(r
).caret
.Position();
3033 const int insertLength
= pdoc
->InsertString(positionInsert
, eol
, istrlen(eol
));
3034 if (insertLength
> 0) {
3035 sel
.Range(r
) = SelectionRange(positionInsert
+ insertLength
);
3040 // Perform notifications after all the changes as the application may change the
3041 // selections in response to the characters.
3042 for (size_t i
= 0; i
< countInsertions
; i
++) {
3043 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3046 if (recordingMacro
) {
3050 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3058 EnsureCaretVisible();
3059 // Avoid blinking during rapid typing:
3060 ShowCaretAtCurrentPosition();
3063 SelectionPosition
Editor::PositionUpOrDown(SelectionPosition spStart
, int direction
, int lastX
) {
3064 const Point pt
= LocationFromPosition(spStart
);
3067 if (vs
.annotationVisible
) {
3068 const int lineDoc
= pdoc
->LineFromPosition(spStart
.Position());
3069 const Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
3070 const int subLine
= static_cast<int>(pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
3072 if (direction
< 0 && subLine
== 0) {
3073 const int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
3074 if (lineDisplay
> 0) {
3075 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
3077 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
3078 skipLines
= pdoc
->AnnotationLines(lineDoc
);
3082 const int newY
= static_cast<int>(pt
.y
) + (1 + skipLines
) * direction
* vs
.lineHeight
;
3084 lastX
= static_cast<int>(pt
.x
) + xOffset
;
3086 SelectionPosition posNew
= SPositionFromLocation(
3087 Point::FromInts(lastX
- xOffset
, newY
), false, false, UserVirtualSpace());
3089 if (direction
< 0) {
3090 // Line wrapping may lead to a location on the same line, so
3091 // seek back if that is the case.
3092 Point ptNew
= LocationFromPosition(posNew
.Position());
3093 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
3095 posNew
.SetVirtualSpace(0);
3096 ptNew
= LocationFromPosition(posNew
.Position());
3098 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
3099 // There is an equivalent case when moving down which skips
3101 Point ptNew
= LocationFromPosition(posNew
.Position());
3102 while ((posNew
.Position() > spStart
.Position()) && (ptNew
.y
> newY
)) {
3104 posNew
.SetVirtualSpace(0);
3105 ptNew
= LocationFromPosition(posNew
.Position());
3111 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
3112 if ((selt
== Selection::noSel
) && sel
.MoveExtends()) {
3113 selt
= Selection::selStream
;
3115 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
3116 if (sel
.IsRectangular()) {
3117 if (selt
== Selection::noSel
) {
3118 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
3120 caretToUse
= sel
.Rectangular().caret
;
3123 if (selt
== Selection::selRectangle
) {
3124 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3125 if (!sel
.IsRectangular()) {
3126 InvalidateWholeSelection();
3127 sel
.DropAdditionalRanges();
3129 const SelectionPosition posNew
= MovePositionSoVisible(
3130 PositionUpOrDown(caretToUse
, direction
, lastXChosen
), direction
);
3131 sel
.selType
= Selection::selRectangle
;
3132 sel
.Rectangular() = SelectionRange(posNew
, rangeBase
.anchor
);
3133 SetRectangularRange();
3134 MovedCaret(posNew
, caretToUse
, true);
3136 InvalidateWholeSelection();
3137 if (!additionalSelectionTyping
|| (sel
.IsRectangular())) {
3138 sel
.DropAdditionalRanges();
3140 sel
.selType
= Selection::selStream
;
3141 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3142 const int lastX
= (r
== sel
.Main()) ? lastXChosen
: -1;
3143 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3144 const SelectionPosition posNew
= MovePositionSoVisible(
3145 PositionUpOrDown(spCaretNow
, direction
, lastX
), direction
);
3146 sel
.Range(r
) = selt
== Selection::selStream
?
3147 SelectionRange(posNew
, sel
.Range(r
).anchor
) : SelectionRange(posNew
);
3149 sel
.RemoveDuplicates();
3150 MovedCaret(sel
.RangeMain().caret
, caretToUse
, true);
3154 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
3155 int lineDoc
, savedPos
= sel
.MainCaret();
3157 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
3158 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
3159 if (direction
> 0) {
3160 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
3161 if (selt
== Selection::noSel
) {
3162 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
3167 } while (!cs
.GetVisible(lineDoc
));
3170 Range
Editor::RangeDisplayLine(int lineVisible
) {
3172 AutoSurface
surface(this);
3173 return view
.RangeDisplayLine(surface
, *this, lineVisible
, vs
);
3176 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3178 AutoSurface
surface(this);
3179 int posRet
= view
.StartEndDisplayLine(surface
, *this, pos
, start
, vs
);
3180 if (posRet
== INVALID_POSITION
) {
3189 unsigned int WithExtends(unsigned int iMessage
) {
3191 case SCI_CHARLEFT
: return SCI_CHARLEFTEXTEND
;
3192 case SCI_CHARRIGHT
: return SCI_CHARRIGHTEXTEND
;
3194 case SCI_WORDLEFT
: return SCI_WORDLEFTEXTEND
;
3195 case SCI_WORDRIGHT
: return SCI_WORDRIGHTEXTEND
;
3196 case SCI_WORDLEFTEND
: return SCI_WORDLEFTENDEXTEND
;
3197 case SCI_WORDRIGHTEND
: return SCI_WORDRIGHTENDEXTEND
;
3198 case SCI_WORDPARTLEFT
: return SCI_WORDPARTLEFTEXTEND
;
3199 case SCI_WORDPARTRIGHT
: return SCI_WORDPARTRIGHTEXTEND
;
3201 case SCI_HOME
: return SCI_HOMEEXTEND
;
3202 case SCI_HOMEDISPLAY
: return SCI_HOMEDISPLAYEXTEND
;
3203 case SCI_HOMEWRAP
: return SCI_HOMEWRAPEXTEND
;
3204 case SCI_VCHOME
: return SCI_VCHOMEEXTEND
;
3205 case SCI_VCHOMEDISPLAY
: return SCI_VCHOMEDISPLAYEXTEND
;
3206 case SCI_VCHOMEWRAP
: return SCI_VCHOMEWRAPEXTEND
;
3208 case SCI_LINEEND
: return SCI_LINEENDEXTEND
;
3209 case SCI_LINEENDDISPLAY
: return SCI_LINEENDDISPLAYEXTEND
;
3210 case SCI_LINEENDWRAP
: return SCI_LINEENDWRAPEXTEND
;
3212 default: return iMessage
;
3216 int NaturalDirection(unsigned int iMessage
) {
3219 case SCI_CHARLEFTEXTEND
:
3220 case SCI_CHARLEFTRECTEXTEND
:
3222 case SCI_WORDLEFTEXTEND
:
3223 case SCI_WORDLEFTEND
:
3224 case SCI_WORDLEFTENDEXTEND
:
3225 case SCI_WORDPARTLEFT
:
3226 case SCI_WORDPARTLEFTEXTEND
:
3228 case SCI_HOMEEXTEND
:
3229 case SCI_HOMEDISPLAY
:
3230 case SCI_HOMEDISPLAYEXTEND
:
3232 case SCI_HOMEWRAPEXTEND
:
3233 // VC_HOME* mostly goes back
3235 case SCI_VCHOMEEXTEND
:
3236 case SCI_VCHOMEDISPLAY
:
3237 case SCI_VCHOMEDISPLAYEXTEND
:
3238 case SCI_VCHOMEWRAP
:
3239 case SCI_VCHOMEWRAPEXTEND
:
3247 bool IsRectExtend(unsigned int iMessage
) {
3249 case SCI_CHARLEFTRECTEXTEND
:
3250 case SCI_CHARRIGHTRECTEXTEND
:
3251 case SCI_HOMERECTEXTEND
:
3252 case SCI_VCHOMERECTEXTEND
:
3253 case SCI_LINEENDRECTEXTEND
:
3262 int Editor::VCHomeDisplayPosition(int position
) {
3263 const int homePos
= pdoc
->VCHomePosition(position
);
3264 const int viewLineStart
= StartEndDisplayLine(position
, true);
3265 if (viewLineStart
> homePos
)
3266 return viewLineStart
;
3271 int Editor::VCHomeWrapPosition(int position
) {
3272 const int homePos
= pdoc
->VCHomePosition(position
);
3273 const int viewLineStart
= StartEndDisplayLine(position
, true);
3274 if ((viewLineStart
< position
) && (viewLineStart
> homePos
))
3275 return viewLineStart
;
3280 int Editor::LineEndWrapPosition(int position
) {
3281 const int endPos
= StartEndDisplayLine(position
, false);
3282 const int realEndPos
= pdoc
->LineEndPosition(position
);
3283 if (endPos
> realEndPos
// if moved past visible EOLs
3284 || position
>= endPos
) // if at end of display line already
3290 int Editor::HorizontalMove(unsigned int iMessage
) {
3291 if (sel
.MoveExtends()) {
3292 iMessage
= WithExtends(iMessage
);
3295 if (!multipleSelection
&& !sel
.IsRectangular()) {
3296 // Simplify selection down to 1
3297 sel
.SetSelection(sel
.RangeMain());
3300 // Invalidate each of the current selections
3301 InvalidateWholeSelection();
3303 if (IsRectExtend(iMessage
)) {
3304 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3305 if (!sel
.IsRectangular()) {
3306 sel
.DropAdditionalRanges();
3308 // Will change to rectangular if not currently rectangular
3309 SelectionPosition spCaret
= rangeBase
.caret
;
3311 case SCI_CHARLEFTRECTEXTEND
:
3312 if (pdoc
->IsLineEndPosition(spCaret
.Position()) && spCaret
.VirtualSpace()) {
3313 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3314 } else if ((virtualSpaceOptions
& SCVS_NOWRAPLINESTART
) == 0 || pdoc
->GetColumn(spCaret
.Position()) > 0) {
3315 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3318 case SCI_CHARRIGHTRECTEXTEND
:
3319 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3320 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3322 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3325 case SCI_HOMERECTEXTEND
:
3326 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3328 case SCI_VCHOMERECTEXTEND
:
3329 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3331 case SCI_LINEENDRECTEXTEND
:
3332 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3335 const int directionMove
= (spCaret
< rangeBase
.caret
) ? -1 : 1;
3336 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3337 sel
.selType
= Selection::selRectangle
;
3338 sel
.Rectangular() = SelectionRange(spCaret
, rangeBase
.anchor
);
3339 SetRectangularRange();
3340 } else if (sel
.IsRectangular()) {
3341 // Not a rectangular extension so switch to stream.
3342 const SelectionPosition selAtLimit
=
3343 (NaturalDirection(iMessage
) > 0) ? sel
.Limits().end
: sel
.Limits().start
;
3344 sel
.selType
= Selection::selStream
;
3345 sel
.SetSelection(SelectionRange(selAtLimit
));
3347 if (!additionalSelectionTyping
) {
3348 InvalidateWholeSelection();
3349 sel
.DropAdditionalRanges();
3351 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3352 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3353 SelectionPosition spCaret
= spCaretNow
;
3356 case SCI_CHARLEFTEXTEND
:
3357 if (spCaret
.VirtualSpace()) {
3358 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3359 } else if ((virtualSpaceOptions
& SCVS_NOWRAPLINESTART
) == 0 || pdoc
->GetColumn(spCaret
.Position()) > 0) {
3360 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3364 case SCI_CHARRIGHTEXTEND
:
3365 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(spCaret
.Position())) {
3366 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3368 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3372 case SCI_WORDLEFTEXTEND
:
3373 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), -1));
3376 case SCI_WORDRIGHTEXTEND
:
3377 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), 1));
3379 case SCI_WORDLEFTEND
:
3380 case SCI_WORDLEFTENDEXTEND
:
3381 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), -1));
3383 case SCI_WORDRIGHTEND
:
3384 case SCI_WORDRIGHTENDEXTEND
:
3385 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), 1));
3387 case SCI_WORDPARTLEFT
:
3388 case SCI_WORDPARTLEFTEXTEND
:
3389 spCaret
= SelectionPosition(pdoc
->WordPartLeft(spCaret
.Position()));
3391 case SCI_WORDPARTRIGHT
:
3392 case SCI_WORDPARTRIGHTEXTEND
:
3393 spCaret
= SelectionPosition(pdoc
->WordPartRight(spCaret
.Position()));
3396 case SCI_HOMEEXTEND
:
3397 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3399 case SCI_HOMEDISPLAY
:
3400 case SCI_HOMEDISPLAYEXTEND
:
3401 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), true));
3404 case SCI_HOMEWRAPEXTEND
:
3405 spCaret
= MovePositionSoVisible(StartEndDisplayLine(spCaret
.Position(), true), -1);
3406 if (spCaretNow
<= spCaret
)
3407 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3410 case SCI_VCHOMEEXTEND
:
3411 // VCHome alternates between beginning of line and beginning of text so may move back or forwards
3412 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3414 case SCI_VCHOMEDISPLAY
:
3415 case SCI_VCHOMEDISPLAYEXTEND
:
3416 spCaret
= SelectionPosition(VCHomeDisplayPosition(spCaret
.Position()));
3418 case SCI_VCHOMEWRAP
:
3419 case SCI_VCHOMEWRAPEXTEND
:
3420 spCaret
= SelectionPosition(VCHomeWrapPosition(spCaret
.Position()));
3423 case SCI_LINEENDEXTEND
:
3424 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3426 case SCI_LINEENDDISPLAY
:
3427 case SCI_LINEENDDISPLAYEXTEND
:
3428 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), false));
3430 case SCI_LINEENDWRAP
:
3431 case SCI_LINEENDWRAPEXTEND
:
3432 spCaret
= SelectionPosition(LineEndWrapPosition(spCaret
.Position()));
3436 PLATFORM_ASSERT(false);
3439 const int directionMove
= (spCaret
< spCaretNow
) ? -1 : 1;
3440 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3442 // Handle move versus extend, and special behaviour for non-empty left/right
3446 if (sel
.Range(r
).Empty()) {
3447 sel
.Range(r
) = SelectionRange(spCaret
);
3449 sel
.Range(r
) = SelectionRange(
3450 (iMessage
== SCI_CHARLEFT
) ? sel
.Range(r
).Start() : sel
.Range(r
).End());
3456 case SCI_WORDLEFTEND
:
3457 case SCI_WORDRIGHTEND
:
3458 case SCI_WORDPARTLEFT
:
3459 case SCI_WORDPARTRIGHT
:
3461 case SCI_HOMEDISPLAY
:
3464 case SCI_VCHOMEDISPLAY
:
3465 case SCI_VCHOMEWRAP
:
3467 case SCI_LINEENDDISPLAY
:
3468 case SCI_LINEENDWRAP
:
3469 sel
.Range(r
) = SelectionRange(spCaret
);
3472 case SCI_CHARLEFTEXTEND
:
3473 case SCI_CHARRIGHTEXTEND
:
3474 case SCI_WORDLEFTEXTEND
:
3475 case SCI_WORDRIGHTEXTEND
:
3476 case SCI_WORDLEFTENDEXTEND
:
3477 case SCI_WORDRIGHTENDEXTEND
:
3478 case SCI_WORDPARTLEFTEXTEND
:
3479 case SCI_WORDPARTRIGHTEXTEND
:
3480 case SCI_HOMEEXTEND
:
3481 case SCI_HOMEDISPLAYEXTEND
:
3482 case SCI_HOMEWRAPEXTEND
:
3483 case SCI_VCHOMEEXTEND
:
3484 case SCI_VCHOMEDISPLAYEXTEND
:
3485 case SCI_VCHOMEWRAPEXTEND
:
3486 case SCI_LINEENDEXTEND
:
3487 case SCI_LINEENDDISPLAYEXTEND
:
3488 case SCI_LINEENDWRAPEXTEND
: {
3489 SelectionRange rangeNew
= SelectionRange(spCaret
, sel
.Range(r
).anchor
);
3490 sel
.TrimOtherSelections(r
, SelectionRange(rangeNew
));
3491 sel
.Range(r
) = rangeNew
;
3496 PLATFORM_ASSERT(false);
3501 sel
.RemoveDuplicates();
3503 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3505 // Invalidate the new state of the selection
3506 InvalidateWholeSelection();
3509 // Need the line moving and so forth from MovePositionTo
3513 int Editor::DelWordOrLine(unsigned int iMessage
) {
3514 // Virtual space may be realised for SCI_DELWORDRIGHT or SCI_DELWORDRIGHTEND
3515 // which means 2 actions so wrap in an undo group.
3517 // Rightwards and leftwards deletions differ in treatment of virtual space.
3518 // Clear virtual space for leftwards, realise for rightwards.
3519 const bool leftwards
= (iMessage
== SCI_DELWORDLEFT
) || (iMessage
== SCI_DELLINELEFT
);
3521 if (!additionalSelectionTyping
) {
3522 InvalidateWholeSelection();
3523 sel
.DropAdditionalRanges();
3526 UndoGroup
ug0(pdoc
, (sel
.Count() > 1) || !leftwards
);
3528 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3530 // Delete to the left so first clear the virtual space.
3531 sel
.Range(r
).ClearVirtualSpace();
3533 // Delete to the right so first realise the virtual space.
3534 sel
.Range(r
) = SelectionRange(
3535 RealizeVirtualSpace(sel
.Range(r
).caret
));
3540 case SCI_DELWORDLEFT
:
3541 rangeDelete
= Range(
3542 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), -1),
3543 sel
.Range(r
).caret
.Position());
3545 case SCI_DELWORDRIGHT
:
3546 rangeDelete
= Range(
3547 sel
.Range(r
).caret
.Position(),
3548 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), 1));
3550 case SCI_DELWORDRIGHTEND
:
3551 rangeDelete
= Range(
3552 sel
.Range(r
).caret
.Position(),
3553 pdoc
->NextWordEnd(sel
.Range(r
).caret
.Position(), 1));
3555 case SCI_DELLINELEFT
:
3556 rangeDelete
= Range(
3557 pdoc
->LineStart(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())),
3558 sel
.Range(r
).caret
.Position());
3560 case SCI_DELLINERIGHT
:
3561 rangeDelete
= Range(
3562 sel
.Range(r
).caret
.Position(),
3563 pdoc
->LineEnd(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())));
3566 if (!RangeContainsProtected(rangeDelete
.start
, rangeDelete
.end
)) {
3567 pdoc
->DeleteChars(rangeDelete
.start
, rangeDelete
.end
- rangeDelete
.start
);
3571 // May need something stronger here: can selections overlap at this point?
3572 sel
.RemoveDuplicates();
3574 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3576 // Invalidate the new state of the selection
3577 InvalidateWholeSelection();
3583 int Editor::KeyCommand(unsigned int iMessage
) {
3586 CursorUpOrDown(1, Selection::noSel
);
3588 case SCI_LINEDOWNEXTEND
:
3589 CursorUpOrDown(1, Selection::selStream
);
3591 case SCI_LINEDOWNRECTEXTEND
:
3592 CursorUpOrDown(1, Selection::selRectangle
);
3595 ParaUpOrDown(1, Selection::noSel
);
3597 case SCI_PARADOWNEXTEND
:
3598 ParaUpOrDown(1, Selection::selStream
);
3600 case SCI_LINESCROLLDOWN
:
3601 ScrollTo(topLine
+ 1);
3602 MoveCaretInsideView(false);
3605 CursorUpOrDown(-1, Selection::noSel
);
3607 case SCI_LINEUPEXTEND
:
3608 CursorUpOrDown(-1, Selection::selStream
);
3610 case SCI_LINEUPRECTEXTEND
:
3611 CursorUpOrDown(-1, Selection::selRectangle
);
3614 ParaUpOrDown(-1, Selection::noSel
);
3616 case SCI_PARAUPEXTEND
:
3617 ParaUpOrDown(-1, Selection::selStream
);
3619 case SCI_LINESCROLLUP
:
3620 ScrollTo(topLine
- 1);
3621 MoveCaretInsideView(false);
3625 case SCI_CHARLEFTEXTEND
:
3626 case SCI_CHARLEFTRECTEXTEND
:
3628 case SCI_CHARRIGHTEXTEND
:
3629 case SCI_CHARRIGHTRECTEXTEND
:
3631 case SCI_WORDLEFTEXTEND
:
3633 case SCI_WORDRIGHTEXTEND
:
3634 case SCI_WORDLEFTEND
:
3635 case SCI_WORDLEFTENDEXTEND
:
3636 case SCI_WORDRIGHTEND
:
3637 case SCI_WORDRIGHTENDEXTEND
:
3638 case SCI_WORDPARTLEFT
:
3639 case SCI_WORDPARTLEFTEXTEND
:
3640 case SCI_WORDPARTRIGHT
:
3641 case SCI_WORDPARTRIGHTEXTEND
:
3643 case SCI_HOMEEXTEND
:
3644 case SCI_HOMERECTEXTEND
:
3645 case SCI_HOMEDISPLAY
:
3646 case SCI_HOMEDISPLAYEXTEND
:
3648 case SCI_HOMEWRAPEXTEND
:
3650 case SCI_VCHOMEEXTEND
:
3651 case SCI_VCHOMERECTEXTEND
:
3652 case SCI_VCHOMEDISPLAY
:
3653 case SCI_VCHOMEDISPLAYEXTEND
:
3654 case SCI_VCHOMEWRAP
:
3655 case SCI_VCHOMEWRAPEXTEND
:
3657 case SCI_LINEENDEXTEND
:
3658 case SCI_LINEENDRECTEXTEND
:
3659 case SCI_LINEENDDISPLAY
:
3660 case SCI_LINEENDDISPLAYEXTEND
:
3661 case SCI_LINEENDWRAP
:
3662 case SCI_LINEENDWRAPEXTEND
:
3663 return HorizontalMove(iMessage
);
3665 case SCI_DOCUMENTSTART
:
3669 case SCI_DOCUMENTSTARTEXTEND
:
3670 MovePositionTo(0, Selection::selStream
);
3673 case SCI_DOCUMENTEND
:
3674 MovePositionTo(pdoc
->Length());
3677 case SCI_DOCUMENTENDEXTEND
:
3678 MovePositionTo(pdoc
->Length(), Selection::selStream
);
3681 case SCI_STUTTEREDPAGEUP
:
3682 PageMove(-1, Selection::noSel
, true);
3684 case SCI_STUTTEREDPAGEUPEXTEND
:
3685 PageMove(-1, Selection::selStream
, true);
3687 case SCI_STUTTEREDPAGEDOWN
:
3688 PageMove(1, Selection::noSel
, true);
3690 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3691 PageMove(1, Selection::selStream
, true);
3696 case SCI_PAGEUPEXTEND
:
3697 PageMove(-1, Selection::selStream
);
3699 case SCI_PAGEUPRECTEXTEND
:
3700 PageMove(-1, Selection::selRectangle
);
3705 case SCI_PAGEDOWNEXTEND
:
3706 PageMove(1, Selection::selStream
);
3708 case SCI_PAGEDOWNRECTEXTEND
:
3709 PageMove(1, Selection::selRectangle
);
3711 case SCI_EDITTOGGLEOVERTYPE
:
3712 inOverstrike
= !inOverstrike
;
3713 ShowCaretAtCurrentPosition();
3714 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
3717 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3718 // Also unselect text
3720 if (sel
.Count() > 1) {
3721 // Drop additional selections
3722 InvalidateWholeSelection();
3723 sel
.DropAdditionalRanges();
3726 case SCI_DELETEBACK
:
3728 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3731 EnsureCaretVisible();
3733 case SCI_DELETEBACKNOTLINE
:
3735 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3738 EnsureCaretVisible();
3742 if (caretSticky
== SC_CARETSTICKY_OFF
) {
3745 EnsureCaretVisible();
3746 ShowCaretAtCurrentPosition(); // Avoid blinking
3750 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3753 EnsureCaretVisible();
3754 ShowCaretAtCurrentPosition(); // Avoid blinking
3763 if (vs
.zoomLevel
< 20) {
3765 InvalidateStyleRedraw();
3770 if (vs
.zoomLevel
> -10) {
3772 InvalidateStyleRedraw();
3777 case SCI_DELWORDLEFT
:
3778 case SCI_DELWORDRIGHT
:
3779 case SCI_DELWORDRIGHTEND
:
3780 case SCI_DELLINELEFT
:
3781 case SCI_DELLINERIGHT
:
3782 return DelWordOrLine(iMessage
);
3784 case SCI_LINECOPY
: {
3785 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3786 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3787 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3788 pdoc
->LineStart(lineEnd
+ 1));
3792 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3793 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3794 int start
= pdoc
->LineStart(lineStart
);
3795 int end
= pdoc
->LineStart(lineEnd
+ 1);
3796 SetSelection(start
, end
);
3801 case SCI_LINEDELETE
: {
3802 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3803 int start
= pdoc
->LineStart(line
);
3804 int end
= pdoc
->LineStart(line
+ 1);
3805 pdoc
->DeleteChars(start
, end
- start
);
3808 case SCI_LINETRANSPOSE
:
3811 case SCI_LINEDUPLICATE
:
3814 case SCI_SELECTIONDUPLICATE
:
3818 ChangeCaseOfSelection(cmLower
);
3821 ChangeCaseOfSelection(cmUpper
);
3823 case SCI_SCROLLTOSTART
:
3826 case SCI_SCROLLTOEND
:
3827 ScrollTo(MaxScrollPos());
3833 int Editor::KeyDefault(int, int) {
3837 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
3839 int msg
= kmap
.Find(key
, modifiers
);
3843 return static_cast<int>(WndProc(msg
, 0, 0));
3847 return KeyDefault(key
, modifiers
);
3851 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3852 return KeyDownWithModifiers(key
, ModifierFlags(shift
, ctrl
, alt
), consumed
);
3855 void Editor::Indent(bool forwards
) {
3857 for (size_t r
=0; r
<sel
.Count(); r
++) {
3858 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
3859 int caretPosition
= sel
.Range(r
).caret
.Position();
3860 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
3861 if (lineOfAnchor
== lineCurrentPos
) {
3863 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
3864 caretPosition
= sel
.Range(r
).caret
.Position();
3865 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3867 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3868 int indentationStep
= pdoc
->IndentSize();
3869 const int posSelect
= pdoc
->SetLineIndentation(
3870 lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
3871 sel
.Range(r
) = SelectionRange(posSelect
);
3873 if (pdoc
->useTabs
) {
3874 const int lengthInserted
= pdoc
->InsertString(caretPosition
, "\t", 1);
3875 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3877 int numSpaces
= (pdoc
->tabInChars
) -
3878 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
3880 numSpaces
= pdoc
->tabInChars
;
3881 const std::string
spaceText(numSpaces
, ' ');
3882 const int lengthInserted
= pdoc
->InsertString(caretPosition
, spaceText
.c_str(),
3883 static_cast<int>(spaceText
.length()));
3884 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3888 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3890 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3891 int indentationStep
= pdoc
->IndentSize();
3892 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3893 sel
.Range(r
) = SelectionRange(posSelect
);
3895 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
3899 int newPos
= caretPosition
;
3900 while (pdoc
->GetColumn(newPos
) > newColumn
)
3902 sel
.Range(r
) = SelectionRange(newPos
);
3905 } else { // Multiline
3906 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
3907 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
3908 // Multiple lines selected so indent / dedent
3909 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3910 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3911 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
3912 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3913 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3914 if (lineOfAnchor
< lineCurrentPos
) {
3915 if (currentPosPosOnLine
== 0)
3916 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3918 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3920 if (anchorPosOnLine
== 0)
3921 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3923 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3927 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
3930 class CaseFolderASCII
: public CaseFolderTable
{
3935 ~CaseFolderASCII() override
{
3940 CaseFolder
*Editor::CaseFolderForEncoding() {
3941 // Simple default that only maps ASCII upper case to lower case.
3942 return new CaseFolderASCII();
3946 * Search of a text in the document, in the given range.
3947 * @return The position of the found text, -1 if not found.
3949 long Editor::FindText(
3950 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3951 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3952 sptr_t lParam
) { ///< @c Sci_TextToFind structure: The text to search for in the given range.
3954 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
3955 int lengthFound
= istrlen(ft
->lpstrText
);
3956 if (!pdoc
->HasCaseFolder())
3957 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3959 long pos
= pdoc
->FindText(
3960 static_cast<int>(ft
->chrg
.cpMin
),
3961 static_cast<int>(ft
->chrg
.cpMax
),
3963 static_cast<int>(wParam
),
3966 ft
->chrgText
.cpMin
= pos
;
3967 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3969 return static_cast<int>(pos
);
3970 } catch (RegexError
&) {
3971 errorStatus
= SC_STATUS_WARN_REGEX
;
3977 * Relocatable search support : Searches relative to current selection
3978 * point and sets the selection to the found text range with
3982 * Anchor following searches at current selection start: This allows
3983 * multiple incremental interactive searches to be macro recorded
3984 * while still setting the selection to found text so the find/select
3985 * operation is self-contained.
3987 void Editor::SearchAnchor() {
3988 searchAnchor
= SelectionStart().Position();
3992 * Find text from current search anchor: Must call @c SearchAnchor first.
3993 * Used for next text and previous text requests.
3994 * @return The position of the found text, -1 if not found.
3996 long Editor::SearchText(
3997 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3998 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3999 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
4000 sptr_t lParam
) { ///< The text to search for.
4002 const char *txt
= reinterpret_cast<char *>(lParam
);
4004 int lengthFound
= istrlen(txt
);
4005 if (!pdoc
->HasCaseFolder())
4006 pdoc
->SetCaseFolder(CaseFolderForEncoding());
4008 if (iMessage
== SCI_SEARCHNEXT
) {
4009 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
4010 static_cast<int>(wParam
),
4013 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
4014 static_cast<int>(wParam
),
4017 } catch (RegexError
&) {
4018 errorStatus
= SC_STATUS_WARN_REGEX
;
4022 SetSelection(static_cast<int>(pos
), static_cast<int>(pos
+ lengthFound
));
4028 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
4030 for (char &ch
: ret
) {
4031 switch (caseMapping
) {
4033 if (ch
>= 'a' && ch
<= 'z')
4034 ch
= static_cast<char>(ch
- 'a' + 'A');
4037 if (ch
>= 'A' && ch
<= 'Z')
4038 ch
= static_cast<char>(ch
- 'A' + 'a');
4046 * Search for text in the target range of the document.
4047 * @return The position of the found text, -1 if not found.
4049 long Editor::SearchInTarget(const char *text
, int length
) {
4050 int lengthFound
= length
;
4052 if (!pdoc
->HasCaseFolder())
4053 pdoc
->SetCaseFolder(CaseFolderForEncoding());
4055 long pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4059 targetStart
= static_cast<int>(pos
);
4060 targetEnd
= static_cast<int>(pos
+ lengthFound
);
4063 } catch (RegexError
&) {
4064 errorStatus
= SC_STATUS_WARN_REGEX
;
4069 void Editor::GoToLine(int lineNo
) {
4070 if (lineNo
> pdoc
->LinesTotal())
4071 lineNo
= pdoc
->LinesTotal();
4074 SetEmptySelection(pdoc
->LineStart(lineNo
));
4075 ShowCaretAtCurrentPosition();
4076 EnsureCaretVisible();
4079 static bool Close(Point pt1
, Point pt2
, Point threshold
) {
4080 if (std::abs(pt1
.x
- pt2
.x
) > threshold
.x
)
4082 if (std::abs(pt1
.y
- pt2
.y
) > threshold
.y
)
4087 std::string
Editor::RangeText(int start
, int end
) const {
4089 int len
= end
- start
;
4090 std::string
ret(len
, '\0');
4091 for (int i
= 0; i
< len
; i
++) {
4092 ret
[i
] = pdoc
->CharAt(start
+ i
);
4096 return std::string();
4099 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
4101 if (allowLineCopy
) {
4102 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4103 int start
= pdoc
->LineStart(currentLine
);
4104 int end
= pdoc
->LineEnd(currentLine
);
4106 std::string text
= RangeText(start
, end
);
4107 if (pdoc
->eolMode
!= SC_EOL_LF
)
4108 text
.push_back('\r');
4109 if (pdoc
->eolMode
!= SC_EOL_CR
)
4110 text
.push_back('\n');
4111 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4112 vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
4116 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
4117 if (sel
.selType
== Selection::selRectangle
)
4118 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
4119 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
4120 SelectionRange current
= rangesInOrder
[r
];
4121 text
.append(RangeText(current
.Start().Position(), current
.End().Position()));
4122 if (sel
.selType
== Selection::selRectangle
) {
4123 if (pdoc
->eolMode
!= SC_EOL_LF
)
4124 text
.push_back('\r');
4125 if (pdoc
->eolMode
!= SC_EOL_CR
)
4126 text
.push_back('\n');
4129 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4130 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
4134 void Editor::CopyRangeToClipboard(int start
, int end
) {
4135 start
= pdoc
->ClampPositionIntoDocument(start
);
4136 end
= pdoc
->ClampPositionIntoDocument(end
);
4137 SelectionText selectedText
;
4138 std::string text
= RangeText(start
, end
);
4139 selectedText
.Copy(text
,
4140 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4141 CopyToClipboard(selectedText
);
4144 void Editor::CopyText(int length
, const char *text
) {
4145 SelectionText selectedText
;
4146 selectedText
.Copy(std::string(text
, length
),
4147 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4148 CopyToClipboard(selectedText
);
4151 void Editor::SetDragPosition(SelectionPosition newPos
) {
4152 if (newPos
.Position() >= 0) {
4153 newPos
= MovePositionOutsideChar(newPos
, 1);
4156 if (!(posDrag
== newPos
)) {
4158 if (FineTickerAvailable()) {
4159 FineTickerCancel(tickCaret
);
4160 if ((caret
.active
) && (caret
.period
> 0) && (newPos
.Position() < 0))
4161 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
4171 void Editor::DisplayCursor(Window::Cursor c
) {
4172 if (cursorMode
== SC_CURSORNORMAL
)
4175 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4178 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
4179 int xMove
= static_cast<int>(ptStart
.x
- ptNow
.x
);
4180 int yMove
= static_cast<int>(ptStart
.y
- ptNow
.y
);
4181 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
4182 return distanceSquared
> 16;
4185 void Editor::StartDrag() {
4186 // Always handled by subclasses
4187 //SetMouseCapture(true);
4188 //DisplayCursor(Window::cursorArrow);
4191 void Editor::DropAt(SelectionPosition position
, const char *value
, size_t lengthValue
, bool moving
, bool rectangular
) {
4192 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
4193 if (inDragDrop
== ddDragging
)
4194 dropWentOutside
= false;
4196 bool positionWasInSelection
= PositionInSelection(position
.Position());
4198 bool positionOnEdgeOfSelection
=
4199 (position
== SelectionStart()) || (position
== SelectionEnd());
4201 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
4202 (positionOnEdgeOfSelection
&& !moving
)) {
4204 SelectionPosition selStart
= SelectionStart();
4205 SelectionPosition selEnd
= SelectionEnd();
4209 SelectionPosition positionAfterDeletion
= position
;
4210 if ((inDragDrop
== ddDragging
) && moving
) {
4211 // Remove dragged out text
4212 if (rectangular
|| sel
.selType
== Selection::selLines
) {
4213 for (size_t r
=0; r
<sel
.Count(); r
++) {
4214 if (position
>= sel
.Range(r
).Start()) {
4215 if (position
> sel
.Range(r
).End()) {
4216 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
4218 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
4223 if (position
> selStart
) {
4224 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
4229 position
= positionAfterDeletion
;
4231 std::string convertedText
= Document::TransformLineEnds(value
, lengthValue
, pdoc
->eolMode
);
4234 PasteRectangular(position
, convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4235 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4236 SetEmptySelection(position
);
4238 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
4239 position
= RealizeVirtualSpace(position
);
4240 const int lengthInserted
= pdoc
->InsertString(
4241 position
.Position(), convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4242 if (lengthInserted
> 0) {
4243 SelectionPosition posAfterInsertion
= position
;
4244 posAfterInsertion
.Add(lengthInserted
);
4245 SetSelection(posAfterInsertion
, position
);
4248 } else if (inDragDrop
== ddDragging
) {
4249 SetEmptySelection(position
);
4253 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
4254 DropAt(position
, value
, strlen(value
), moving
, rectangular
);
4258 * @return true if given position is inside the selection,
4260 bool Editor::PositionInSelection(int pos
) {
4261 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
4262 for (size_t r
=0; r
<sel
.Count(); r
++) {
4263 if (sel
.Range(r
).Contains(pos
))
4269 bool Editor::PointInSelection(Point pt
) {
4270 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
4271 Point ptPos
= LocationFromPosition(pos
);
4272 for (size_t r
=0; r
<sel
.Count(); r
++) {
4273 SelectionRange range
= sel
.Range(r
);
4274 if (range
.Contains(pos
)) {
4276 if (pos
== range
.Start()) {
4277 // see if just before selection
4278 if (pt
.x
< ptPos
.x
) {
4282 if (pos
== range
.End()) {
4283 // see if just after selection
4284 if (pt
.x
> ptPos
.x
) {
4295 bool Editor::PointInSelMargin(Point pt
) const {
4296 // Really means: "Point in a margin"
4297 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4298 PRectangle rcSelMargin
= GetClientRectangle();
4299 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.leftMarginWidth
);
4300 rcSelMargin
.left
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.fixedColumnWidth
);
4301 return rcSelMargin
.ContainsWholePixel(pt
);
4307 Window::Cursor
Editor::GetMarginCursor(Point pt
) const {
4309 for (size_t margin
= 0; margin
< vs
.ms
.size(); margin
++) {
4310 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4311 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
4312 x
+= vs
.ms
[margin
].width
;
4314 return Window::cursorReverseArrow
;
4317 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
4318 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
4319 SetSelection(currentPos_
, anchor_
);
4322 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
4323 int selCurrentPos
, selAnchorPos
;
4325 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
4326 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
4327 if (lineAnchorPos_
< lineCurrentPos_
) {
4328 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
4329 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4330 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4331 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
4332 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4333 } else { // Same line, select it
4334 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4335 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4338 if (lineAnchorPos_
< lineCurrentPos_
) {
4339 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
4340 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4341 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4342 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4343 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
4344 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4345 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
4346 } else { // Same line, select it
4347 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4348 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4349 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4352 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
4355 void Editor::WordSelection(int pos
) {
4356 if (pos
< wordSelectAnchorStartPos
) {
4357 // Extend backward to the word containing pos.
4358 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
4359 // This ensures that a series of empty lines isn't counted as a single "word".
4360 if (!pdoc
->IsLineEndPosition(pos
))
4361 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
4362 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
4363 } else if (pos
> wordSelectAnchorEndPos
) {
4364 // Extend forward to the word containing the character to the left of pos.
4365 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
4366 // This ensures that a series of empty lines isn't counted as a single "word".
4367 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
4368 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
4369 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
4371 // Select only the anchored word
4372 if (pos
>= originalAnchorPos
)
4373 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
4375 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
4379 void Editor::DwellEnd(bool mouseMoved
) {
4381 ticksToDwell
= dwellDelay
;
4383 ticksToDwell
= SC_TIME_FOREVER
;
4384 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4386 NotifyDwelling(ptMouseLast
, dwelling
);
4388 if (FineTickerAvailable()) {
4389 FineTickerCancel(tickDwell
);
4390 if (mouseMoved
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4391 //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
4396 void Editor::MouseLeave() {
4397 SetHotSpotRange(NULL
);
4398 if (!HaveMouseCapture()) {
4399 ptMouseLast
= Point(-1,-1);
4404 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
4405 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
4406 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
4409 void Editor::ButtonDownWithModifiers(Point pt
, unsigned int curTime
, int modifiers
) {
4410 SetHoverIndicatorPoint(pt
);
4411 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
4413 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
4414 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
4415 const bool alt
= (modifiers
& SCI_ALT
) != 0;
4416 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
4417 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4418 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4419 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4420 inDragDrop
= ddNone
;
4421 sel
.SetMoveExtends(false);
4423 if (NotifyMarginClick(pt
, modifiers
))
4426 NotifyIndicatorClick(true, newPos
.Position(), modifiers
);
4428 bool inSelMargin
= PointInSelMargin(pt
);
4429 // In margin ctrl+(double)click should always select everything
4430 if (ctrl
&& inSelMargin
) {
4432 lastClickTime
= curTime
;
4436 if (shift
&& !inSelMargin
) {
4437 SetSelection(newPos
);
4439 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
, doubleClickCloseThreshold
)) {
4440 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4441 SetMouseCapture(true);
4442 if (FineTickerAvailable()) {
4443 FineTickerStart(tickScroll
, 100, 10);
4445 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
4446 SetEmptySelection(newPos
.Position());
4447 bool doubleClick
= false;
4448 // Stop mouse button bounce changing selection type
4449 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4451 // Inside margin selection type should be either selSubLine or selWholeLine.
4452 if (selectionType
== selSubLine
) {
4453 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
4454 // so we switch to selWholeLine in order to select whole line.
4455 selectionType
= selWholeLine
;
4456 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
4457 // If it is neither, reset selection type to line selection.
4458 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4461 if (selectionType
== selChar
) {
4462 selectionType
= selWord
;
4464 } else if (selectionType
== selWord
) {
4465 // Since we ended up here, we're inside a *triple* click, which should always select
4466 // whole line regardless of word wrap being enabled or not.
4467 selectionType
= selWholeLine
;
4469 selectionType
= selChar
;
4470 originalAnchorPos
= sel
.MainCaret();
4475 if (selectionType
== selWord
) {
4476 int charPos
= originalAnchorPos
;
4477 if (sel
.MainCaret() == originalAnchorPos
) {
4478 charPos
= PositionFromLocation(pt
, false, true);
4479 charPos
= MovePositionOutsideChar(charPos
, -1);
4482 int startWord
, endWord
;
4483 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
4484 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
4485 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
4487 // Selecting backwards, or anchor beyond last character on line. In these cases,
4488 // we select the word containing the character to the *left* of the anchor.
4489 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
4490 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
4491 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
4493 // Anchor at start of line; select nothing to begin with.
4494 startWord
= charPos
;
4499 wordSelectAnchorStartPos
= startWord
;
4500 wordSelectAnchorEndPos
= endWord
;
4501 wordSelectInitialCaretPos
= sel
.MainCaret();
4502 WordSelection(wordSelectInitialCaretPos
);
4503 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
4504 lineAnchorPos
= newPos
.Position();
4505 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4506 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4508 SetEmptySelection(sel
.MainCaret());
4510 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4512 NotifyDoubleClick(pt
, modifiers
);
4513 if (PositionIsHotspot(newCharPos
.Position()))
4514 NotifyHotSpotDoubleClicked(newCharPos
.Position(), modifiers
);
4516 } else { // Single click
4518 if (sel
.IsRectangular() || (sel
.Count() > 1)) {
4519 InvalidateWholeSelection();
4522 sel
.selType
= Selection::selStream
;
4524 // Single click in margin: select whole line or only subline if word wrap is enabled
4525 lineAnchorPos
= newPos
.Position();
4526 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4527 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4529 // Single shift+click in margin: select from line anchor to clicked line
4530 if (sel
.MainAnchor() > sel
.MainCaret())
4531 lineAnchorPos
= sel
.MainAnchor() - 1;
4533 lineAnchorPos
= sel
.MainAnchor();
4534 // Reset selection type if there is an empty selection.
4535 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
4536 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
4537 // This ensures that we continue selecting in the same selection mode.
4538 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
4539 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4540 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4543 SetDragPosition(SelectionPosition(invalidPosition
));
4544 SetMouseCapture(true);
4545 if (FineTickerAvailable()) {
4546 FineTickerStart(tickScroll
, 100, 10);
4549 if (PointIsHotspot(pt
)) {
4550 NotifyHotSpotClicked(newCharPos
.Position(), modifiers
);
4551 hotSpotClickPos
= newCharPos
.Position();
4554 if (PointInSelection(pt
) && !SelectionEmpty())
4555 inDragDrop
= ddInitial
;
4557 inDragDrop
= ddNone
;
4559 SetMouseCapture(true);
4560 if (FineTickerAvailable()) {
4561 FineTickerStart(tickScroll
, 100, 10);
4563 if (inDragDrop
!= ddInitial
) {
4564 SetDragPosition(SelectionPosition(invalidPosition
));
4566 if (ctrl
&& multipleSelection
) {
4567 SelectionRange
range(newPos
);
4568 sel
.TentativeSelection(range
);
4569 InvalidateSelection(range
, true);
4571 InvalidateSelection(SelectionRange(newPos
), true);
4572 if (sel
.Count() > 1)
4574 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
4576 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4577 SetSelection(newPos
, newPos
);
4580 SelectionPosition anchorCurrent
= newPos
;
4582 anchorCurrent
= sel
.IsRectangular() ?
4583 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
4584 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4585 selectionType
= selChar
;
4586 originalAnchorPos
= sel
.MainCaret();
4587 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
4588 SetRectangularRange();
4592 lastClickTime
= curTime
;
4594 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4595 ShowCaretAtCurrentPosition();
4598 void Editor::RightButtonDownWithModifiers(Point pt
, unsigned int, int modifiers
) {
4599 if (NotifyMarginRightClick(pt
, modifiers
))
4603 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4604 return ButtonDownWithModifiers(pt
, curTime
, ModifierFlags(shift
, ctrl
, alt
));
4607 bool Editor::PositionIsHotspot(int position
) const {
4608 return vs
.styles
[pdoc
->StyleIndexAt(position
)].hotspot
;
4611 bool Editor::PointIsHotspot(Point pt
) {
4612 int pos
= PositionFromLocation(pt
, true, true);
4613 if (pos
== INVALID_POSITION
)
4615 return PositionIsHotspot(pos
);
4618 void Editor::SetHoverIndicatorPosition(int position
) {
4619 int hoverIndicatorPosPrev
= hoverIndicatorPos
;
4620 hoverIndicatorPos
= INVALID_POSITION
;
4621 if (vs
.indicatorsDynamic
== 0)
4623 if (position
!= INVALID_POSITION
) {
4624 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
4625 if (vs
.indicators
[deco
->indicator
].IsDynamic()) {
4626 if (pdoc
->decorations
.ValueAt(deco
->indicator
, position
)) {
4627 hoverIndicatorPos
= position
;
4632 if (hoverIndicatorPosPrev
!= hoverIndicatorPos
) {
4637 void Editor::SetHoverIndicatorPoint(Point pt
) {
4638 if (vs
.indicatorsDynamic
== 0) {
4639 SetHoverIndicatorPosition(INVALID_POSITION
);
4641 SetHoverIndicatorPosition(PositionFromLocation(pt
, true, true));
4645 void Editor::SetHotSpotRange(Point
*pt
) {
4647 int pos
= PositionFromLocation(*pt
, false, true);
4649 // If we don't limit this to word characters then the
4650 // range can encompass more than the run range and then
4651 // the underline will not be drawn properly.
4653 hsNew
.start
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4654 hsNew
.end
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4656 // Only invalidate the range if the hotspot range has changed...
4657 if (!(hsNew
== hotspot
)) {
4658 if (hotspot
.Valid()) {
4659 InvalidateRange(hotspot
.start
, hotspot
.end
);
4662 InvalidateRange(hotspot
.start
, hotspot
.end
);
4665 if (hotspot
.Valid()) {
4666 InvalidateRange(hotspot
.start
, hotspot
.end
);
4668 hotspot
= Range(invalidPosition
);
4672 Range
Editor::GetHotSpotRange() const {
4676 void Editor::ButtonMoveWithModifiers(Point pt
, int modifiers
) {
4677 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4681 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
4682 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4683 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
4685 if (inDragDrop
== ddInitial
) {
4686 if (DragThreshold(ptMouseLast
, pt
)) {
4687 SetMouseCapture(false);
4688 if (FineTickerAvailable()) {
4689 FineTickerCancel(tickScroll
);
4691 SetDragPosition(movePos
);
4692 CopySelectionRange(&drag
);
4699 PRectangle rcClient
= GetClientRectangle();
4700 Point ptOrigin
= GetVisibleOriginInMain();
4701 rcClient
.Move(0, -ptOrigin
.y
);
4702 if (FineTickerAvailable() && (dwellDelay
< SC_TIME_FOREVER
) && rcClient
.Contains(pt
)) {
4703 FineTickerStart(tickDwell
, dwellDelay
, dwellDelay
/10);
4705 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4706 if (HaveMouseCapture()) {
4708 // Slow down autoscrolling/selection
4709 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4710 if (autoScrollTimer
.ticksToWait
> 0)
4712 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4715 if (posDrag
.IsValid()) {
4716 SetDragPosition(movePos
);
4718 if (selectionType
== selChar
) {
4719 if (sel
.selType
== Selection::selStream
&& (modifiers
& SCI_ALT
) && mouseSelectionRectangularSwitch
) {
4720 sel
.selType
= Selection::selRectangle
;
4722 if (sel
.IsRectangular()) {
4723 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
4724 SetSelection(movePos
, sel
.RangeMain().anchor
);
4725 } else if (sel
.Count() > 1) {
4726 InvalidateSelection(sel
.RangeMain(), false);
4727 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
4728 sel
.TentativeSelection(range
);
4729 InvalidateSelection(range
, true);
4731 SetSelection(movePos
, sel
.RangeMain().anchor
);
4733 } else if (selectionType
== selWord
) {
4734 // Continue selecting by word
4735 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
4736 // No need to do anything. Previously this case was lumped
4737 // in with "Moved forward", but that can be harmful in this
4738 // case: a handler for the NotifyDoubleClick re-adjusts
4739 // the selection for a fancier definition of "word" (for
4740 // example, in Perl it is useful to include the leading
4741 // '$', '%' or '@' on variables for word selection). In this
4742 // the ButtonMove() called via Tick() for auto-scrolling
4743 // could result in the fancier word selection adjustment
4746 wordSelectInitialCaretPos
= -1;
4747 WordSelection(movePos
.Position());
4750 // Continue selecting by line
4751 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4756 int lineMove
= DisplayFromPosition(movePos
.Position());
4757 if (pt
.y
> rcClient
.bottom
) {
4758 ScrollTo(lineMove
- LinesOnScreen() + 1);
4760 } else if (pt
.y
< rcClient
.top
) {
4764 EnsureCaretVisible(false, false, true);
4766 if (hotspot
.Valid() && !PointIsHotspot(pt
))
4767 SetHotSpotRange(NULL
);
4769 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,true) != hotSpotClickPos
) {
4770 if (inDragDrop
== ddNone
) {
4771 DisplayCursor(Window::cursorText
);
4773 hotSpotClickPos
= INVALID_POSITION
;
4777 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4778 if (PointInSelMargin(pt
)) {
4779 DisplayCursor(GetMarginCursor(pt
));
4780 SetHotSpotRange(NULL
);
4781 return; // No need to test for selection
4784 // Display regular (drag) cursor over selection
4785 if (PointInSelection(pt
) && !SelectionEmpty()) {
4786 DisplayCursor(Window::cursorArrow
);
4788 SetHoverIndicatorPoint(pt
);
4789 if (PointIsHotspot(pt
)) {
4790 DisplayCursor(Window::cursorHand
);
4791 SetHotSpotRange(&pt
);
4793 if (hoverIndicatorPos
!= invalidPosition
)
4794 DisplayCursor(Window::cursorHand
);
4796 DisplayCursor(Window::cursorText
);
4797 SetHotSpotRange(NULL
);
4803 void Editor::ButtonMove(Point pt
) {
4804 ButtonMoveWithModifiers(pt
, 0);
4807 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4808 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
4809 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
4810 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4811 if (hoverIndicatorPos
!= INVALID_POSITION
)
4812 InvalidateRange(newPos
.Position(), newPos
.Position() + 1);
4813 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4814 if (inDragDrop
== ddInitial
) {
4815 inDragDrop
= ddNone
;
4816 SetEmptySelection(newPos
);
4817 selectionType
= selChar
;
4818 originalAnchorPos
= sel
.MainCaret();
4820 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
4821 hotSpotClickPos
= INVALID_POSITION
;
4822 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4823 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4824 NotifyHotSpotReleaseClick(newCharPos
.Position(), ctrl
? SCI_CTRL
: 0);
4826 if (HaveMouseCapture()) {
4827 if (PointInSelMargin(pt
)) {
4828 DisplayCursor(GetMarginCursor(pt
));
4830 DisplayCursor(Window::cursorText
);
4831 SetHotSpotRange(NULL
);
4834 SetMouseCapture(false);
4835 if (FineTickerAvailable()) {
4836 FineTickerCancel(tickScroll
);
4838 NotifyIndicatorClick(false, newPos
.Position(), 0);
4839 if (inDragDrop
== ddDragging
) {
4840 SelectionPosition selStart
= SelectionStart();
4841 SelectionPosition selEnd
= SelectionEnd();
4842 if (selStart
< selEnd
) {
4843 if (drag
.Length()) {
4844 const int length
= static_cast<int>(drag
.Length());
4846 const int lengthInserted
= pdoc
->InsertString(
4847 newPos
.Position(), drag
.Data(), length
);
4848 if (lengthInserted
> 0) {
4849 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4851 } else if (newPos
< selStart
) {
4852 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4853 const int lengthInserted
= pdoc
->InsertString(
4854 newPos
.Position(), drag
.Data(), length
);
4855 if (lengthInserted
> 0) {
4856 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4858 } else if (newPos
> selEnd
) {
4859 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4860 newPos
.Add(-static_cast<int>(drag
.Length()));
4861 const int lengthInserted
= pdoc
->InsertString(
4862 newPos
.Position(), drag
.Data(), length
);
4863 if (lengthInserted
> 0) {
4864 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4867 SetEmptySelection(newPos
.Position());
4871 selectionType
= selChar
;
4874 if (selectionType
== selChar
) {
4875 if (sel
.Count() > 1) {
4877 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
4878 InvalidateWholeSelection();
4880 SetSelection(newPos
, sel
.RangeMain().anchor
);
4883 sel
.CommitTentative();
4885 SetRectangularRange();
4886 lastClickTime
= curTime
;
4888 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4889 if (sel
.selType
== Selection::selStream
) {
4892 inDragDrop
= ddNone
;
4893 EnsureCaretVisible(false);
4897 // Called frequently to perform background UI including
4898 // caret blinking and automatic scrolling.
4899 void Editor::Tick() {
4900 if (HaveMouseCapture()) {
4902 ButtonMove(ptMouseLast
);
4904 if (caret
.period
> 0) {
4905 timer
.ticksToWait
-= timer
.tickSize
;
4906 if (timer
.ticksToWait
<= 0) {
4907 caret
.on
= !caret
.on
;
4908 timer
.ticksToWait
= caret
.period
;
4914 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
4915 scrollWidth
= view
.lineWidthMaxSeen
;
4918 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4919 (ticksToDwell
> 0) &&
4920 (!HaveMouseCapture()) &&
4921 (ptMouseLast
.y
>= 0)) {
4922 ticksToDwell
-= timer
.tickSize
;
4923 if (ticksToDwell
<= 0) {
4925 NotifyDwelling(ptMouseLast
, dwelling
);
4930 bool Editor::Idle() {
4931 bool needWrap
= Wrapping() && wrapPending
.NeedsWrap();
4934 // Wrap lines during idle.
4935 WrapLines(WrapScope::wsIdle
);
4937 needWrap
= wrapPending
.NeedsWrap();
4938 } else if (needIdleStyling
) {
4942 // Add more idle things to do here, but make sure idleDone is
4943 // set correctly before the function returns. returning
4944 // false will stop calling this idle function until SetIdle() is
4947 const bool idleDone
= !needWrap
&& !needIdleStyling
; // && thatDone && theOtherThingDone...
4952 void Editor::SetTicking(bool) {
4953 // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
4954 // derived platform class but fine grained timers should now be implemented.
4955 // Either way, execution should not arrive here so assert failure.
4959 void Editor::TickFor(TickReason reason
) {
4962 caret
.on
= !caret
.on
;
4969 ButtonMove(ptMouseLast
);
4973 FineTickerCancel(tickWiden
);
4976 if ((!HaveMouseCapture()) &&
4977 (ptMouseLast
.y
>= 0)) {
4979 NotifyDwelling(ptMouseLast
, dwelling
);
4981 FineTickerCancel(tickDwell
);
4984 // tickPlatform handled by subclass
4989 bool Editor::FineTickerAvailable() {
4993 // FineTickerStart is be overridden by subclasses that support fine ticking so
4994 // this method should never be called.
4995 bool Editor::FineTickerRunning(TickReason
) {
5000 // FineTickerStart is be overridden by subclasses that support fine ticking so
5001 // this method should never be called.
5002 void Editor::FineTickerStart(TickReason
, int, int) {
5006 // FineTickerCancel is be overridden by subclasses that support fine ticking so
5007 // this method should never be called.
5008 void Editor::FineTickerCancel(TickReason
) {
5012 void Editor::SetFocusState(bool focusState
) {
5013 hasFocus
= focusState
;
5014 NotifyFocus(hasFocus
);
5018 ShowCaretAtCurrentPosition();
5021 int Editor::PositionAfterArea(PRectangle rcArea
) const {
5022 // The start of the document line after the display line after the area
5023 // This often means that the line after a modification is restyled which helps
5024 // detect multiline comment additions and heals single line comments
5025 int lineAfter
= TopLineOfMain() + static_cast<int>(rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
5026 if (lineAfter
< cs
.LinesDisplayed())
5027 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
5029 return pdoc
->Length();
5032 // Style to a position within the view. If this causes a change at end of last line then
5033 // affects later lines so style all the viewed text.
5034 void Editor::StyleToPositionInView(Position pos
) {
5035 int endWindow
= PositionAfterArea(GetClientDrawingRectangle());
5036 if (pos
> endWindow
)
5038 const int styleAtEnd
= pdoc
->StyleIndexAt(pos
-1);
5039 pdoc
->EnsureStyledTo(pos
);
5040 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleIndexAt(pos
-1))) {
5041 // Style at end of line changed so is multi-line change like starting a comment
5042 // so require rest of window to be styled.
5043 DiscardOverdraw(); // Prepared bitmaps may be invalid
5044 // DiscardOverdraw may have truncated client drawing area so recalculate endWindow
5045 endWindow
= PositionAfterArea(GetClientDrawingRectangle());
5046 pdoc
->EnsureStyledTo(endWindow
);
5050 int Editor::PositionAfterMaxStyling(int posMax
, bool scrolling
) const {
5051 if ((idleStyling
== SC_IDLESTYLING_NONE
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5052 // Both states do not limit styling
5056 // Try to keep time taken by styling reasonable so interaction remains smooth.
5057 // When scrolling, allow less time to ensure responsive
5058 const double secondsAllowed
= scrolling
? 0.005 : 0.02;
5060 const int linesToStyle
= Platform::Clamp(static_cast<int>(secondsAllowed
/ pdoc
->durationStyleOneLine
),
5062 const int stylingMaxLine
= std::min(
5063 static_cast<int>(pdoc
->LineFromPosition(pdoc
->GetEndStyled()) + linesToStyle
),
5064 pdoc
->LinesTotal());
5065 return std::min(static_cast<int>(pdoc
->LineStart(stylingMaxLine
)), posMax
);
5068 void Editor::StartIdleStyling(bool truncatedLastStyling
) {
5069 if ((idleStyling
== SC_IDLESTYLING_ALL
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5070 if (pdoc
->GetEndStyled() < pdoc
->Length()) {
5071 // Style remainder of document in idle time
5072 needIdleStyling
= true;
5074 } else if (truncatedLastStyling
) {
5075 needIdleStyling
= true;
5078 if (needIdleStyling
) {
5083 // Style for an area but bound the amount of styling to remain responsive
5084 void Editor::StyleAreaBounded(PRectangle rcArea
, bool scrolling
) {
5085 const int posAfterArea
= PositionAfterArea(rcArea
);
5086 const int posAfterMax
= PositionAfterMaxStyling(posAfterArea
, scrolling
);
5087 if (posAfterMax
< posAfterArea
) {
5088 // Idle styling may be performed before current visible area
5089 // Style a bit now then style further in idle time
5090 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5092 // Can style all wanted now.
5093 StyleToPositionInView(posAfterArea
);
5095 StartIdleStyling(posAfterMax
< posAfterArea
);
5098 void Editor::IdleStyling() {
5099 const int posAfterArea
= PositionAfterArea(GetClientRectangle());
5100 const int endGoal
= (idleStyling
>= SC_IDLESTYLING_AFTERVISIBLE
) ?
5101 pdoc
->Length() : posAfterArea
;
5102 const int posAfterMax
= PositionAfterMaxStyling(endGoal
, false);
5103 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5104 if (pdoc
->GetEndStyled() >= endGoal
) {
5105 needIdleStyling
= false;
5109 void Editor::IdleWork() {
5110 // Style the line after the modification as this allows modifications that change just the
5111 // line of the modification to heal instead of propagating to the rest of the window.
5112 if (workNeeded
.items
& WorkNeeded::workStyle
) {
5113 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(workNeeded
.upTo
) + 2));
5119 void Editor::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
5120 workNeeded
.Need(items
, upTo
);
5123 bool Editor::PaintContains(PRectangle rc
) {
5127 return rcPaint
.Contains(rc
);
5131 bool Editor::PaintContainsMargin() {
5132 if (wMargin
.GetID()) {
5133 // With separate margin view, paint of text view
5134 // never contains margin.
5137 PRectangle rcSelMargin
= GetClientRectangle();
5138 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
);
5139 return PaintContains(rcSelMargin
);
5142 void Editor::CheckForChangeOutsidePaint(Range r
) {
5143 if (paintState
== painting
&& !paintingAllText
) {
5144 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5148 PRectangle rcRange
= RectangleFromRange(r
, 0);
5149 PRectangle rcText
= GetTextRectangle();
5150 if (rcRange
.top
< rcText
.top
) {
5151 rcRange
.top
= rcText
.top
;
5153 if (rcRange
.bottom
> rcText
.bottom
) {
5154 rcRange
.bottom
= rcText
.bottom
;
5157 if (!PaintContains(rcRange
)) {
5159 paintAbandonedByStyling
= true;
5164 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5165 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5166 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5167 CheckForChangeOutsidePaint(Range(braces
[0]));
5168 CheckForChangeOutsidePaint(Range(pos0
));
5171 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5172 CheckForChangeOutsidePaint(Range(braces
[1]));
5173 CheckForChangeOutsidePaint(Range(pos1
));
5176 bracesMatchStyle
= matchStyle
;
5177 if (paintState
== notPainting
) {
5183 void Editor::SetAnnotationHeights(int start
, int end
) {
5184 if (vs
.annotationVisible
) {
5186 bool changedHeight
= false;
5187 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
5188 int linesWrapped
= 1;
5190 AutoSurface
surface(this);
5191 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5192 if (surface
&& ll
) {
5193 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5194 linesWrapped
= ll
->lines
;
5197 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
5198 changedHeight
= true;
5200 if (changedHeight
) {
5206 void Editor::SetDocPointer(Document
*document
) {
5207 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5208 pdoc
->RemoveWatcher(this, 0);
5210 if (document
== NULL
) {
5211 pdoc
= new Document();
5217 // Ensure all positions within document
5222 braces
[0] = invalidPosition
;
5223 braces
[1] = invalidPosition
;
5225 vs
.ReleaseAllExtendedStyles();
5227 SetRepresentations();
5229 // Reset the contraction state to fully shown.
5231 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5232 SetAnnotationHeights(0, pdoc
->LinesTotal());
5233 view
.llc
.Deallocate();
5236 hotspot
= Range(invalidPosition
);
5237 hoverIndicatorPos
= invalidPosition
;
5239 view
.ClearAllTabstops();
5241 pdoc
->AddWatcher(this, 0);
5246 void Editor::SetAnnotationVisible(int visible
) {
5247 if (vs
.annotationVisible
!= visible
) {
5248 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
5249 vs
.annotationVisible
= visible
;
5250 if (changedFromOrToHidden
) {
5251 int dir
= vs
.annotationVisible
? 1 : -1;
5252 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
5253 int annotationLines
= pdoc
->AnnotationLines(line
);
5254 if (annotationLines
> 0) {
5255 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
5264 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5266 int Editor::ExpandLine(int line
) {
5267 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5269 while (line
<= lineMaxSubord
) {
5270 cs
.SetVisible(line
, line
, true);
5271 int level
= pdoc
->GetLevel(line
);
5272 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5273 if (cs
.GetExpanded(line
)) {
5274 line
= ExpandLine(line
);
5276 line
= pdoc
->GetLastChild(line
);
5281 return lineMaxSubord
;
5284 void Editor::SetFoldExpanded(int lineDoc
, bool expanded
) {
5285 if (cs
.SetExpanded(lineDoc
, expanded
)) {
5290 void Editor::FoldLine(int line
, int action
) {
5292 if (action
== SC_FOLDACTION_TOGGLE
) {
5293 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5294 line
= pdoc
->GetFoldParent(line
);
5298 action
= (cs
.GetExpanded(line
)) ? SC_FOLDACTION_CONTRACT
: SC_FOLDACTION_EXPAND
;
5301 if (action
== SC_FOLDACTION_CONTRACT
) {
5302 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5303 if (lineMaxSubord
> line
) {
5304 cs
.SetExpanded(line
, 0);
5305 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5307 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
5308 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5309 // This does not re-expand the fold
5310 EnsureCaretVisible();
5315 if (!(cs
.GetVisible(line
))) {
5316 EnsureLineVisible(line
, false);
5319 cs
.SetExpanded(line
, 1);
5328 void Editor::FoldExpand(int line
, int action
, int level
) {
5329 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5330 if (action
== SC_FOLDACTION_TOGGLE
) {
5331 expanding
= !cs
.GetExpanded(line
);
5333 // Ensure child lines lexed and fold information extracted before
5334 // flipping the state.
5335 pdoc
->GetLastChild(line
, LevelNumber(level
));
5336 SetFoldExpanded(line
, expanding
);
5337 if (expanding
&& (cs
.HiddenLines() == 0))
5340 int lineMaxSubord
= pdoc
->GetLastChild(line
, LevelNumber(level
));
5342 cs
.SetVisible(line
, lineMaxSubord
, expanding
);
5343 while (line
<= lineMaxSubord
) {
5344 int levelLine
= pdoc
->GetLevel(line
);
5345 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5346 SetFoldExpanded(line
, expanding
);
5354 int Editor::ContractedFoldNext(int lineStart
) const {
5355 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
5356 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
5358 line
= cs
.ContractedNext(line
+1);
5367 * Recurse up from this line to find any folds that prevent this line from being visible
5368 * and unfold them all.
5370 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5372 // In case in need of wrapping to ensure DisplayFromDoc works.
5373 if (lineDoc
>= wrapPending
.start
)
5374 WrapLines(WrapScope::wsAll
);
5376 if (!cs
.GetVisible(lineDoc
)) {
5377 // Back up to find a non-blank line
5378 int lookLine
= lineDoc
;
5379 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
5380 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
5381 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
5383 int lineParent
= pdoc
->GetFoldParent(lookLine
);
5384 if (lineParent
< 0) {
5385 // Backed up to a top level line, so try to find parent of initial line
5386 lineParent
= pdoc
->GetFoldParent(lineDoc
);
5388 if (lineParent
>= 0) {
5389 if (lineDoc
!= lineParent
)
5390 EnsureLineVisible(lineParent
, enforcePolicy
);
5391 if (!cs
.GetExpanded(lineParent
)) {
5392 cs
.SetExpanded(lineParent
, 1);
5393 ExpandLine(lineParent
);
5399 if (enforcePolicy
) {
5400 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5401 if (visiblePolicy
& VISIBLE_SLOP
) {
5402 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5403 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5404 SetVerticalScrollPos();
5406 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5407 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5408 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5409 SetVerticalScrollPos();
5413 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5414 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5415 SetVerticalScrollPos();
5422 void Editor::FoldAll(int action
) {
5423 pdoc
->EnsureStyledTo(pdoc
->Length());
5424 int maxLine
= pdoc
->LinesTotal();
5425 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5426 if (action
== SC_FOLDACTION_TOGGLE
) {
5427 // Discover current state
5428 for (int lineSeek
= 0; lineSeek
< maxLine
; lineSeek
++) {
5429 if (pdoc
->GetLevel(lineSeek
) & SC_FOLDLEVELHEADERFLAG
) {
5430 expanding
= !cs
.GetExpanded(lineSeek
);
5436 cs
.SetVisible(0, maxLine
-1, true);
5437 for (int line
= 0; line
< maxLine
; line
++) {
5438 int levelLine
= pdoc
->GetLevel(line
);
5439 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5440 SetFoldExpanded(line
, true);
5444 for (int line
= 0; line
< maxLine
; line
++) {
5445 int level
= pdoc
->GetLevel(line
);
5446 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
5447 (SC_FOLDLEVELBASE
== LevelNumber(level
))) {
5448 SetFoldExpanded(line
, false);
5449 int lineMaxSubord
= pdoc
->GetLastChild(line
, -1);
5450 if (lineMaxSubord
> line
) {
5451 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5460 void Editor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
5461 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
5462 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
5463 // Adding a fold point.
5464 if (cs
.SetExpanded(line
, true)) {
5467 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5469 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
5470 const int prevLine
= line
- 1;
5471 const int prevLineLevel
= pdoc
->GetLevel(prevLine
);
5473 // Combining two blocks where the first block is collapsed (e.g. by deleting the line(s) which separate(s) the two blocks)
5474 if ((LevelNumber(prevLineLevel
) == LevelNumber(levelNow
)) && !cs
.GetVisible(prevLine
))
5475 FoldLine(pdoc
->GetFoldParent(prevLine
), SC_FOLDACTION_EXPAND
);
5477 if (!cs
.GetExpanded(line
)) {
5478 // Removing the fold from one that has been contracted so should expand
5479 // otherwise lines are left invisible with no way to make them visible
5480 if (cs
.SetExpanded(line
, true)) {
5483 // Combining two blocks where the second one is collapsed (e.g. by adding characters in the line which separates the two blocks)
5484 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5487 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) &&
5488 (LevelNumber(levelPrev
) > LevelNumber(levelNow
))) {
5489 if (cs
.HiddenLines()) {
5490 // See if should still be hidden
5491 int parentLine
= pdoc
->GetFoldParent(line
);
5492 if ((parentLine
< 0) || (cs
.GetExpanded(parentLine
) && cs
.GetVisible(parentLine
))) {
5493 cs
.SetVisible(line
, line
, true);
5500 // Combining two blocks where the first one is collapsed (e.g. by adding characters in the line which separates the two blocks)
5501 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) && (LevelNumber(levelPrev
) < LevelNumber(levelNow
))) {
5502 if (cs
.HiddenLines()) {
5503 const int parentLine
= pdoc
->GetFoldParent(line
);
5504 if (!cs
.GetExpanded(parentLine
) && cs
.GetVisible(line
))
5505 FoldLine(parentLine
, SC_FOLDACTION_EXPAND
);
5510 void Editor::NeedShown(int pos
, int len
) {
5511 if (foldAutomatic
& SC_AUTOMATICFOLD_SHOW
) {
5512 int lineStart
= pdoc
->LineFromPosition(pos
);
5513 int lineEnd
= pdoc
->LineFromPosition(pos
+len
);
5514 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
5515 EnsureLineVisible(line
, false);
5518 NotifyNeedShown(pos
, len
);
5522 int Editor::GetTag(char *tagValue
, int tagNumber
) {
5523 const char *text
= 0;
5525 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
5526 char name
[3] = "\\?";
5527 name
[1] = static_cast<char>(tagNumber
+ '0');
5529 text
= pdoc
->SubstituteByPosition(name
, &length
);
5533 memcpy(tagValue
, text
, length
+ 1);
5540 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5543 length
= istrlen(text
);
5544 if (replacePatterns
) {
5545 text
= pdoc
->SubstituteByPosition(text
, &length
);
5550 if (targetStart
!= targetEnd
)
5551 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5552 targetEnd
= targetStart
;
5553 const int lengthInserted
= pdoc
->InsertString(targetStart
, text
, length
);
5554 targetEnd
= targetStart
+ lengthInserted
;
5558 bool Editor::IsUnicodeMode() const {
5559 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5562 int Editor::CodePage() const {
5564 return pdoc
->dbcsCodePage
;
5569 int Editor::WrapCount(int line
) {
5570 AutoSurface
surface(this);
5571 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5573 if (surface
&& ll
) {
5574 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5581 void Editor::AddStyledText(char *buffer
, int appendLength
) {
5582 // The buffer consists of alternating character bytes and style bytes
5583 int textLength
= appendLength
/ 2;
5584 std::string
text(textLength
, '\0');
5586 for (i
= 0; i
< textLength
; i
++) {
5587 text
[i
] = buffer
[i
*2];
5589 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), text
.c_str(), textLength
);
5590 for (i
= 0; i
< textLength
; i
++) {
5591 text
[i
] = buffer
[i
*2+1];
5593 pdoc
->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
5594 pdoc
->SetStyles(textLength
, text
.c_str());
5595 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5598 bool Editor::ValidMargin(uptr_t wParam
) const {
5599 return wParam
< vs
.ms
.size();
5602 static char *CharPtrFromSPtr(sptr_t lParam
) {
5603 return reinterpret_cast<char *>(lParam
);
5606 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5607 vs
.EnsureStyle(wParam
);
5609 case SCI_STYLESETFORE
:
5610 vs
.styles
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
5612 case SCI_STYLESETBACK
:
5613 vs
.styles
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
5615 case SCI_STYLESETBOLD
:
5616 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
5618 case SCI_STYLESETWEIGHT
:
5619 vs
.styles
[wParam
].weight
= static_cast<int>(lParam
);
5621 case SCI_STYLESETITALIC
:
5622 vs
.styles
[wParam
].italic
= lParam
!= 0;
5624 case SCI_STYLESETEOLFILLED
:
5625 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5627 case SCI_STYLESETSIZE
:
5628 vs
.styles
[wParam
].size
= static_cast<int>(lParam
* SC_FONT_SIZE_MULTIPLIER
);
5630 case SCI_STYLESETSIZEFRACTIONAL
:
5631 vs
.styles
[wParam
].size
= static_cast<int>(lParam
);
5633 case SCI_STYLESETFONT
:
5635 vs
.SetStyleFontName(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5638 case SCI_STYLESETUNDERLINE
:
5639 vs
.styles
[wParam
].underline
= lParam
!= 0;
5641 case SCI_STYLESETCASE
:
5642 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5644 case SCI_STYLESETCHARACTERSET
:
5645 vs
.styles
[wParam
].characterSet
= static_cast<int>(lParam
);
5646 pdoc
->SetCaseFolder(NULL
);
5648 case SCI_STYLESETVISIBLE
:
5649 vs
.styles
[wParam
].visible
= lParam
!= 0;
5651 case SCI_STYLESETCHANGEABLE
:
5652 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5654 case SCI_STYLESETHOTSPOT
:
5655 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5658 InvalidateStyleRedraw();
5661 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5662 vs
.EnsureStyle(wParam
);
5664 case SCI_STYLEGETFORE
:
5665 return vs
.styles
[wParam
].fore
.AsLong();
5666 case SCI_STYLEGETBACK
:
5667 return vs
.styles
[wParam
].back
.AsLong();
5668 case SCI_STYLEGETBOLD
:
5669 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
5670 case SCI_STYLEGETWEIGHT
:
5671 return vs
.styles
[wParam
].weight
;
5672 case SCI_STYLEGETITALIC
:
5673 return vs
.styles
[wParam
].italic
? 1 : 0;
5674 case SCI_STYLEGETEOLFILLED
:
5675 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5676 case SCI_STYLEGETSIZE
:
5677 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
5678 case SCI_STYLEGETSIZEFRACTIONAL
:
5679 return vs
.styles
[wParam
].size
;
5680 case SCI_STYLEGETFONT
:
5681 return StringResult(lParam
, vs
.styles
[wParam
].fontName
);
5682 case SCI_STYLEGETUNDERLINE
:
5683 return vs
.styles
[wParam
].underline
? 1 : 0;
5684 case SCI_STYLEGETCASE
:
5685 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5686 case SCI_STYLEGETCHARACTERSET
:
5687 return vs
.styles
[wParam
].characterSet
;
5688 case SCI_STYLEGETVISIBLE
:
5689 return vs
.styles
[wParam
].visible
? 1 : 0;
5690 case SCI_STYLEGETCHANGEABLE
:
5691 return vs
.styles
[wParam
].changeable
? 1 : 0;
5692 case SCI_STYLEGETHOTSPOT
:
5693 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5698 void Editor::SetSelectionNMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5699 InvalidateRange(sel
.Range(wParam
).Start().Position(), sel
.Range(wParam
).End().Position());
5702 case SCI_SETSELECTIONNCARET
:
5703 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
5706 case SCI_SETSELECTIONNANCHOR
:
5707 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
5710 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
5711 sel
.Range(wParam
).caret
.SetVirtualSpace(static_cast<int>(lParam
));
5714 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
5715 sel
.Range(wParam
).anchor
.SetVirtualSpace(static_cast<int>(lParam
));
5718 case SCI_SETSELECTIONNSTART
:
5719 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
5722 case SCI_SETSELECTIONNEND
:
5723 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
5727 InvalidateRange(sel
.Range(wParam
).Start().Position(), sel
.Range(wParam
).End().Position());
5728 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
5731 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
5732 const size_t len
= val
? strlen(val
) : 0;
5734 char *ptr
= CharPtrFromSPtr(lParam
);
5736 memcpy(ptr
, val
, len
+1);
5740 return len
; // Not including NUL
5743 sptr_t
Editor::BytesResult(sptr_t lParam
, const unsigned char *val
, size_t len
) {
5744 // No NUL termination: len is number of valid/displayed bytes
5745 if ((lParam
) && (len
> 0)) {
5746 char *ptr
= CharPtrFromSPtr(lParam
);
5748 memcpy(ptr
, val
, len
);
5752 return val
? len
: 0;
5755 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5756 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5758 // Optional macro recording hook
5760 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5766 return pdoc
->Length() + 1;
5769 char *ptr
= CharPtrFromSPtr(lParam
);
5770 unsigned int iChar
= 0;
5771 for (; iChar
< wParam
- 1; iChar
++)
5772 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5781 pdoc
->DeleteChars(0, pdoc
->Length());
5782 SetEmptySelection(0);
5783 const char *text
= CharPtrFromSPtr(lParam
);
5784 pdoc
->InsertString(0, text
, istrlen(text
));
5788 case SCI_GETTEXTLENGTH
:
5789 return pdoc
->Length();
5800 case SCI_COPYALLOWLINE
:
5804 case SCI_VERTICALCENTRECARET
:
5805 VerticalCentreCaret();
5808 case SCI_MOVESELECTEDLINESUP
:
5809 MoveSelectedLinesUp();
5812 case SCI_MOVESELECTEDLINESDOWN
:
5813 MoveSelectedLinesDown();
5817 CopyRangeToClipboard(static_cast<int>(wParam
), static_cast<int>(lParam
));
5821 CopyText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5826 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5829 EnsureCaretVisible();
5835 EnsureCaretVisible();
5844 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5846 case SCI_EMPTYUNDOBUFFER
:
5847 pdoc
->DeleteUndoHistory();
5850 case SCI_GETFIRSTVISIBLELINE
:
5853 case SCI_SETFIRSTVISIBLELINE
:
5854 ScrollTo(static_cast<int>(wParam
));
5857 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5858 int lineStart
= pdoc
->LineStart(static_cast<int>(wParam
));
5859 int lineEnd
= pdoc
->LineStart(static_cast<int>(wParam
+ 1));
5861 return lineEnd
- lineStart
;
5863 char *ptr
= CharPtrFromSPtr(lParam
);
5865 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5866 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5871 case SCI_GETLINECOUNT
:
5872 if (pdoc
->LinesTotal() == 0)
5875 return pdoc
->LinesTotal();
5878 return !pdoc
->IsSavePoint();
5881 int nStart
= static_cast<int>(wParam
);
5882 int nEnd
= static_cast<int>(lParam
);
5884 nEnd
= pdoc
->Length();
5886 nStart
= nEnd
; // Remove selection
5887 InvalidateSelection(SelectionRange(nStart
, nEnd
));
5889 sel
.selType
= Selection::selStream
;
5890 SetSelection(nEnd
, nStart
);
5891 EnsureCaretVisible();
5895 case SCI_GETSELTEXT
: {
5896 SelectionText selectedText
;
5897 CopySelectionRange(&selectedText
);
5899 return selectedText
.LengthWithTerminator();
5901 char *ptr
= CharPtrFromSPtr(lParam
);
5902 unsigned int iChar
= 0;
5903 if (selectedText
.Length()) {
5904 for (; iChar
< selectedText
.LengthWithTerminator(); iChar
++)
5905 ptr
[iChar
] = selectedText
.Data()[iChar
];
5913 case SCI_LINEFROMPOSITION
:
5914 if (static_cast<int>(wParam
) < 0)
5916 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
5918 case SCI_POSITIONFROMLINE
:
5919 if (static_cast<int>(wParam
) < 0)
5920 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
5922 return 0; // Even if there is no text, there is a first line that starts at 0
5923 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5925 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5927 return pdoc
->LineStart(static_cast<int>(wParam
));
5929 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5930 case SCI_LINELENGTH
:
5931 if ((static_cast<int>(wParam
) < 0) ||
5932 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5934 return pdoc
->LineStart(static_cast<int>(wParam
) + 1) - pdoc
->LineStart(static_cast<int>(wParam
));
5936 case SCI_REPLACESEL
: {
5941 char *replacement
= CharPtrFromSPtr(lParam
);
5942 const int lengthInserted
= pdoc
->InsertString(
5943 sel
.MainCaret(), replacement
, istrlen(replacement
));
5944 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5945 EnsureCaretVisible();
5949 case SCI_SETTARGETSTART
:
5950 targetStart
= static_cast<int>(wParam
);
5953 case SCI_GETTARGETSTART
:
5956 case SCI_SETTARGETEND
:
5957 targetEnd
= static_cast<int>(wParam
);
5960 case SCI_GETTARGETEND
:
5963 case SCI_SETTARGETRANGE
:
5964 targetStart
= static_cast<int>(wParam
);
5965 targetEnd
= static_cast<int>(lParam
);
5968 case SCI_TARGETWHOLEDOCUMENT
:
5970 targetEnd
= pdoc
->Length();
5973 case SCI_TARGETFROMSELECTION
:
5974 if (sel
.MainCaret() < sel
.MainAnchor()) {
5975 targetStart
= sel
.MainCaret();
5976 targetEnd
= sel
.MainAnchor();
5978 targetStart
= sel
.MainAnchor();
5979 targetEnd
= sel
.MainCaret();
5983 case SCI_GETTARGETTEXT
: {
5984 std::string text
= RangeText(targetStart
, targetEnd
);
5985 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(text
.c_str()), text
.length());
5988 case SCI_REPLACETARGET
:
5989 PLATFORM_ASSERT(lParam
);
5990 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5992 case SCI_REPLACETARGETRE
:
5993 PLATFORM_ASSERT(lParam
);
5994 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5996 case SCI_SEARCHINTARGET
:
5997 PLATFORM_ASSERT(lParam
);
5998 return SearchInTarget(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6000 case SCI_SETSEARCHFLAGS
:
6001 searchFlags
= static_cast<int>(wParam
);
6004 case SCI_GETSEARCHFLAGS
:
6008 return GetTag(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6010 case SCI_POSITIONBEFORE
:
6011 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) - 1, -1, true);
6013 case SCI_POSITIONAFTER
:
6014 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) + 1, 1, true);
6016 case SCI_POSITIONRELATIVE
:
6017 return Platform::Clamp(pdoc
->GetRelativePosition(static_cast<int>(wParam
), static_cast<int>(lParam
)), 0, pdoc
->Length());
6019 case SCI_LINESCROLL
:
6020 ScrollTo(topLine
+ static_cast<int>(lParam
));
6021 HorizontalScrollTo(xOffset
+ static_cast<int>(wParam
)* static_cast<int>(vs
.spaceWidth
));
6024 case SCI_SETXOFFSET
:
6025 xOffset
= static_cast<int>(wParam
);
6026 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6027 SetHorizontalScrollPos();
6031 case SCI_GETXOFFSET
:
6034 case SCI_CHOOSECARETX
:
6038 case SCI_SCROLLCARET
:
6039 EnsureCaretVisible();
6042 case SCI_SETREADONLY
:
6043 pdoc
->SetReadOnly(wParam
!= 0);
6046 case SCI_GETREADONLY
:
6047 return pdoc
->IsReadOnly();
6052 case SCI_POINTXFROMPOSITION
:
6056 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
6057 // Convert to view-relative
6058 return static_cast<int>(pt
.x
) - vs
.textStart
+ vs
.fixedColumnWidth
;
6061 case SCI_POINTYFROMPOSITION
:
6065 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
6066 return static_cast<int>(pt
.y
);
6070 return FindText(wParam
, lParam
);
6072 case SCI_GETTEXTRANGE
: {
6075 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6076 int cpMax
= static_cast<int>(tr
->chrg
.cpMax
);
6078 cpMax
= pdoc
->Length();
6079 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
6080 int len
= static_cast<int>(cpMax
- tr
->chrg
.cpMin
); // No -1 as cpMin and cpMax are referring to inter character positions
6081 pdoc
->GetCharRange(tr
->lpstrText
, static_cast<int>(tr
->chrg
.cpMin
), len
);
6082 // Spec says copied text is terminated with a NUL
6083 tr
->lpstrText
[len
] = '\0';
6084 return len
; // Not including NUL
6087 case SCI_HIDESELECTION
:
6088 view
.hideSelection
= wParam
!= 0;
6092 case SCI_FORMATRANGE
:
6093 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
6095 case SCI_GETMARGINLEFT
:
6096 return vs
.leftMarginWidth
;
6098 case SCI_GETMARGINRIGHT
:
6099 return vs
.rightMarginWidth
;
6101 case SCI_SETMARGINLEFT
:
6102 lastXChosen
+= static_cast<int>(lParam
) - vs
.leftMarginWidth
;
6103 vs
.leftMarginWidth
= static_cast<int>(lParam
);
6104 InvalidateStyleRedraw();
6107 case SCI_SETMARGINRIGHT
:
6108 vs
.rightMarginWidth
= static_cast<int>(lParam
);
6109 InvalidateStyleRedraw();
6112 // Control specific mesages
6117 const int lengthInserted
= pdoc
->InsertString(
6118 CurrentPosition(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6119 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
6123 case SCI_ADDSTYLEDTEXT
:
6125 AddStyledText(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6128 case SCI_INSERTTEXT
: {
6131 int insertPos
= static_cast<int>(wParam
);
6132 if (static_cast<int>(wParam
) == -1)
6133 insertPos
= CurrentPosition();
6134 int newCurrent
= CurrentPosition();
6135 char *sz
= CharPtrFromSPtr(lParam
);
6136 const int lengthInserted
= pdoc
->InsertString(insertPos
, sz
, istrlen(sz
));
6137 if (newCurrent
> insertPos
)
6138 newCurrent
+= lengthInserted
;
6139 SetEmptySelection(newCurrent
);
6143 case SCI_CHANGEINSERTION
:
6144 PLATFORM_ASSERT(lParam
);
6145 pdoc
->ChangeInsertion(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6148 case SCI_APPENDTEXT
:
6149 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6156 case SCI_DELETERANGE
:
6157 pdoc
->DeleteChars(static_cast<int>(wParam
), static_cast<int>(lParam
));
6160 case SCI_CLEARDOCUMENTSTYLE
:
6161 ClearDocumentStyle();
6164 case SCI_SETUNDOCOLLECTION
:
6165 pdoc
->SetUndoCollection(wParam
!= 0);
6168 case SCI_GETUNDOCOLLECTION
:
6169 return pdoc
->IsCollectingUndo();
6171 case SCI_BEGINUNDOACTION
:
6172 pdoc
->BeginUndoAction();
6175 case SCI_ENDUNDOACTION
:
6176 pdoc
->EndUndoAction();
6179 case SCI_GETCARETPERIOD
:
6180 return caret
.period
;
6182 case SCI_SETCARETPERIOD
:
6183 CaretSetPeriod(static_cast<int>(wParam
));
6186 case SCI_GETWORDCHARS
:
6187 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
6189 case SCI_SETWORDCHARS
: {
6190 pdoc
->SetDefaultCharClasses(false);
6193 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6197 case SCI_GETWHITESPACECHARS
:
6198 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
6200 case SCI_SETWHITESPACECHARS
: {
6203 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6207 case SCI_GETPUNCTUATIONCHARS
:
6208 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
6210 case SCI_SETPUNCTUATIONCHARS
: {
6213 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
6217 case SCI_SETCHARSDEFAULT
:
6218 pdoc
->SetDefaultCharClasses(true);
6222 return pdoc
->Length();
6225 pdoc
->Allocate(static_cast<int>(wParam
));
6229 return pdoc
->CharAt(static_cast<int>(wParam
));
6231 case SCI_SETCURRENTPOS
:
6232 if (sel
.IsRectangular()) {
6233 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
6234 SetRectangularRange();
6237 SetSelection(static_cast<int>(wParam
), sel
.MainAnchor());
6241 case SCI_GETCURRENTPOS
:
6242 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
6245 if (sel
.IsRectangular()) {
6246 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
6247 SetRectangularRange();
6250 SetSelection(sel
.MainCaret(), static_cast<int>(wParam
));
6255 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
6257 case SCI_SETSELECTIONSTART
:
6258 SetSelection(Platform::Maximum(sel
.MainCaret(), static_cast<int>(wParam
)), static_cast<int>(wParam
));
6261 case SCI_GETSELECTIONSTART
:
6262 return sel
.LimitsForRectangularElseMain().start
.Position();
6264 case SCI_SETSELECTIONEND
:
6265 SetSelection(static_cast<int>(wParam
), Platform::Minimum(sel
.MainAnchor(), static_cast<int>(wParam
)));
6268 case SCI_GETSELECTIONEND
:
6269 return sel
.LimitsForRectangularElseMain().end
.Position();
6271 case SCI_SETEMPTYSELECTION
:
6272 SetEmptySelection(static_cast<int>(wParam
));
6275 case SCI_SETPRINTMAGNIFICATION
:
6276 view
.printParameters
.magnification
= static_cast<int>(wParam
);
6279 case SCI_GETPRINTMAGNIFICATION
:
6280 return view
.printParameters
.magnification
;
6282 case SCI_SETPRINTCOLOURMODE
:
6283 view
.printParameters
.colourMode
= static_cast<int>(wParam
);
6286 case SCI_GETPRINTCOLOURMODE
:
6287 return view
.printParameters
.colourMode
;
6289 case SCI_SETPRINTWRAPMODE
:
6290 view
.printParameters
.wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6293 case SCI_GETPRINTWRAPMODE
:
6294 return view
.printParameters
.wrapState
;
6296 case SCI_GETSTYLEAT
:
6297 if (static_cast<int>(wParam
) >= pdoc
->Length())
6300 return pdoc
->StyleAt(static_cast<int>(wParam
));
6310 case SCI_SETSAVEPOINT
:
6311 pdoc
->SetSavePoint();
6314 case SCI_GETSTYLEDTEXT
: {
6317 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6319 for (long iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6320 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(static_cast<int>(iChar
));
6321 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(static_cast<int>(iChar
));
6323 tr
->lpstrText
[iPlace
] = '\0';
6324 tr
->lpstrText
[iPlace
+ 1] = '\0';
6329 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6331 case SCI_MARKERLINEFROMHANDLE
:
6332 return pdoc
->LineFromHandle(static_cast<int>(wParam
));
6334 case SCI_MARKERDELETEHANDLE
:
6335 pdoc
->DeleteMarkFromHandle(static_cast<int>(wParam
));
6339 return vs
.viewWhitespace
;
6342 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6346 case SCI_GETTABDRAWMODE
:
6347 return vs
.tabDrawMode
;
6349 case SCI_SETTABDRAWMODE
:
6350 vs
.tabDrawMode
= static_cast<TabDrawMode
>(wParam
);
6354 case SCI_GETWHITESPACESIZE
:
6355 return vs
.whitespaceSize
;
6357 case SCI_SETWHITESPACESIZE
:
6358 vs
.whitespaceSize
= static_cast<int>(wParam
);
6362 case SCI_POSITIONFROMPOINT
:
6363 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6366 case SCI_POSITIONFROMPOINTCLOSE
:
6367 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6370 case SCI_CHARPOSITIONFROMPOINT
:
6371 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6374 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
6375 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6379 GoToLine(static_cast<int>(wParam
));
6383 SetEmptySelection(static_cast<int>(wParam
));
6384 EnsureCaretVisible();
6387 case SCI_GETCURLINE
: {
6388 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
6389 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6390 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6392 return 1 + lineEnd
- lineStart
;
6394 PLATFORM_ASSERT(wParam
> 0);
6395 char *ptr
= CharPtrFromSPtr(lParam
);
6396 unsigned int iPlace
= 0;
6397 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6398 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6401 return sel
.MainCaret() - lineStart
;
6404 case SCI_GETENDSTYLED
:
6405 return pdoc
->GetEndStyled();
6407 case SCI_GETEOLMODE
:
6408 return pdoc
->eolMode
;
6410 case SCI_SETEOLMODE
:
6411 pdoc
->eolMode
= static_cast<int>(wParam
);
6414 case SCI_SETLINEENDTYPESALLOWED
:
6415 if (pdoc
->SetLineEndTypesAllowed(static_cast<int>(wParam
))) {
6417 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6418 SetAnnotationHeights(0, pdoc
->LinesTotal());
6419 InvalidateStyleRedraw();
6423 case SCI_GETLINEENDTYPESALLOWED
:
6424 return pdoc
->GetLineEndTypesAllowed();
6426 case SCI_GETLINEENDTYPESACTIVE
:
6427 return pdoc
->GetLineEndTypesActive();
6429 case SCI_STARTSTYLING
:
6430 pdoc
->StartStyling(static_cast<int>(wParam
), static_cast<char>(lParam
));
6433 case SCI_SETSTYLING
:
6434 if (static_cast<int>(wParam
) < 0)
6435 errorStatus
= SC_STATUS_FAILURE
;
6437 pdoc
->SetStyleFor(static_cast<int>(wParam
), static_cast<char>(lParam
));
6440 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6443 pdoc
->SetStyles(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6446 case SCI_SETBUFFEREDDRAW
:
6447 view
.bufferedDraw
= wParam
!= 0;
6450 case SCI_GETBUFFEREDDRAW
:
6451 return view
.bufferedDraw
;
6453 case SCI_GETTWOPHASEDRAW
:
6454 return view
.phasesDraw
== EditView::phasesTwo
;
6456 case SCI_SETTWOPHASEDRAW
:
6457 if (view
.SetTwoPhaseDraw(wParam
!= 0))
6458 InvalidateStyleRedraw();
6461 case SCI_GETPHASESDRAW
:
6462 return view
.phasesDraw
;
6464 case SCI_SETPHASESDRAW
:
6465 if (view
.SetPhasesDraw(static_cast<int>(wParam
)))
6466 InvalidateStyleRedraw();
6469 case SCI_SETFONTQUALITY
:
6470 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
6471 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
6472 InvalidateStyleRedraw();
6475 case SCI_GETFONTQUALITY
:
6476 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
6478 case SCI_SETTABWIDTH
:
6480 pdoc
->tabInChars
= static_cast<int>(wParam
);
6481 if (pdoc
->indentInChars
== 0)
6482 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6484 InvalidateStyleRedraw();
6487 case SCI_GETTABWIDTH
:
6488 return pdoc
->tabInChars
;
6490 case SCI_CLEARTABSTOPS
:
6491 if (view
.ClearTabstops(static_cast<int>(wParam
))) {
6492 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6493 NotifyModified(pdoc
, mh
, NULL
);
6497 case SCI_ADDTABSTOP
:
6498 if (view
.AddTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
))) {
6499 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6500 NotifyModified(pdoc
, mh
, NULL
);
6504 case SCI_GETNEXTTABSTOP
:
6505 return view
.GetNextTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
));
6508 pdoc
->indentInChars
= static_cast<int>(wParam
);
6509 if (pdoc
->indentInChars
!= 0)
6510 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6512 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6513 InvalidateStyleRedraw();
6517 return pdoc
->indentInChars
;
6519 case SCI_SETUSETABS
:
6520 pdoc
->useTabs
= wParam
!= 0;
6521 InvalidateStyleRedraw();
6524 case SCI_GETUSETABS
:
6525 return pdoc
->useTabs
;
6527 case SCI_SETLINEINDENTATION
:
6528 pdoc
->SetLineIndentation(static_cast<int>(wParam
), static_cast<int>(lParam
));
6531 case SCI_GETLINEINDENTATION
:
6532 return pdoc
->GetLineIndentation(static_cast<int>(wParam
));
6534 case SCI_GETLINEINDENTPOSITION
:
6535 return pdoc
->GetLineIndentPosition(static_cast<int>(wParam
));
6537 case SCI_SETTABINDENTS
:
6538 pdoc
->tabIndents
= wParam
!= 0;
6541 case SCI_GETTABINDENTS
:
6542 return pdoc
->tabIndents
;
6544 case SCI_SETBACKSPACEUNINDENTS
:
6545 pdoc
->backspaceUnindents
= wParam
!= 0;
6548 case SCI_GETBACKSPACEUNINDENTS
:
6549 return pdoc
->backspaceUnindents
;
6551 case SCI_SETMOUSEDWELLTIME
:
6552 dwellDelay
= static_cast<int>(wParam
);
6553 ticksToDwell
= dwellDelay
;
6556 case SCI_GETMOUSEDWELLTIME
:
6559 case SCI_WORDSTARTPOSITION
:
6560 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), -1, lParam
!= 0);
6562 case SCI_WORDENDPOSITION
:
6563 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), 1, lParam
!= 0);
6565 case SCI_ISRANGEWORD
:
6566 return pdoc
->IsWordAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
6568 case SCI_SETIDLESTYLING
:
6569 idleStyling
= static_cast<int>(wParam
);
6572 case SCI_GETIDLESTYLING
:
6575 case SCI_SETWRAPMODE
:
6576 if (vs
.SetWrapState(static_cast<int>(wParam
))) {
6578 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6579 InvalidateStyleRedraw();
6580 ReconfigureScrollBars();
6584 case SCI_GETWRAPMODE
:
6585 return vs
.wrapState
;
6587 case SCI_SETWRAPVISUALFLAGS
:
6588 if (vs
.SetWrapVisualFlags(static_cast<int>(wParam
))) {
6589 InvalidateStyleRedraw();
6590 ReconfigureScrollBars();
6594 case SCI_GETWRAPVISUALFLAGS
:
6595 return vs
.wrapVisualFlags
;
6597 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6598 if (vs
.SetWrapVisualFlagsLocation(static_cast<int>(wParam
))) {
6599 InvalidateStyleRedraw();
6603 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6604 return vs
.wrapVisualFlagsLocation
;
6606 case SCI_SETWRAPSTARTINDENT
:
6607 if (vs
.SetWrapVisualStartIndent(static_cast<int>(wParam
))) {
6608 InvalidateStyleRedraw();
6609 ReconfigureScrollBars();
6613 case SCI_GETWRAPSTARTINDENT
:
6614 return vs
.wrapVisualStartIndent
;
6616 case SCI_SETWRAPINDENTMODE
:
6617 if (vs
.SetWrapIndentMode(static_cast<int>(wParam
))) {
6618 InvalidateStyleRedraw();
6619 ReconfigureScrollBars();
6623 case SCI_GETWRAPINDENTMODE
:
6624 return vs
.wrapIndentMode
;
6626 case SCI_SETLAYOUTCACHE
:
6627 view
.llc
.SetLevel(static_cast<int>(wParam
));
6630 case SCI_GETLAYOUTCACHE
:
6631 return view
.llc
.GetLevel();
6633 case SCI_SETPOSITIONCACHE
:
6634 view
.posCache
.SetSize(wParam
);
6637 case SCI_GETPOSITIONCACHE
:
6638 return view
.posCache
.GetSize();
6640 case SCI_SETSCROLLWIDTH
:
6641 PLATFORM_ASSERT(wParam
> 0);
6642 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6643 view
.lineWidthMaxSeen
= 0;
6644 scrollWidth
= static_cast<int>(wParam
);
6649 case SCI_GETSCROLLWIDTH
:
6652 case SCI_SETSCROLLWIDTHTRACKING
:
6653 trackLineWidth
= wParam
!= 0;
6656 case SCI_GETSCROLLWIDTHTRACKING
:
6657 return trackLineWidth
;
6663 case SCI_LINESSPLIT
:
6664 LinesSplit(static_cast<int>(wParam
));
6668 PLATFORM_ASSERT(wParam
< vs
.styles
.size());
6669 PLATFORM_ASSERT(lParam
);
6670 return TextWidth(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6672 case SCI_TEXTHEIGHT
:
6674 return vs
.lineHeight
;
6676 case SCI_SETENDATLASTLINE
:
6677 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6678 if (endAtLastLine
!= (wParam
!= 0)) {
6679 endAtLastLine
= wParam
!= 0;
6684 case SCI_GETENDATLASTLINE
:
6685 return endAtLastLine
;
6687 case SCI_SETCARETSTICKY
:
6688 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
6689 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
6690 caretSticky
= static_cast<int>(wParam
);
6694 case SCI_GETCARETSTICKY
:
6697 case SCI_TOGGLECARETSTICKY
:
6698 caretSticky
= !caretSticky
;
6702 return pdoc
->GetColumn(static_cast<int>(wParam
));
6704 case SCI_FINDCOLUMN
:
6705 return pdoc
->FindColumn(static_cast<int>(wParam
), static_cast<int>(lParam
));
6707 case SCI_SETHSCROLLBAR
:
6708 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6709 horizontalScrollBarVisible
= wParam
!= 0;
6711 ReconfigureScrollBars();
6715 case SCI_GETHSCROLLBAR
:
6716 return horizontalScrollBarVisible
;
6718 case SCI_SETVSCROLLBAR
:
6719 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6720 verticalScrollBarVisible
= wParam
!= 0;
6722 ReconfigureScrollBars();
6723 if (verticalScrollBarVisible
)
6724 SetVerticalScrollPos();
6728 case SCI_GETVSCROLLBAR
:
6729 return verticalScrollBarVisible
;
6731 case SCI_SETINDENTATIONGUIDES
:
6732 vs
.viewIndentationGuides
= IndentView(wParam
);
6736 case SCI_GETINDENTATIONGUIDES
:
6737 return vs
.viewIndentationGuides
;
6739 case SCI_SETHIGHLIGHTGUIDE
:
6740 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6741 highlightGuideColumn
= static_cast<int>(wParam
);
6746 case SCI_GETHIGHLIGHTGUIDE
:
6747 return highlightGuideColumn
;
6749 case SCI_GETLINEENDPOSITION
:
6750 return pdoc
->LineEnd(static_cast<int>(wParam
));
6752 case SCI_SETCODEPAGE
:
6753 if (ValidCodePage(static_cast<int>(wParam
))) {
6754 if (pdoc
->SetDBCSCodePage(static_cast<int>(wParam
))) {
6756 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6757 SetAnnotationHeights(0, pdoc
->LinesTotal());
6758 InvalidateStyleRedraw();
6759 SetRepresentations();
6764 case SCI_GETCODEPAGE
:
6765 return pdoc
->dbcsCodePage
;
6767 case SCI_SETIMEINTERACTION
:
6768 imeInteraction
= static_cast<EditModel::IMEInteraction
>(wParam
);
6771 case SCI_GETIMEINTERACTION
:
6772 return imeInteraction
;
6774 // Marker definition and setting
6775 case SCI_MARKERDEFINE
:
6776 if (wParam
<= MARKER_MAX
) {
6777 vs
.markers
[wParam
].markType
= static_cast<int>(lParam
);
6778 vs
.CalcLargestMarkerHeight();
6780 InvalidateStyleData();
6784 case SCI_MARKERSYMBOLDEFINED
:
6785 if (wParam
<= MARKER_MAX
)
6786 return vs
.markers
[wParam
].markType
;
6790 case SCI_MARKERSETFORE
:
6791 if (wParam
<= MARKER_MAX
)
6792 vs
.markers
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6793 InvalidateStyleData();
6796 case SCI_MARKERSETBACKSELECTED
:
6797 if (wParam
<= MARKER_MAX
)
6798 vs
.markers
[wParam
].backSelected
= ColourDesired(static_cast<long>(lParam
));
6799 InvalidateStyleData();
6802 case SCI_MARKERENABLEHIGHLIGHT
:
6803 marginView
.highlightDelimiter
.isEnabled
= wParam
== 1;
6806 case SCI_MARKERSETBACK
:
6807 if (wParam
<= MARKER_MAX
)
6808 vs
.markers
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6809 InvalidateStyleData();
6812 case SCI_MARKERSETALPHA
:
6813 if (wParam
<= MARKER_MAX
)
6814 vs
.markers
[wParam
].alpha
= static_cast<int>(lParam
);
6815 InvalidateStyleRedraw();
6817 case SCI_MARKERADD
: {
6818 int markerID
= pdoc
->AddMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6821 case SCI_MARKERADDSET
:
6823 pdoc
->AddMarkSet(static_cast<int>(wParam
), static_cast<int>(lParam
));
6826 case SCI_MARKERDELETE
:
6827 pdoc
->DeleteMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6830 case SCI_MARKERDELETEALL
:
6831 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6835 return pdoc
->GetMark(static_cast<int>(wParam
));
6837 case SCI_MARKERNEXT
:
6838 return pdoc
->MarkerNext(static_cast<int>(wParam
), static_cast<int>(lParam
));
6840 case SCI_MARKERPREVIOUS
: {
6841 for (int iLine
= static_cast<int>(wParam
); iLine
>= 0; iLine
--) {
6842 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6848 case SCI_MARKERDEFINEPIXMAP
:
6849 if (wParam
<= MARKER_MAX
) {
6850 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6851 vs
.CalcLargestMarkerHeight();
6853 InvalidateStyleData();
6857 case SCI_RGBAIMAGESETWIDTH
:
6858 sizeRGBAImage
.x
= static_cast<XYPOSITION
>(wParam
);
6861 case SCI_RGBAIMAGESETHEIGHT
:
6862 sizeRGBAImage
.y
= static_cast<XYPOSITION
>(wParam
);
6865 case SCI_RGBAIMAGESETSCALE
:
6866 scaleRGBAImage
= static_cast<float>(wParam
);
6869 case SCI_MARKERDEFINERGBAIMAGE
:
6870 if (wParam
<= MARKER_MAX
) {
6871 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0f
, reinterpret_cast<unsigned char *>(lParam
));
6872 vs
.CalcLargestMarkerHeight();
6874 InvalidateStyleData();
6878 case SCI_SETMARGINTYPEN
:
6879 if (ValidMargin(wParam
)) {
6880 vs
.ms
[wParam
].style
= static_cast<int>(lParam
);
6881 InvalidateStyleRedraw();
6885 case SCI_GETMARGINTYPEN
:
6886 if (ValidMargin(wParam
))
6887 return vs
.ms
[wParam
].style
;
6891 case SCI_SETMARGINWIDTHN
:
6892 if (ValidMargin(wParam
)) {
6893 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6894 if (vs
.ms
[wParam
].width
!= lParam
) {
6895 lastXChosen
+= static_cast<int>(lParam
) - vs
.ms
[wParam
].width
;
6896 vs
.ms
[wParam
].width
= static_cast<int>(lParam
);
6897 InvalidateStyleRedraw();
6902 case SCI_GETMARGINWIDTHN
:
6903 if (ValidMargin(wParam
))
6904 return vs
.ms
[wParam
].width
;
6908 case SCI_SETMARGINMASKN
:
6909 if (ValidMargin(wParam
)) {
6910 vs
.ms
[wParam
].mask
= static_cast<int>(lParam
);
6911 InvalidateStyleRedraw();
6915 case SCI_GETMARGINMASKN
:
6916 if (ValidMargin(wParam
))
6917 return vs
.ms
[wParam
].mask
;
6921 case SCI_SETMARGINSENSITIVEN
:
6922 if (ValidMargin(wParam
)) {
6923 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6924 InvalidateStyleRedraw();
6928 case SCI_GETMARGINSENSITIVEN
:
6929 if (ValidMargin(wParam
))
6930 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6934 case SCI_SETMARGINCURSORN
:
6935 if (ValidMargin(wParam
))
6936 vs
.ms
[wParam
].cursor
= static_cast<int>(lParam
);
6939 case SCI_GETMARGINCURSORN
:
6940 if (ValidMargin(wParam
))
6941 return vs
.ms
[wParam
].cursor
;
6945 case SCI_SETMARGINBACKN
:
6946 if (ValidMargin(wParam
)) {
6947 vs
.ms
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6948 InvalidateStyleRedraw();
6952 case SCI_GETMARGINBACKN
:
6953 if (ValidMargin(wParam
))
6954 return vs
.ms
[wParam
].back
.AsLong();
6958 case SCI_SETMARGINS
:
6960 vs
.ms
.resize(wParam
);
6963 case SCI_GETMARGINS
:
6964 return vs
.ms
.size();
6966 case SCI_STYLECLEARALL
:
6968 InvalidateStyleRedraw();
6971 case SCI_STYLESETFORE
:
6972 case SCI_STYLESETBACK
:
6973 case SCI_STYLESETBOLD
:
6974 case SCI_STYLESETWEIGHT
:
6975 case SCI_STYLESETITALIC
:
6976 case SCI_STYLESETEOLFILLED
:
6977 case SCI_STYLESETSIZE
:
6978 case SCI_STYLESETSIZEFRACTIONAL
:
6979 case SCI_STYLESETFONT
:
6980 case SCI_STYLESETUNDERLINE
:
6981 case SCI_STYLESETCASE
:
6982 case SCI_STYLESETCHARACTERSET
:
6983 case SCI_STYLESETVISIBLE
:
6984 case SCI_STYLESETCHANGEABLE
:
6985 case SCI_STYLESETHOTSPOT
:
6986 StyleSetMessage(iMessage
, wParam
, lParam
);
6989 case SCI_STYLEGETFORE
:
6990 case SCI_STYLEGETBACK
:
6991 case SCI_STYLEGETBOLD
:
6992 case SCI_STYLEGETWEIGHT
:
6993 case SCI_STYLEGETITALIC
:
6994 case SCI_STYLEGETEOLFILLED
:
6995 case SCI_STYLEGETSIZE
:
6996 case SCI_STYLEGETSIZEFRACTIONAL
:
6997 case SCI_STYLEGETFONT
:
6998 case SCI_STYLEGETUNDERLINE
:
6999 case SCI_STYLEGETCASE
:
7000 case SCI_STYLEGETCHARACTERSET
:
7001 case SCI_STYLEGETVISIBLE
:
7002 case SCI_STYLEGETCHANGEABLE
:
7003 case SCI_STYLEGETHOTSPOT
:
7004 return StyleGetMessage(iMessage
, wParam
, lParam
);
7006 case SCI_STYLERESETDEFAULT
:
7007 vs
.ResetDefaultStyle();
7008 InvalidateStyleRedraw();
7010 case SCI_SETSTYLEBITS
:
7011 vs
.EnsureStyle(0xff);
7014 case SCI_GETSTYLEBITS
:
7017 case SCI_SETLINESTATE
:
7018 return pdoc
->SetLineState(static_cast<int>(wParam
), static_cast<int>(lParam
));
7020 case SCI_GETLINESTATE
:
7021 return pdoc
->GetLineState(static_cast<int>(wParam
));
7023 case SCI_GETMAXLINESTATE
:
7024 return pdoc
->GetMaxLineState();
7026 case SCI_GETCARETLINEVISIBLE
:
7027 return vs
.showCaretLineBackground
;
7028 case SCI_SETCARETLINEVISIBLE
:
7029 vs
.showCaretLineBackground
= wParam
!= 0;
7030 InvalidateStyleRedraw();
7032 case SCI_GETCARETLINEVISIBLEALWAYS
:
7033 return vs
.alwaysShowCaretLineBackground
;
7034 case SCI_SETCARETLINEVISIBLEALWAYS
:
7035 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
7036 InvalidateStyleRedraw();
7039 case SCI_GETCARETLINEBACK
:
7040 return vs
.caretLineBackground
.AsLong();
7041 case SCI_SETCARETLINEBACK
:
7042 vs
.caretLineBackground
= static_cast<int>(wParam
);
7043 InvalidateStyleRedraw();
7045 case SCI_GETCARETLINEBACKALPHA
:
7046 return vs
.caretLineAlpha
;
7047 case SCI_SETCARETLINEBACKALPHA
:
7048 vs
.caretLineAlpha
= static_cast<int>(wParam
);
7049 InvalidateStyleRedraw();
7054 case SCI_VISIBLEFROMDOCLINE
:
7055 return cs
.DisplayFromDoc(static_cast<int>(wParam
));
7057 case SCI_DOCLINEFROMVISIBLE
:
7058 return cs
.DocFromDisplay(static_cast<int>(wParam
));
7061 return WrapCount(static_cast<int>(wParam
));
7063 case SCI_SETFOLDLEVEL
: {
7064 int prev
= pdoc
->SetLevel(static_cast<int>(wParam
), static_cast<int>(lParam
));
7065 if (prev
!= static_cast<int>(lParam
))
7070 case SCI_GETFOLDLEVEL
:
7071 return pdoc
->GetLevel(static_cast<int>(wParam
));
7073 case SCI_GETLASTCHILD
:
7074 return pdoc
->GetLastChild(static_cast<int>(wParam
), static_cast<int>(lParam
));
7076 case SCI_GETFOLDPARENT
:
7077 return pdoc
->GetFoldParent(static_cast<int>(wParam
));
7080 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), true);
7087 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), false);
7092 case SCI_GETLINEVISIBLE
:
7093 return cs
.GetVisible(static_cast<int>(wParam
));
7095 case SCI_GETALLLINESVISIBLE
:
7096 return cs
.HiddenLines() ? 0 : 1;
7098 case SCI_SETFOLDEXPANDED
:
7099 SetFoldExpanded(static_cast<int>(wParam
), lParam
!= 0);
7102 case SCI_GETFOLDEXPANDED
:
7103 return cs
.GetExpanded(static_cast<int>(wParam
));
7105 case SCI_SETAUTOMATICFOLD
:
7106 foldAutomatic
= static_cast<int>(wParam
);
7109 case SCI_GETAUTOMATICFOLD
:
7110 return foldAutomatic
;
7112 case SCI_SETFOLDFLAGS
:
7113 foldFlags
= static_cast<int>(wParam
);
7117 case SCI_TOGGLEFOLDSHOWTEXT
:
7118 cs
.SetFoldDisplayText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7119 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
7122 case SCI_FOLDDISPLAYTEXTSETSTYLE
:
7123 foldDisplayTextStyle
= static_cast<int>(wParam
);
7127 case SCI_TOGGLEFOLD
:
7128 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
7132 FoldLine(static_cast<int>(wParam
), static_cast<int>(lParam
));
7135 case SCI_FOLDCHILDREN
:
7136 FoldExpand(static_cast<int>(wParam
), static_cast<int>(lParam
), pdoc
->GetLevel(static_cast<int>(wParam
)));
7140 FoldAll(static_cast<int>(wParam
));
7143 case SCI_EXPANDCHILDREN
:
7144 FoldExpand(static_cast<int>(wParam
), SC_FOLDACTION_EXPAND
, static_cast<int>(lParam
));
7147 case SCI_CONTRACTEDFOLDNEXT
:
7148 return ContractedFoldNext(static_cast<int>(wParam
));
7150 case SCI_ENSUREVISIBLE
:
7151 EnsureLineVisible(static_cast<int>(wParam
), false);
7154 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
7155 EnsureLineVisible(static_cast<int>(wParam
), true);
7158 case SCI_SCROLLRANGE
:
7159 ScrollRange(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7162 case SCI_SEARCHANCHOR
:
7166 case SCI_SEARCHNEXT
:
7167 case SCI_SEARCHPREV
:
7168 return SearchText(iMessage
, wParam
, lParam
);
7170 case SCI_SETXCARETPOLICY
:
7171 caretXPolicy
= static_cast<int>(wParam
);
7172 caretXSlop
= static_cast<int>(lParam
);
7175 case SCI_SETYCARETPOLICY
:
7176 caretYPolicy
= static_cast<int>(wParam
);
7177 caretYSlop
= static_cast<int>(lParam
);
7180 case SCI_SETVISIBLEPOLICY
:
7181 visiblePolicy
= static_cast<int>(wParam
);
7182 visibleSlop
= static_cast<int>(lParam
);
7185 case SCI_LINESONSCREEN
:
7186 return LinesOnScreen();
7188 case SCI_SETSELFORE
:
7189 vs
.selColours
.fore
= ColourOptional(wParam
, lParam
);
7190 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(lParam
));
7191 InvalidateStyleRedraw();
7194 case SCI_SETSELBACK
:
7195 vs
.selColours
.back
= ColourOptional(wParam
, lParam
);
7196 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(lParam
));
7197 InvalidateStyleRedraw();
7200 case SCI_SETSELALPHA
:
7201 vs
.selAlpha
= static_cast<int>(wParam
);
7202 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7203 InvalidateStyleRedraw();
7206 case SCI_GETSELALPHA
:
7209 case SCI_GETSELEOLFILLED
:
7210 return vs
.selEOLFilled
;
7212 case SCI_SETSELEOLFILLED
:
7213 vs
.selEOLFilled
= wParam
!= 0;
7214 InvalidateStyleRedraw();
7217 case SCI_SETWHITESPACEFORE
:
7218 vs
.whitespaceColours
.fore
= ColourOptional(wParam
, lParam
);
7219 InvalidateStyleRedraw();
7222 case SCI_SETWHITESPACEBACK
:
7223 vs
.whitespaceColours
.back
= ColourOptional(wParam
, lParam
);
7224 InvalidateStyleRedraw();
7227 case SCI_SETCARETFORE
:
7228 vs
.caretcolour
= ColourDesired(static_cast<long>(wParam
));
7229 InvalidateStyleRedraw();
7232 case SCI_GETCARETFORE
:
7233 return vs
.caretcolour
.AsLong();
7235 case SCI_SETCARETSTYLE
:
7236 if (wParam
<= CARETSTYLE_BLOCK
)
7237 vs
.caretStyle
= static_cast<int>(wParam
);
7239 /* Default to the line caret */
7240 vs
.caretStyle
= CARETSTYLE_LINE
;
7241 InvalidateStyleRedraw();
7244 case SCI_GETCARETSTYLE
:
7245 return vs
.caretStyle
;
7247 case SCI_SETCARETWIDTH
:
7248 if (static_cast<int>(wParam
) <= 0)
7250 else if (wParam
>= 3)
7253 vs
.caretWidth
= static_cast<int>(wParam
);
7254 InvalidateStyleRedraw();
7257 case SCI_GETCARETWIDTH
:
7258 return vs
.caretWidth
;
7260 case SCI_ASSIGNCMDKEY
:
7261 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7262 Platform::HighShortFromLong(static_cast<long>(wParam
)), static_cast<unsigned int>(lParam
));
7265 case SCI_CLEARCMDKEY
:
7266 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7267 Platform::HighShortFromLong(static_cast<long>(wParam
)), SCI_NULL
);
7270 case SCI_CLEARALLCMDKEYS
:
7274 case SCI_INDICSETSTYLE
:
7275 if (wParam
<= INDIC_MAX
) {
7276 vs
.indicators
[wParam
].sacNormal
.style
= static_cast<int>(lParam
);
7277 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7278 InvalidateStyleRedraw();
7282 case SCI_INDICGETSTYLE
:
7283 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.style
: 0;
7285 case SCI_INDICSETFORE
:
7286 if (wParam
<= INDIC_MAX
) {
7287 vs
.indicators
[wParam
].sacNormal
.fore
= ColourDesired(static_cast<long>(lParam
));
7288 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7289 InvalidateStyleRedraw();
7293 case SCI_INDICGETFORE
:
7294 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.fore
.AsLong() : 0;
7296 case SCI_INDICSETHOVERSTYLE
:
7297 if (wParam
<= INDIC_MAX
) {
7298 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7299 InvalidateStyleRedraw();
7303 case SCI_INDICGETHOVERSTYLE
:
7304 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.style
: 0;
7306 case SCI_INDICSETHOVERFORE
:
7307 if (wParam
<= INDIC_MAX
) {
7308 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7309 InvalidateStyleRedraw();
7313 case SCI_INDICGETHOVERFORE
:
7314 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.fore
.AsLong() : 0;
7316 case SCI_INDICSETFLAGS
:
7317 if (wParam
<= INDIC_MAX
) {
7318 vs
.indicators
[wParam
].SetFlags(static_cast<int>(lParam
));
7319 InvalidateStyleRedraw();
7323 case SCI_INDICGETFLAGS
:
7324 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].Flags() : 0;
7326 case SCI_INDICSETUNDER
:
7327 if (wParam
<= INDIC_MAX
) {
7328 vs
.indicators
[wParam
].under
= lParam
!= 0;
7329 InvalidateStyleRedraw();
7333 case SCI_INDICGETUNDER
:
7334 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
7336 case SCI_INDICSETALPHA
:
7337 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7338 vs
.indicators
[wParam
].fillAlpha
= static_cast<int>(lParam
);
7339 InvalidateStyleRedraw();
7343 case SCI_INDICGETALPHA
:
7344 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
7346 case SCI_INDICSETOUTLINEALPHA
:
7347 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7348 vs
.indicators
[wParam
].outlineAlpha
= static_cast<int>(lParam
);
7349 InvalidateStyleRedraw();
7353 case SCI_INDICGETOUTLINEALPHA
:
7354 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
7356 case SCI_SETINDICATORCURRENT
:
7357 pdoc
->decorations
.SetCurrentIndicator(static_cast<int>(wParam
));
7359 case SCI_GETINDICATORCURRENT
:
7360 return pdoc
->decorations
.GetCurrentIndicator();
7361 case SCI_SETINDICATORVALUE
:
7362 pdoc
->decorations
.SetCurrentValue(static_cast<int>(wParam
));
7364 case SCI_GETINDICATORVALUE
:
7365 return pdoc
->decorations
.GetCurrentValue();
7367 case SCI_INDICATORFILLRANGE
:
7368 pdoc
->DecorationFillRange(static_cast<int>(wParam
), pdoc
->decorations
.GetCurrentValue(), static_cast<int>(lParam
));
7371 case SCI_INDICATORCLEARRANGE
:
7372 pdoc
->DecorationFillRange(static_cast<int>(wParam
), 0, static_cast<int>(lParam
));
7375 case SCI_INDICATORALLONFOR
:
7376 return pdoc
->decorations
.AllOnFor(static_cast<int>(wParam
));
7378 case SCI_INDICATORVALUEAT
:
7379 return pdoc
->decorations
.ValueAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
7381 case SCI_INDICATORSTART
:
7382 return pdoc
->decorations
.Start(static_cast<int>(wParam
), static_cast<int>(lParam
));
7384 case SCI_INDICATOREND
:
7385 return pdoc
->decorations
.End(static_cast<int>(wParam
), static_cast<int>(lParam
));
7388 case SCI_LINEDOWNEXTEND
:
7390 case SCI_PARADOWNEXTEND
:
7392 case SCI_LINEUPEXTEND
:
7394 case SCI_PARAUPEXTEND
:
7396 case SCI_CHARLEFTEXTEND
:
7398 case SCI_CHARRIGHTEXTEND
:
7400 case SCI_WORDLEFTEXTEND
:
7402 case SCI_WORDRIGHTEXTEND
:
7403 case SCI_WORDLEFTEND
:
7404 case SCI_WORDLEFTENDEXTEND
:
7405 case SCI_WORDRIGHTEND
:
7406 case SCI_WORDRIGHTENDEXTEND
:
7408 case SCI_HOMEEXTEND
:
7410 case SCI_LINEENDEXTEND
:
7412 case SCI_HOMEWRAPEXTEND
:
7413 case SCI_LINEENDWRAP
:
7414 case SCI_LINEENDWRAPEXTEND
:
7415 case SCI_DOCUMENTSTART
:
7416 case SCI_DOCUMENTSTARTEXTEND
:
7417 case SCI_DOCUMENTEND
:
7418 case SCI_DOCUMENTENDEXTEND
:
7419 case SCI_SCROLLTOSTART
:
7420 case SCI_SCROLLTOEND
:
7422 case SCI_STUTTEREDPAGEUP
:
7423 case SCI_STUTTEREDPAGEUPEXTEND
:
7424 case SCI_STUTTEREDPAGEDOWN
:
7425 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7428 case SCI_PAGEUPEXTEND
:
7430 case SCI_PAGEDOWNEXTEND
:
7431 case SCI_EDITTOGGLEOVERTYPE
:
7433 case SCI_DELETEBACK
:
7439 case SCI_VCHOMEEXTEND
:
7440 case SCI_VCHOMEWRAP
:
7441 case SCI_VCHOMEWRAPEXTEND
:
7442 case SCI_VCHOMEDISPLAY
:
7443 case SCI_VCHOMEDISPLAYEXTEND
:
7446 case SCI_DELWORDLEFT
:
7447 case SCI_DELWORDRIGHT
:
7448 case SCI_DELWORDRIGHTEND
:
7449 case SCI_DELLINELEFT
:
7450 case SCI_DELLINERIGHT
:
7453 case SCI_LINEDELETE
:
7454 case SCI_LINETRANSPOSE
:
7455 case SCI_LINEDUPLICATE
:
7458 case SCI_LINESCROLLDOWN
:
7459 case SCI_LINESCROLLUP
:
7460 case SCI_WORDPARTLEFT
:
7461 case SCI_WORDPARTLEFTEXTEND
:
7462 case SCI_WORDPARTRIGHT
:
7463 case SCI_WORDPARTRIGHTEXTEND
:
7464 case SCI_DELETEBACKNOTLINE
:
7465 case SCI_HOMEDISPLAY
:
7466 case SCI_HOMEDISPLAYEXTEND
:
7467 case SCI_LINEENDDISPLAY
:
7468 case SCI_LINEENDDISPLAYEXTEND
:
7469 case SCI_LINEDOWNRECTEXTEND
:
7470 case SCI_LINEUPRECTEXTEND
:
7471 case SCI_CHARLEFTRECTEXTEND
:
7472 case SCI_CHARRIGHTRECTEXTEND
:
7473 case SCI_HOMERECTEXTEND
:
7474 case SCI_VCHOMERECTEXTEND
:
7475 case SCI_LINEENDRECTEXTEND
:
7476 case SCI_PAGEUPRECTEXTEND
:
7477 case SCI_PAGEDOWNRECTEXTEND
:
7478 case SCI_SELECTIONDUPLICATE
:
7479 return KeyCommand(iMessage
);
7481 case SCI_BRACEHIGHLIGHT
:
7482 SetBraceHighlight(static_cast<int>(wParam
), static_cast<int>(lParam
), STYLE_BRACELIGHT
);
7485 case SCI_BRACEHIGHLIGHTINDICATOR
:
7486 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7487 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
7488 vs
.braceHighlightIndicator
= static_cast<int>(lParam
);
7492 case SCI_BRACEBADLIGHT
:
7493 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7496 case SCI_BRACEBADLIGHTINDICATOR
:
7497 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7498 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
7499 vs
.braceBadLightIndicator
= static_cast<int>(lParam
);
7503 case SCI_BRACEMATCH
:
7504 // wParam is position of char to find brace for,
7505 // lParam is maximum amount of text to restyle to find it
7506 return pdoc
->BraceMatch(static_cast<int>(wParam
), static_cast<int>(lParam
));
7508 case SCI_GETVIEWEOL
:
7511 case SCI_SETVIEWEOL
:
7512 vs
.viewEOL
= wParam
!= 0;
7513 InvalidateStyleRedraw();
7517 vs
.zoomLevel
= static_cast<int>(wParam
);
7518 InvalidateStyleRedraw();
7523 return vs
.zoomLevel
;
7525 case SCI_GETEDGECOLUMN
:
7526 return vs
.theEdge
.column
;
7528 case SCI_SETEDGECOLUMN
:
7529 vs
.theEdge
.column
= static_cast<int>(wParam
);
7530 InvalidateStyleRedraw();
7533 case SCI_GETEDGEMODE
:
7534 return vs
.edgeState
;
7536 case SCI_SETEDGEMODE
:
7537 vs
.edgeState
= static_cast<int>(wParam
);
7538 InvalidateStyleRedraw();
7541 case SCI_GETEDGECOLOUR
:
7542 return vs
.theEdge
.colour
.AsLong();
7544 case SCI_SETEDGECOLOUR
:
7545 vs
.theEdge
.colour
= ColourDesired(static_cast<long>(wParam
));
7546 InvalidateStyleRedraw();
7549 case SCI_MULTIEDGEADDLINE
:
7550 vs
.theMultiEdge
.push_back(EdgeProperties(wParam
, lParam
));
7551 InvalidateStyleRedraw();
7554 case SCI_MULTIEDGECLEARALL
:
7555 std::vector
<EdgeProperties
>().swap(vs
.theMultiEdge
); // Free vector and memory, C++03 compatible
7556 InvalidateStyleRedraw();
7559 case SCI_GETACCESSIBILITY
:
7560 return SC_ACCESSIBILITY_DISABLED
;
7562 case SCI_SETACCESSIBILITY
:
7563 // May be implemented by platform code.
7566 case SCI_GETDOCPOINTER
:
7567 return reinterpret_cast<sptr_t
>(pdoc
);
7569 case SCI_SETDOCPOINTER
:
7571 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7574 case SCI_CREATEDOCUMENT
: {
7575 Document
*doc
= new Document();
7577 return reinterpret_cast<sptr_t
>(doc
);
7580 case SCI_ADDREFDOCUMENT
:
7581 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7584 case SCI_RELEASEDOCUMENT
:
7585 (reinterpret_cast<Document
*>(lParam
))->Release();
7588 case SCI_CREATELOADER
: {
7589 Document
*doc
= new Document();
7591 doc
->Allocate(static_cast<int>(wParam
));
7592 doc
->SetUndoCollection(false);
7593 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
7596 case SCI_SETMODEVENTMASK
:
7597 modEventMask
= static_cast<int>(wParam
);
7600 case SCI_GETMODEVENTMASK
:
7601 return modEventMask
;
7603 case SCI_CONVERTEOLS
:
7604 pdoc
->ConvertLineEnds(static_cast<int>(wParam
));
7605 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7608 case SCI_SETLENGTHFORENCODE
:
7609 lengthForEncode
= static_cast<int>(wParam
);
7612 case SCI_SELECTIONISRECTANGLE
:
7613 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7615 case SCI_SETSELECTIONMODE
: {
7618 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7619 sel
.selType
= Selection::selStream
;
7621 case SC_SEL_RECTANGLE
:
7622 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7623 sel
.selType
= Selection::selRectangle
;
7626 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7627 sel
.selType
= Selection::selLines
;
7630 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7631 sel
.selType
= Selection::selThin
;
7634 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7635 sel
.selType
= Selection::selStream
;
7637 InvalidateWholeSelection();
7640 case SCI_GETSELECTIONMODE
:
7641 switch (sel
.selType
) {
7642 case Selection::selStream
:
7643 return SC_SEL_STREAM
;
7644 case Selection::selRectangle
:
7645 return SC_SEL_RECTANGLE
;
7646 case Selection::selLines
:
7647 return SC_SEL_LINES
;
7648 case Selection::selThin
:
7651 return SC_SEL_STREAM
;
7653 case SCI_GETLINESELSTARTPOSITION
:
7654 case SCI_GETLINESELENDPOSITION
: {
7655 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(static_cast<int>(wParam
))),
7656 SelectionPosition(pdoc
->LineEnd(static_cast<int>(wParam
))));
7657 for (size_t r
=0; r
<sel
.Count(); r
++) {
7658 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7659 if (portion
.start
.IsValid()) {
7660 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
7663 return INVALID_POSITION
;
7666 case SCI_SETOVERTYPE
:
7667 inOverstrike
= wParam
!= 0;
7670 case SCI_GETOVERTYPE
:
7671 return inOverstrike
? 1 : 0;
7674 SetFocusState(wParam
!= 0);
7681 errorStatus
= static_cast<int>(wParam
);
7687 case SCI_SETMOUSEDOWNCAPTURES
:
7688 mouseDownCaptures
= wParam
!= 0;
7691 case SCI_GETMOUSEDOWNCAPTURES
:
7692 return mouseDownCaptures
;
7694 case SCI_SETMOUSEWHEELCAPTURES
:
7695 mouseWheelCaptures
= wParam
!= 0;
7698 case SCI_GETMOUSEWHEELCAPTURES
:
7699 return mouseWheelCaptures
;
7702 cursorMode
= static_cast<int>(wParam
);
7703 DisplayCursor(Window::cursorText
);
7709 case SCI_SETCONTROLCHARSYMBOL
:
7710 vs
.controlCharSymbol
= static_cast<int>(wParam
);
7711 InvalidateStyleRedraw();
7714 case SCI_GETCONTROLCHARSYMBOL
:
7715 return vs
.controlCharSymbol
;
7717 case SCI_SETREPRESENTATION
:
7718 reprs
.SetRepresentation(reinterpret_cast<const char *>(wParam
), CharPtrFromSPtr(lParam
));
7721 case SCI_GETREPRESENTATION
: {
7722 const Representation
*repr
= reprs
.RepresentationFromCharacter(
7723 reinterpret_cast<const char *>(wParam
), UTF8MaxBytes
);
7725 return StringResult(lParam
, repr
->stringRep
.c_str());
7730 case SCI_CLEARREPRESENTATION
:
7731 reprs
.ClearRepresentation(reinterpret_cast<const char *>(wParam
));
7734 case SCI_STARTRECORD
:
7735 recordingMacro
= true;
7738 case SCI_STOPRECORD
:
7739 recordingMacro
= false;
7742 case SCI_MOVECARETINSIDEVIEW
:
7743 MoveCaretInsideView();
7746 case SCI_SETFOLDMARGINCOLOUR
:
7747 vs
.foldmarginColour
= ColourOptional(wParam
, lParam
);
7748 InvalidateStyleRedraw();
7751 case SCI_SETFOLDMARGINHICOLOUR
:
7752 vs
.foldmarginHighlightColour
= ColourOptional(wParam
, lParam
);
7753 InvalidateStyleRedraw();
7756 case SCI_SETHOTSPOTACTIVEFORE
:
7757 vs
.hotspotColours
.fore
= ColourOptional(wParam
, lParam
);
7758 InvalidateStyleRedraw();
7761 case SCI_GETHOTSPOTACTIVEFORE
:
7762 return vs
.hotspotColours
.fore
.AsLong();
7764 case SCI_SETHOTSPOTACTIVEBACK
:
7765 vs
.hotspotColours
.back
= ColourOptional(wParam
, lParam
);
7766 InvalidateStyleRedraw();
7769 case SCI_GETHOTSPOTACTIVEBACK
:
7770 return vs
.hotspotColours
.back
.AsLong();
7772 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7773 vs
.hotspotUnderline
= wParam
!= 0;
7774 InvalidateStyleRedraw();
7777 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7778 return vs
.hotspotUnderline
? 1 : 0;
7780 case SCI_SETHOTSPOTSINGLELINE
:
7781 vs
.hotspotSingleLine
= wParam
!= 0;
7782 InvalidateStyleRedraw();
7785 case SCI_GETHOTSPOTSINGLELINE
:
7786 return vs
.hotspotSingleLine
? 1 : 0;
7788 case SCI_SETPASTECONVERTENDINGS
:
7789 convertPastes
= wParam
!= 0;
7792 case SCI_GETPASTECONVERTENDINGS
:
7793 return convertPastes
? 1 : 0;
7795 case SCI_GETCHARACTERPOINTER
:
7796 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
7798 case SCI_GETRANGEPOINTER
:
7799 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7801 case SCI_GETGAPPOSITION
:
7802 return pdoc
->GapPosition();
7804 case SCI_SETEXTRAASCENT
:
7805 vs
.extraAscent
= static_cast<int>(wParam
);
7806 InvalidateStyleRedraw();
7809 case SCI_GETEXTRAASCENT
:
7810 return vs
.extraAscent
;
7812 case SCI_SETEXTRADESCENT
:
7813 vs
.extraDescent
= static_cast<int>(wParam
);
7814 InvalidateStyleRedraw();
7817 case SCI_GETEXTRADESCENT
:
7818 return vs
.extraDescent
;
7820 case SCI_MARGINSETSTYLEOFFSET
:
7821 vs
.marginStyleOffset
= static_cast<int>(wParam
);
7822 InvalidateStyleRedraw();
7825 case SCI_MARGINGETSTYLEOFFSET
:
7826 return vs
.marginStyleOffset
;
7828 case SCI_SETMARGINOPTIONS
:
7829 marginOptions
= static_cast<int>(wParam
);
7832 case SCI_GETMARGINOPTIONS
:
7833 return marginOptions
;
7835 case SCI_MARGINSETTEXT
:
7836 pdoc
->MarginSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7839 case SCI_MARGINGETTEXT
: {
7840 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7841 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7844 case SCI_MARGINSETSTYLE
:
7845 pdoc
->MarginSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7848 case SCI_MARGINGETSTYLE
: {
7849 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7853 case SCI_MARGINSETSTYLES
:
7854 pdoc
->MarginSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7857 case SCI_MARGINGETSTYLES
: {
7858 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7859 return BytesResult(lParam
, st
.styles
, st
.length
);
7862 case SCI_MARGINTEXTCLEARALL
:
7863 pdoc
->MarginClearAll();
7866 case SCI_ANNOTATIONSETTEXT
:
7867 pdoc
->AnnotationSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7870 case SCI_ANNOTATIONGETTEXT
: {
7871 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7872 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7875 case SCI_ANNOTATIONGETSTYLE
: {
7876 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7880 case SCI_ANNOTATIONSETSTYLE
:
7881 pdoc
->AnnotationSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7884 case SCI_ANNOTATIONSETSTYLES
:
7885 pdoc
->AnnotationSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7888 case SCI_ANNOTATIONGETSTYLES
: {
7889 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7890 return BytesResult(lParam
, st
.styles
, st
.length
);
7893 case SCI_ANNOTATIONGETLINES
:
7894 return pdoc
->AnnotationLines(static_cast<int>(wParam
));
7896 case SCI_ANNOTATIONCLEARALL
:
7897 pdoc
->AnnotationClearAll();
7900 case SCI_ANNOTATIONSETVISIBLE
:
7901 SetAnnotationVisible(static_cast<int>(wParam
));
7904 case SCI_ANNOTATIONGETVISIBLE
:
7905 return vs
.annotationVisible
;
7907 case SCI_ANNOTATIONSETSTYLEOFFSET
:
7908 vs
.annotationStyleOffset
= static_cast<int>(wParam
);
7909 InvalidateStyleRedraw();
7912 case SCI_ANNOTATIONGETSTYLEOFFSET
:
7913 return vs
.annotationStyleOffset
;
7915 case SCI_RELEASEALLEXTENDEDSTYLES
:
7916 vs
.ReleaseAllExtendedStyles();
7919 case SCI_ALLOCATEEXTENDEDSTYLES
:
7920 return vs
.AllocateExtendedStyles(static_cast<int>(wParam
));
7922 case SCI_ADDUNDOACTION
:
7923 pdoc
->AddUndoAction(static_cast<int>(wParam
), lParam
& UNDO_MAY_COALESCE
);
7926 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH
:
7927 mouseSelectionRectangularSwitch
= wParam
!= 0;
7930 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH
:
7931 return mouseSelectionRectangularSwitch
;
7933 case SCI_SETMULTIPLESELECTION
:
7934 multipleSelection
= wParam
!= 0;
7938 case SCI_GETMULTIPLESELECTION
:
7939 return multipleSelection
;
7941 case SCI_SETADDITIONALSELECTIONTYPING
:
7942 additionalSelectionTyping
= wParam
!= 0;
7946 case SCI_GETADDITIONALSELECTIONTYPING
:
7947 return additionalSelectionTyping
;
7949 case SCI_SETMULTIPASTE
:
7950 multiPasteMode
= static_cast<int>(wParam
);
7953 case SCI_GETMULTIPASTE
:
7954 return multiPasteMode
;
7956 case SCI_SETADDITIONALCARETSBLINK
:
7957 view
.additionalCaretsBlink
= wParam
!= 0;
7961 case SCI_GETADDITIONALCARETSBLINK
:
7962 return view
.additionalCaretsBlink
;
7964 case SCI_SETADDITIONALCARETSVISIBLE
:
7965 view
.additionalCaretsVisible
= wParam
!= 0;
7969 case SCI_GETADDITIONALCARETSVISIBLE
:
7970 return view
.additionalCaretsVisible
;
7972 case SCI_GETSELECTIONS
:
7975 case SCI_GETSELECTIONEMPTY
:
7978 case SCI_CLEARSELECTIONS
:
7980 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7984 case SCI_SETSELECTION
:
7985 sel
.SetSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7989 case SCI_ADDSELECTION
:
7990 sel
.AddSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7991 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7995 case SCI_DROPSELECTIONN
:
7996 sel
.DropSelection(static_cast<int>(wParam
));
7997 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
8001 case SCI_SETMAINSELECTION
:
8002 sel
.SetMain(static_cast<int>(wParam
));
8003 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
8007 case SCI_GETMAINSELECTION
:
8010 case SCI_SETSELECTIONNCARET
:
8011 case SCI_SETSELECTIONNANCHOR
:
8012 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
8013 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
8014 case SCI_SETSELECTIONNSTART
:
8015 case SCI_SETSELECTIONNEND
:
8016 SetSelectionNMessage(iMessage
, wParam
, lParam
);
8019 case SCI_GETSELECTIONNCARET
:
8020 return sel
.Range(wParam
).caret
.Position();
8022 case SCI_GETSELECTIONNANCHOR
:
8023 return sel
.Range(wParam
).anchor
.Position();
8025 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
8026 return sel
.Range(wParam
).caret
.VirtualSpace();
8028 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
8029 return sel
.Range(wParam
).anchor
.VirtualSpace();
8031 case SCI_GETSELECTIONNSTART
:
8032 return sel
.Range(wParam
).Start().Position();
8034 case SCI_GETSELECTIONNEND
:
8035 return sel
.Range(wParam
).End().Position();
8037 case SCI_SETRECTANGULARSELECTIONCARET
:
8038 if (!sel
.IsRectangular())
8040 sel
.selType
= Selection::selRectangle
;
8041 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
8042 SetRectangularRange();
8046 case SCI_GETRECTANGULARSELECTIONCARET
:
8047 return sel
.Rectangular().caret
.Position();
8049 case SCI_SETRECTANGULARSELECTIONANCHOR
:
8050 if (!sel
.IsRectangular())
8052 sel
.selType
= Selection::selRectangle
;
8053 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
8054 SetRectangularRange();
8058 case SCI_GETRECTANGULARSELECTIONANCHOR
:
8059 return sel
.Rectangular().anchor
.Position();
8061 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
8062 if (!sel
.IsRectangular())
8064 sel
.selType
= Selection::selRectangle
;
8065 sel
.Rectangular().caret
.SetVirtualSpace(static_cast<int>(wParam
));
8066 SetRectangularRange();
8070 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
8071 return sel
.Rectangular().caret
.VirtualSpace();
8073 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
8074 if (!sel
.IsRectangular())
8076 sel
.selType
= Selection::selRectangle
;
8077 sel
.Rectangular().anchor
.SetVirtualSpace(static_cast<int>(wParam
));
8078 SetRectangularRange();
8082 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
8083 return sel
.Rectangular().anchor
.VirtualSpace();
8085 case SCI_SETVIRTUALSPACEOPTIONS
:
8086 virtualSpaceOptions
= static_cast<int>(wParam
);
8089 case SCI_GETVIRTUALSPACEOPTIONS
:
8090 return virtualSpaceOptions
;
8092 case SCI_SETADDITIONALSELFORE
:
8093 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(wParam
));
8094 InvalidateStyleRedraw();
8097 case SCI_SETADDITIONALSELBACK
:
8098 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(wParam
));
8099 InvalidateStyleRedraw();
8102 case SCI_SETADDITIONALSELALPHA
:
8103 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
8104 InvalidateStyleRedraw();
8107 case SCI_GETADDITIONALSELALPHA
:
8108 return vs
.selAdditionalAlpha
;
8110 case SCI_SETADDITIONALCARETFORE
:
8111 vs
.additionalCaretColour
= ColourDesired(static_cast<long>(wParam
));
8112 InvalidateStyleRedraw();
8115 case SCI_GETADDITIONALCARETFORE
:
8116 return vs
.additionalCaretColour
.AsLong();
8118 case SCI_ROTATESELECTION
:
8120 InvalidateWholeSelection();
8123 case SCI_SWAPMAINANCHORCARET
:
8124 InvalidateSelection(sel
.RangeMain());
8125 sel
.RangeMain().Swap();
8128 case SCI_MULTIPLESELECTADDNEXT
:
8129 MultipleSelectAdd(addOne
);
8132 case SCI_MULTIPLESELECTADDEACH
:
8133 MultipleSelectAdd(addEach
);
8136 case SCI_CHANGELEXERSTATE
:
8137 pdoc
->ChangeLexerState(static_cast<int>(wParam
), static_cast<int>(lParam
));
8140 case SCI_SETIDENTIFIER
:
8141 SetCtrlID(static_cast<int>(wParam
));
8144 case SCI_GETIDENTIFIER
:
8147 case SCI_SETTECHNOLOGY
:
8148 // No action by default
8151 case SCI_GETTECHNOLOGY
:
8154 case SCI_COUNTCHARACTERS
:
8155 return pdoc
->CountCharacters(static_cast<int>(wParam
), static_cast<int>(lParam
));
8158 return DefWndProc(iMessage
, wParam
, lParam
);
8160 //Platform::DebugPrintf("end wnd proc\n");