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;
118 doubleClickCloseThreshold
= Point(3, 3);
119 dwellDelay
= SC_TIME_FOREVER
;
120 ticksToDwell
= SC_TIME_FOREVER
;
125 dropWentOutside
= false;
126 posDrop
= SelectionPosition(invalidPosition
);
127 hotSpotClickPos
= INVALID_POSITION
;
128 selectionType
= selChar
;
132 originalAnchorPos
= 0;
133 wordSelectAnchorStartPos
= 0;
134 wordSelectAnchorEndPos
= 0;
135 wordSelectInitialCaretPos
= -1;
137 caretXPolicy
= CARET_SLOP
| CARET_EVEN
;
140 caretYPolicy
= CARET_EVEN
;
149 horizontalScrollBarVisible
= true;
151 verticalScrollBarVisible
= true;
152 endAtLastLine
= true;
153 caretSticky
= SC_CARETSTICKY_OFF
;
154 marginOptions
= SC_MARGINOPTION_NONE
;
155 mouseSelectionRectangularSwitch
= false;
156 multipleSelection
= false;
157 additionalSelectionTyping
= false;
158 multiPasteMode
= SC_MULTIPASTE_ONCE
;
159 virtualSpaceOptions
= SCVS_NONE
;
168 lengthForEncode
= -1;
171 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
173 paintState
= notPainting
;
174 paintAbandonedByStyling
= false;
175 paintingAllText
= false;
176 willRedrawAll
= false;
177 idleStyling
= SC_IDLESTYLING_NONE
;
178 needIdleStyling
= false;
180 modEventMask
= SC_MODEVENTMASKALL
;
182 pdoc
->AddWatcher(this, 0);
184 recordingMacro
= false;
187 convertPastes
= true;
189 SetRepresentations();
193 pdoc
->RemoveWatcher(this, 0);
197 void Editor::Finalise() {
202 void Editor::SetRepresentations() {
206 const char *reps
[] = {
207 "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
208 "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
209 "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
210 "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
212 for (size_t j
=0; j
< ELEMENTS(reps
); j
++) {
213 char c
[2] = { static_cast<char>(j
), 0 };
214 reprs
.SetRepresentation(c
, reps
[j
]);
218 // As well as Unicode mode, ISO-8859-1 should use these
219 if (IsUnicodeMode()) {
220 const char *repsC1
[] = {
221 "PAD", "HOP", "BPH", "NBH", "IND", "NEL", "SSA", "ESA",
222 "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
223 "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
224 "SOS", "SGCI", "SCI", "CSI", "ST", "OSC", "PM", "APC"
226 for (size_t j
=0; j
< ELEMENTS(repsC1
); j
++) {
227 char c1
[3] = { '\xc2', static_cast<char>(0x80+j
), 0 };
228 reprs
.SetRepresentation(c1
, repsC1
[j
]);
230 reprs
.SetRepresentation("\xe2\x80\xa8", "LS");
231 reprs
.SetRepresentation("\xe2\x80\xa9", "PS");
234 // UTF-8 invalid bytes
235 if (IsUnicodeMode()) {
236 for (int k
=0x80; k
< 0x100; k
++) {
237 char hiByte
[2] = { static_cast<char>(k
), 0 };
239 sprintf(hexits
, "x%2X", k
);
240 reprs
.SetRepresentation(hiByte
, hexits
);
245 void Editor::DropGraphics(bool freeObjects
) {
246 marginView
.DropGraphics(freeObjects
);
247 view
.DropGraphics(freeObjects
);
250 void Editor::AllocateGraphics() {
251 marginView
.AllocateGraphics(vs
);
252 view
.AllocateGraphics(vs
);
255 void Editor::InvalidateStyleData() {
257 vs
.technology
= technology
;
260 view
.llc
.Invalidate(LineLayout::llInvalid
);
261 view
.posCache
.Clear();
264 void Editor::InvalidateStyleRedraw() {
266 InvalidateStyleData();
270 void Editor::RefreshStyleData() {
273 AutoSurface
surface(this);
275 vs
.Refresh(*surface
, pdoc
->tabInChars
);
278 SetRectangularRange();
282 Point
Editor::GetVisibleOriginInMain() const {
286 Point
Editor::DocumentPointFromView(Point ptView
) const {
287 Point ptDocument
= ptView
;
288 if (wMargin
.GetID()) {
289 Point ptOrigin
= GetVisibleOriginInMain();
290 ptDocument
.x
+= ptOrigin
.x
;
291 ptDocument
.y
+= ptOrigin
.y
;
293 ptDocument
.x
+= xOffset
;
294 ptDocument
.y
+= topLine
* vs
.lineHeight
;
299 int Editor::TopLineOfMain() const {
306 PRectangle
Editor::GetClientRectangle() const {
307 Window
&win
= const_cast<Window
&>(wMain
);
308 return win
.GetClientPosition();
311 PRectangle
Editor::GetClientDrawingRectangle() {
312 return GetClientRectangle();
315 PRectangle
Editor::GetTextRectangle() const {
316 PRectangle rc
= GetClientRectangle();
317 rc
.left
+= vs
.textStart
;
318 rc
.right
-= vs
.rightMarginWidth
;
322 int Editor::LinesOnScreen() const {
323 PRectangle rcClient
= GetClientRectangle();
324 int htClient
= static_cast<int>(rcClient
.bottom
- rcClient
.top
);
325 //Platform::DebugPrintf("lines on screen = %d\n", htClient / lineHeight + 1);
326 return htClient
/ vs
.lineHeight
;
329 int Editor::LinesToScroll() const {
330 int retVal
= LinesOnScreen() - 1;
337 int Editor::MaxScrollPos() const {
338 //Platform::DebugPrintf("Lines %d screen = %d maxScroll = %d\n",
339 //LinesTotal(), LinesOnScreen(), LinesTotal() - LinesOnScreen() + 1);
340 int retVal
= cs
.LinesDisplayed();
342 retVal
-= LinesOnScreen();
353 SelectionPosition
Editor::ClampPositionIntoDocument(SelectionPosition sp
) const {
354 if (sp
.Position() < 0) {
355 return SelectionPosition(0);
356 } else if (sp
.Position() > pdoc
->Length()) {
357 return SelectionPosition(pdoc
->Length());
359 // If not at end of line then set offset to 0
360 if (!pdoc
->IsLineEndPosition(sp
.Position()))
361 sp
.SetVirtualSpace(0);
366 Point
Editor::LocationFromPosition(SelectionPosition pos
) {
368 AutoSurface
surface(this);
369 return view
.LocationFromPosition(surface
, *this, pos
, topLine
, vs
);
372 Point
Editor::LocationFromPosition(int pos
) {
373 return LocationFromPosition(SelectionPosition(pos
));
376 int Editor::XFromPosition(int pos
) {
377 Point pt
= LocationFromPosition(pos
);
378 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
381 int Editor::XFromPosition(SelectionPosition sp
) {
382 Point pt
= LocationFromPosition(sp
);
383 return static_cast<int>(pt
.x
) - vs
.textStart
+ xOffset
;
386 SelectionPosition
Editor::SPositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
, bool virtualSpace
) {
388 AutoSurface
surface(this);
390 if (canReturnInvalid
) {
391 PRectangle rcClient
= GetTextRectangle();
392 // May be in scroll view coordinates so translate back to main view
393 Point ptOrigin
= GetVisibleOriginInMain();
394 rcClient
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
395 if (!rcClient
.Contains(pt
))
396 return SelectionPosition(INVALID_POSITION
);
397 if (pt
.x
< vs
.textStart
)
398 return SelectionPosition(INVALID_POSITION
);
400 return SelectionPosition(INVALID_POSITION
);
402 pt
= DocumentPointFromView(pt
);
403 return view
.SPositionFromLocation(surface
, *this, pt
, canReturnInvalid
, charPosition
, virtualSpace
, vs
);
406 int Editor::PositionFromLocation(Point pt
, bool canReturnInvalid
, bool charPosition
) {
407 return SPositionFromLocation(pt
, canReturnInvalid
, charPosition
, false).Position();
411 * Find the document position corresponding to an x coordinate on a particular document line.
412 * Ensure is between whole characters when document is in multi-byte or UTF-8 mode.
413 * This method is used for rectangular selections and does not work on wrapped lines.
415 SelectionPosition
Editor::SPositionFromLineX(int lineDoc
, int x
) {
417 if (lineDoc
>= pdoc
->LinesTotal())
418 return SelectionPosition(pdoc
->Length());
419 //Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine);
420 AutoSurface
surface(this);
421 return view
.SPositionFromLineX(surface
, *this, lineDoc
, x
, vs
);
424 int Editor::PositionFromLineX(int lineDoc
, int x
) {
425 return SPositionFromLineX(lineDoc
, x
).Position();
428 int Editor::LineFromLocation(Point pt
) const {
429 return cs
.DocFromDisplay(static_cast<int>(pt
.y
) / vs
.lineHeight
+ topLine
);
432 void Editor::SetTopLine(int topLineNew
) {
433 if ((topLine
!= topLineNew
) && (topLineNew
>= 0)) {
434 topLine
= topLineNew
;
435 ContainerNeedsUpdate(SC_UPDATE_V_SCROLL
);
437 posTopLine
= pdoc
->LineStart(cs
.DocFromDisplay(topLine
));
441 * If painting then abandon the painting because a wider redraw is needed.
442 * @return true if calling code should stop drawing.
444 bool Editor::AbandonPaint() {
445 if ((paintState
== painting
) && !paintingAllText
) {
446 paintState
= paintAbandoned
;
448 return paintState
== paintAbandoned
;
451 void Editor::RedrawRect(PRectangle rc
) {
452 //Platform::DebugPrintf("Redraw %0d,%0d - %0d,%0d\n", rc.left, rc.top, rc.right, rc.bottom);
454 // Clip the redraw rectangle into the client area
455 PRectangle rcClient
= GetClientRectangle();
456 if (rc
.top
< rcClient
.top
)
457 rc
.top
= rcClient
.top
;
458 if (rc
.bottom
> rcClient
.bottom
)
459 rc
.bottom
= rcClient
.bottom
;
460 if (rc
.left
< rcClient
.left
)
461 rc
.left
= rcClient
.left
;
462 if (rc
.right
> rcClient
.right
)
463 rc
.right
= rcClient
.right
;
465 if ((rc
.bottom
> rc
.top
) && (rc
.right
> rc
.left
)) {
466 wMain
.InvalidateRectangle(rc
);
470 void Editor::DiscardOverdraw() {
471 // Overridden on platforms that may draw outside visible area.
474 void Editor::Redraw() {
475 //Platform::DebugPrintf("Redraw all\n");
476 PRectangle rcClient
= GetClientRectangle();
477 wMain
.InvalidateRectangle(rcClient
);
479 wMargin
.InvalidateAll();
480 //wMain.InvalidateAll();
483 void Editor::RedrawSelMargin(int line
, bool allAfter
) {
484 const bool markersInText
= vs
.maskInLine
|| vs
.maskDrawInText
;
485 if (!wMargin
.GetID() || markersInText
) { // May affect text area so may need to abandon and retry
486 if (AbandonPaint()) {
490 if (wMargin
.GetID() && markersInText
) {
494 PRectangle rcMarkers
= GetClientRectangle();
495 if (!markersInText
) {
496 // Normal case: just draw the margin
497 rcMarkers
.right
= rcMarkers
.left
+ vs
.fixedColumnWidth
;
500 PRectangle rcLine
= RectangleFromRange(Range(pdoc
->LineStart(line
)), 0);
502 // Inflate line rectangle if there are image markers with height larger than line height
503 if (vs
.largestMarkerHeight
> vs
.lineHeight
) {
504 int delta
= (vs
.largestMarkerHeight
- vs
.lineHeight
+ 1) / 2;
506 rcLine
.bottom
+= delta
;
507 if (rcLine
.top
< rcMarkers
.top
)
508 rcLine
.top
= rcMarkers
.top
;
509 if (rcLine
.bottom
> rcMarkers
.bottom
)
510 rcLine
.bottom
= rcMarkers
.bottom
;
513 rcMarkers
.top
= rcLine
.top
;
515 rcMarkers
.bottom
= rcLine
.bottom
;
516 if (rcMarkers
.Empty())
519 if (wMargin
.GetID()) {
520 Point ptOrigin
= GetVisibleOriginInMain();
521 rcMarkers
.Move(-ptOrigin
.x
, -ptOrigin
.y
);
522 wMargin
.InvalidateRectangle(rcMarkers
);
524 wMain
.InvalidateRectangle(rcMarkers
);
528 PRectangle
Editor::RectangleFromRange(Range r
, int overlap
) {
529 const int minLine
= cs
.DisplayFromDoc(pdoc
->LineFromPosition(r
.First()));
530 const int maxLine
= cs
.DisplayLastFromDoc(pdoc
->LineFromPosition(r
.Last()));
531 const PRectangle rcClientDrawing
= GetClientDrawingRectangle();
533 const int leftTextOverlap
= ((xOffset
== 0) && (vs
.leftMarginWidth
> 0)) ? 1 : 0;
534 rc
.left
= static_cast<XYPOSITION
>(vs
.textStart
- leftTextOverlap
);
535 rc
.top
= static_cast<XYPOSITION
>((minLine
- TopLineOfMain()) * vs
.lineHeight
- overlap
);
536 if (rc
.top
< rcClientDrawing
.top
)
537 rc
.top
= rcClientDrawing
.top
;
538 // Extend to right of prepared area if any to prevent artifacts from caret line highlight
539 rc
.right
= rcClientDrawing
.right
;
540 rc
.bottom
= static_cast<XYPOSITION
>((maxLine
- TopLineOfMain() + 1) * vs
.lineHeight
+ overlap
);
545 void Editor::InvalidateRange(int start
, int end
) {
546 RedrawRect(RectangleFromRange(Range(start
, end
), view
.LinesOverlap() ? vs
.lineOverlap
: 0));
549 int Editor::CurrentPosition() const {
550 return sel
.MainCaret();
553 bool Editor::SelectionEmpty() const {
557 SelectionPosition
Editor::SelectionStart() {
558 return sel
.RangeMain().Start();
561 SelectionPosition
Editor::SelectionEnd() {
562 return sel
.RangeMain().End();
565 void Editor::SetRectangularRange() {
566 if (sel
.IsRectangular()) {
567 int xAnchor
= XFromPosition(sel
.Rectangular().anchor
);
568 int xCaret
= XFromPosition(sel
.Rectangular().caret
);
569 if (sel
.selType
== Selection::selThin
) {
572 int lineAnchorRect
= pdoc
->LineFromPosition(sel
.Rectangular().anchor
.Position());
573 int lineCaret
= pdoc
->LineFromPosition(sel
.Rectangular().caret
.Position());
574 int increment
= (lineCaret
> lineAnchorRect
) ? 1 : -1;
575 for (int line
=lineAnchorRect
; line
!= lineCaret
+increment
; line
+= increment
) {
576 SelectionRange
range(SPositionFromLineX(line
, xCaret
), SPositionFromLineX(line
, xAnchor
));
577 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) == 0)
578 range
.ClearVirtualSpace();
579 if (line
== lineAnchorRect
)
580 sel
.SetSelection(range
);
582 sel
.AddSelectionWithoutTrim(range
);
587 void Editor::ThinRectangularRange() {
588 if (sel
.IsRectangular()) {
589 sel
.selType
= Selection::selThin
;
590 if (sel
.Rectangular().caret
< sel
.Rectangular().anchor
) {
591 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).caret
, sel
.Range(0).anchor
);
593 sel
.Rectangular() = SelectionRange(sel
.Range(sel
.Count()-1).anchor
, sel
.Range(0).caret
);
595 SetRectangularRange();
599 void Editor::InvalidateSelection(SelectionRange newMain
, bool invalidateWholeSelection
) {
600 if (sel
.Count() > 1 || !(sel
.RangeMain().anchor
== newMain
.anchor
) || sel
.IsRectangular()) {
601 invalidateWholeSelection
= true;
603 int firstAffected
= Platform::Minimum(sel
.RangeMain().Start().Position(), newMain
.Start().Position());
604 // +1 for lastAffected ensures caret repainted
605 int lastAffected
= Platform::Maximum(newMain
.caret
.Position()+1, newMain
.anchor
.Position());
606 lastAffected
= Platform::Maximum(lastAffected
, sel
.RangeMain().End().Position());
607 if (invalidateWholeSelection
) {
608 for (size_t r
=0; r
<sel
.Count(); r
++) {
609 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).caret
.Position());
610 firstAffected
= Platform::Minimum(firstAffected
, sel
.Range(r
).anchor
.Position());
611 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).caret
.Position()+1);
612 lastAffected
= Platform::Maximum(lastAffected
, sel
.Range(r
).anchor
.Position());
615 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
616 InvalidateRange(firstAffected
, lastAffected
);
619 void Editor::InvalidateWholeSelection() {
620 InvalidateSelection(sel
.RangeMain(), true);
623 void Editor::SetSelection(SelectionPosition currentPos_
, SelectionPosition anchor_
) {
624 currentPos_
= ClampPositionIntoDocument(currentPos_
);
625 anchor_
= ClampPositionIntoDocument(anchor_
);
626 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
627 /* For Line selection - ensure the anchor and caret are always
628 at the beginning and end of the region lines. */
629 if (sel
.selType
== Selection::selLines
) {
630 if (currentPos_
> anchor_
) {
631 anchor_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(anchor_
.Position())));
632 currentPos_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(currentPos_
.Position())));
634 currentPos_
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(currentPos_
.Position())));
635 anchor_
= SelectionPosition(pdoc
->LineEnd(pdoc
->LineFromPosition(anchor_
.Position())));
638 SelectionRange
rangeNew(currentPos_
, anchor_
);
639 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
640 InvalidateSelection(rangeNew
);
642 sel
.RangeMain() = rangeNew
;
643 SetRectangularRange();
645 SetHoverIndicatorPosition(sel
.MainCaret());
647 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
650 QueueIdleWork(WorkNeeded::workUpdateUI
);
653 void Editor::SetSelection(int currentPos_
, int anchor_
) {
654 SetSelection(SelectionPosition(currentPos_
), SelectionPosition(anchor_
));
657 // Just move the caret on the main selection
658 void Editor::SetSelection(SelectionPosition currentPos_
) {
659 currentPos_
= ClampPositionIntoDocument(currentPos_
);
660 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
661 if (sel
.Count() > 1 || !(sel
.RangeMain().caret
== currentPos_
)) {
662 InvalidateSelection(SelectionRange(currentPos_
));
664 if (sel
.IsRectangular()) {
666 SelectionRange(SelectionPosition(currentPos_
), sel
.Rectangular().anchor
);
667 SetRectangularRange();
670 SelectionRange(SelectionPosition(currentPos_
), sel
.RangeMain().anchor
);
673 SetHoverIndicatorPosition(sel
.MainCaret());
675 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
678 QueueIdleWork(WorkNeeded::workUpdateUI
);
681 void Editor::SetSelection(int currentPos_
) {
682 SetSelection(SelectionPosition(currentPos_
));
685 void Editor::SetEmptySelection(SelectionPosition currentPos_
) {
686 int currentLine
= pdoc
->LineFromPosition(currentPos_
.Position());
687 SelectionRange
rangeNew(ClampPositionIntoDocument(currentPos_
));
688 if (sel
.Count() > 1 || !(sel
.RangeMain() == rangeNew
)) {
689 InvalidateSelection(rangeNew
);
692 sel
.RangeMain() = rangeNew
;
693 SetRectangularRange();
695 SetHoverIndicatorPosition(sel
.MainCaret());
697 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
700 QueueIdleWork(WorkNeeded::workUpdateUI
);
703 void Editor::SetEmptySelection(int currentPos_
) {
704 SetEmptySelection(SelectionPosition(currentPos_
));
707 void Editor::MultipleSelectAdd(AddNumber addNumber
) {
708 if (SelectionEmpty() || !multipleSelection
) {
709 // Select word at caret
710 const int startWord
= pdoc
->ExtendWordSelect(sel
.MainCaret(), -1, true);
711 const int endWord
= pdoc
->ExtendWordSelect(startWord
, 1, true);
712 TrimAndSetSelection(endWord
, startWord
);
716 if (!pdoc
->HasCaseFolder())
717 pdoc
->SetCaseFolder(CaseFolderForEncoding());
719 const Range
rangeMainSelection(sel
.RangeMain().Start().Position(), sel
.RangeMain().End().Position());
720 const std::string selectedText
= RangeText(rangeMainSelection
.start
, rangeMainSelection
.end
);
722 const Range
rangeTarget(targetStart
, targetEnd
);
723 std::vector
<Range
> searchRanges
;
724 // Search should be over the target range excluding the current selection so
725 // may need to search 2 ranges, after the selection then before the selection.
726 if (rangeTarget
.Overlaps(rangeMainSelection
)) {
727 // Common case is that the selection is completely within the target but
728 // may also have overlap at start or end.
729 if (rangeMainSelection
.end
< rangeTarget
.end
)
730 searchRanges
.push_back(Range(rangeMainSelection
.end
, rangeTarget
.end
));
731 if (rangeTarget
.start
< rangeMainSelection
.start
)
732 searchRanges
.push_back(Range(rangeTarget
.start
, rangeMainSelection
.start
));
735 searchRanges
.push_back(rangeTarget
);
738 for (std::vector
<Range
>::const_iterator it
= searchRanges
.begin(); it
!= searchRanges
.end(); ++it
) {
739 int searchStart
= it
->start
;
740 const int searchEnd
= it
->end
;
742 int lengthFound
= static_cast<int>(selectedText
.length());
743 int pos
= pdoc
->FindText(searchStart
, searchEnd
, selectedText
.c_str(),
744 searchFlags
, &lengthFound
);
746 sel
.AddSelection(SelectionRange(pos
+ lengthFound
, pos
));
747 ScrollRange(sel
.RangeMain());
749 if (addNumber
== addOne
)
751 searchStart
= pos
+ lengthFound
;
760 bool Editor::RangeContainsProtected(int start
, int end
) const {
761 if (vs
.ProtectionActive()) {
767 for (int pos
= start
; pos
< end
; pos
++) {
768 if (vs
.styles
[pdoc
->StyleIndexAt(pos
)].IsProtected())
775 bool Editor::SelectionContainsProtected() {
776 for (size_t r
=0; r
<sel
.Count(); r
++) {
777 if (RangeContainsProtected(sel
.Range(r
).Start().Position(),
778 sel
.Range(r
).End().Position())) {
786 * Asks document to find a good position and then moves out of any invisible positions.
788 int Editor::MovePositionOutsideChar(int pos
, int moveDir
, bool checkLineEnd
) const {
789 return MovePositionOutsideChar(SelectionPosition(pos
), moveDir
, checkLineEnd
).Position();
792 SelectionPosition
Editor::MovePositionOutsideChar(SelectionPosition pos
, int moveDir
, bool checkLineEnd
) const {
793 int posMoved
= pdoc
->MovePositionOutsideChar(pos
.Position(), moveDir
, checkLineEnd
);
794 if (posMoved
!= pos
.Position())
795 pos
.SetPosition(posMoved
);
796 if (vs
.ProtectionActive()) {
798 if ((pos
.Position() > 0) && vs
.styles
[pdoc
->StyleIndexAt(pos
.Position() - 1)].IsProtected()) {
799 while ((pos
.Position() < pdoc
->Length()) &&
800 (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position())].IsProtected()))
803 } else if (moveDir
< 0) {
804 if (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position())].IsProtected()) {
805 while ((pos
.Position() > 0) &&
806 (vs
.styles
[pdoc
->StyleIndexAt(pos
.Position() - 1)].IsProtected()))
814 void Editor::MovedCaret(SelectionPosition newPos
, SelectionPosition previousPos
, bool ensureVisible
) {
815 const int currentLine
= pdoc
->LineFromPosition(newPos
.Position());
817 // In case in need of wrapping to ensure DisplayFromDoc works.
818 if (currentLine
>= wrapPending
.start
)
820 XYScrollPosition newXY
= XYScrollToMakeVisible(
821 SelectionRange(posDrag
.IsValid() ? posDrag
: newPos
), xysDefault
);
822 if (previousPos
.IsValid() && (newXY
.xOffset
== xOffset
)) {
823 // simple vertical scroll then invalidate
824 ScrollTo(newXY
.topLine
);
825 InvalidateSelection(SelectionRange(previousPos
), true);
831 ShowCaretAtCurrentPosition();
834 SetHoverIndicatorPosition(sel
.MainCaret());
835 QueueIdleWork(WorkNeeded::workUpdateUI
);
837 if (marginView
.highlightDelimiter
.NeedsDrawing(currentLine
)) {
842 void Editor::MovePositionTo(SelectionPosition newPos
, Selection::selTypes selt
, bool ensureVisible
) {
843 const SelectionPosition spCaret
= ((sel
.Count() == 1) && sel
.Empty()) ?
844 sel
.Last() : SelectionPosition(INVALID_POSITION
);
846 int delta
= newPos
.Position() - sel
.MainCaret();
847 newPos
= ClampPositionIntoDocument(newPos
);
848 newPos
= MovePositionOutsideChar(newPos
, delta
);
849 if (!multipleSelection
&& sel
.IsRectangular() && (selt
== Selection::selStream
)) {
850 // Can't turn into multiple selection so clear additional selections
851 InvalidateSelection(SelectionRange(newPos
), true);
852 sel
.DropAdditionalRanges();
854 if (!sel
.IsRectangular() && (selt
== Selection::selRectangle
)) {
855 // Switching to rectangular
856 InvalidateSelection(sel
.RangeMain(), false);
857 SelectionRange rangeMain
= sel
.RangeMain();
859 sel
.Rectangular() = rangeMain
;
861 if (selt
!= Selection::noSel
) {
864 if (selt
!= Selection::noSel
|| sel
.MoveExtends()) {
865 SetSelection(newPos
);
867 SetEmptySelection(newPos
);
870 MovedCaret(newPos
, spCaret
, ensureVisible
);
873 void Editor::MovePositionTo(int newPos
, Selection::selTypes selt
, bool ensureVisible
) {
874 MovePositionTo(SelectionPosition(newPos
), selt
, ensureVisible
);
877 SelectionPosition
Editor::MovePositionSoVisible(SelectionPosition pos
, int moveDir
) {
878 pos
= ClampPositionIntoDocument(pos
);
879 pos
= MovePositionOutsideChar(pos
, moveDir
);
880 int lineDoc
= pdoc
->LineFromPosition(pos
.Position());
881 if (cs
.GetVisible(lineDoc
)) {
884 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
886 // lineDisplay is already line before fold as lines in fold use display line of line after fold
887 lineDisplay
= Platform::Clamp(lineDisplay
, 0, cs
.LinesDisplayed());
888 return SelectionPosition(pdoc
->LineStart(cs
.DocFromDisplay(lineDisplay
)));
890 lineDisplay
= Platform::Clamp(lineDisplay
- 1, 0, cs
.LinesDisplayed());
891 return SelectionPosition(pdoc
->LineEnd(cs
.DocFromDisplay(lineDisplay
)));
896 SelectionPosition
Editor::MovePositionSoVisible(int pos
, int moveDir
) {
897 return MovePositionSoVisible(SelectionPosition(pos
), moveDir
);
900 Point
Editor::PointMainCaret() {
901 return LocationFromPosition(sel
.Range(sel
.Main()).caret
);
905 * Choose the x position that the caret will try to stick to
906 * as it moves up and down.
908 void Editor::SetLastXChosen() {
909 Point pt
= PointMainCaret();
910 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
913 void Editor::ScrollTo(int line
, bool moveThumb
) {
914 int topLineNew
= Platform::Clamp(line
, 0, MaxScrollPos());
915 if (topLineNew
!= topLine
) {
916 // Try to optimise small scrolls
918 int linesToMove
= topLine
- topLineNew
;
919 bool performBlit
= (abs(linesToMove
) <= 10) && (paintState
== notPainting
);
920 willRedrawAll
= !performBlit
;
922 SetTopLine(topLineNew
);
923 // Optimize by styling the view as this will invalidate any needed area
924 // which could abort the initial paint if discovered later.
925 StyleAreaBounded(GetClientRectangle(), true);
927 // Perform redraw rather than scroll if many lines would be redrawn anyway.
929 ScrollText(linesToMove
);
933 willRedrawAll
= false;
938 SetVerticalScrollPos();
943 void Editor::ScrollText(int /* linesToMove */) {
944 //Platform::DebugPrintf("Editor::ScrollText %d\n", linesToMove);
948 void Editor::HorizontalScrollTo(int xPos
) {
949 //Platform::DebugPrintf("HorizontalScroll %d\n", xPos);
952 if (!Wrapping() && (xOffset
!= xPos
)) {
954 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
955 SetHorizontalScrollPos();
956 RedrawRect(GetClientRectangle());
960 void Editor::VerticalCentreCaret() {
961 int lineDoc
= pdoc
->LineFromPosition(sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret());
962 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
963 int newTop
= lineDisplay
- (LinesOnScreen() / 2);
964 if (topLine
!= newTop
) {
965 SetTopLine(newTop
> 0 ? newTop
: 0);
966 RedrawRect(GetClientRectangle());
970 // Avoid 64 bit compiler warnings.
971 // Scintilla does not support text buffers larger than 2**31
972 static int istrlen(const char *s
) {
973 return static_cast<int>(s
? strlen(s
) : 0);
976 void Editor::MoveSelectedLines(int lineDelta
) {
978 // if selection doesn't start at the beginning of the line, set the new start
979 int selectionStart
= SelectionStart().Position();
980 int startLine
= pdoc
->LineFromPosition(selectionStart
);
981 int beginningOfStartLine
= pdoc
->LineStart(startLine
);
982 selectionStart
= beginningOfStartLine
;
984 // if selection doesn't end at the beginning of a line greater than that of the start,
985 // then set it at the beginning of the next one
986 int selectionEnd
= SelectionEnd().Position();
987 int endLine
= pdoc
->LineFromPosition(selectionEnd
);
988 int beginningOfEndLine
= pdoc
->LineStart(endLine
);
989 bool appendEol
= false;
990 if (selectionEnd
> beginningOfEndLine
991 || selectionStart
== selectionEnd
) {
992 selectionEnd
= pdoc
->LineStart(endLine
+ 1);
993 appendEol
= (selectionEnd
== pdoc
->Length() && pdoc
->LineFromPosition(selectionEnd
) == endLine
);
996 // if there's nowhere for the selection to move
997 // (i.e. at the beginning going up or at the end going down),
998 // stop it right there!
999 if ((selectionStart
== 0 && lineDelta
< 0)
1000 || (selectionEnd
== pdoc
->Length() && lineDelta
> 0)
1001 || selectionStart
== selectionEnd
) {
1007 if (lineDelta
> 0 && selectionEnd
== pdoc
->LineStart(pdoc
->LinesTotal() - 1)) {
1008 SetSelection(pdoc
->MovePositionOutsideChar(selectionEnd
- 1, -1), selectionEnd
);
1010 selectionEnd
= CurrentPosition();
1012 SetSelection(selectionStart
, selectionEnd
);
1014 SelectionText selectedText
;
1015 CopySelectionRange(&selectedText
);
1017 int selectionLength
= SelectionRange(selectionStart
, selectionEnd
).Length();
1018 Point currentLocation
= LocationFromPosition(CurrentPosition());
1019 int currentLine
= LineFromLocation(currentLocation
);
1022 SetSelection(pdoc
->MovePositionOutsideChar(selectionStart
- 1, -1), selectionEnd
);
1025 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1026 if (currentLine
+ lineDelta
>= pdoc
->LinesTotal())
1027 pdoc
->InsertString(pdoc
->Length(), eol
, istrlen(eol
));
1028 GoToLine(currentLine
+ lineDelta
);
1030 selectionLength
= pdoc
->InsertString(CurrentPosition(), selectedText
.Data(), selectionLength
);
1032 const int lengthInserted
= pdoc
->InsertString(CurrentPosition() + selectionLength
, eol
, istrlen(eol
));
1033 selectionLength
+= lengthInserted
;
1035 SetSelection(CurrentPosition(), CurrentPosition() + selectionLength
);
1038 void Editor::MoveSelectedLinesUp() {
1039 MoveSelectedLines(-1);
1042 void Editor::MoveSelectedLinesDown() {
1043 MoveSelectedLines(1);
1046 void Editor::MoveCaretInsideView(bool ensureVisible
) {
1047 PRectangle rcClient
= GetTextRectangle();
1048 Point pt
= PointMainCaret();
1049 if (pt
.y
< rcClient
.top
) {
1050 MovePositionTo(SPositionFromLocation(
1051 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
)),
1052 false, false, UserVirtualSpace()),
1053 Selection::noSel
, ensureVisible
);
1054 } else if ((pt
.y
+ vs
.lineHeight
- 1) > rcClient
.bottom
) {
1055 int yOfLastLineFullyDisplayed
= static_cast<int>(rcClient
.top
) + (LinesOnScreen() - 1) * vs
.lineHeight
;
1056 MovePositionTo(SPositionFromLocation(
1057 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(rcClient
.top
) + yOfLastLineFullyDisplayed
),
1058 false, false, UserVirtualSpace()),
1059 Selection::noSel
, ensureVisible
);
1063 int Editor::DisplayFromPosition(int pos
) {
1064 AutoSurface
surface(this);
1065 return view
.DisplayFromPosition(surface
, *this, pos
, vs
);
1069 * Ensure the caret is reasonably visible in context.
1071 Caret policy in SciTE
1073 If slop is set, we can define a slop value.
1074 This value defines an unwanted zone (UZ) where the caret is... unwanted.
1075 This zone is defined as a number of pixels near the vertical margins,
1076 and as a number of lines near the horizontal margins.
1077 By keeping the caret away from the edges, it is seen within its context,
1078 so it is likely that the identifier that the caret is on can be completely seen,
1079 and that the current line is seen with some of the lines following it which are
1080 often dependent on that line.
1082 If strict is set, the policy is enforced... strictly.
1083 The caret is centred on the display if slop is not set,
1084 and cannot go in the UZ if slop is set.
1086 If jumps is set, the display is moved more energetically
1087 so the caret can move in the same direction longer before the policy is applied again.
1088 '3UZ' notation is used to indicate three time the size of the UZ as a distance to the margin.
1090 If even is not set, instead of having symmetrical UZs,
1091 the left and bottom UZs are extended up to right and top UZs respectively.
1092 This way, we favour the displaying of useful information: the beginning of lines,
1093 where most code reside, and the lines after the caret, eg. the body of a function.
1096 slop | strict | jumps | even | Caret can go to the margin | When reaching limit (caret going out of
1097 | | | | | visibility or going into the UZ) display is...
1098 -----+--------+-------+------+--------------------------------------------+--------------------------------------------------------------
1099 0 | 0 | 0 | 0 | Yes | moved to put caret on top/on right
1100 0 | 0 | 0 | 1 | Yes | moved by one position
1101 0 | 0 | 1 | 0 | Yes | moved to put caret on top/on right
1102 0 | 0 | 1 | 1 | Yes | centred on the caret
1103 0 | 1 | - | 0 | Caret is always on top/on right of display | -
1104 0 | 1 | - | 1 | No, caret is always centred | -
1105 1 | 0 | 0 | 0 | Yes | moved to put caret out of the asymmetrical UZ
1106 1 | 0 | 0 | 1 | Yes | moved to put caret out of the UZ
1107 1 | 0 | 1 | 0 | Yes | moved to put caret at 3UZ of the top or right margin
1108 1 | 0 | 1 | 1 | Yes | moved to put caret at 3UZ of the margin
1109 1 | 1 | - | 0 | Caret is always at UZ of top/right margin | -
1110 1 | 1 | 0 | 1 | No, kept out of UZ | moved by one position
1111 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
1114 Editor::XYScrollPosition
Editor::XYScrollToMakeVisible(const SelectionRange
&range
, const XYScrollOptions options
) {
1115 PRectangle rcClient
= GetTextRectangle();
1116 Point pt
= LocationFromPosition(range
.caret
);
1117 Point ptAnchor
= LocationFromPosition(range
.anchor
);
1118 const Point ptOrigin
= GetVisibleOriginInMain();
1121 ptAnchor
.x
+= ptOrigin
.x
;
1122 ptAnchor
.y
+= ptOrigin
.y
;
1123 const Point
ptBottomCaret(pt
.x
, pt
.y
+ vs
.lineHeight
- 1);
1125 XYScrollPosition
newXY(xOffset
, topLine
);
1126 if (rcClient
.Empty()) {
1130 // Vertical positioning
1131 if ((options
& xysVertical
) && (pt
.y
< rcClient
.top
|| ptBottomCaret
.y
>= rcClient
.bottom
|| (caretYPolicy
& CARET_STRICT
) != 0)) {
1132 const int lineCaret
= DisplayFromPosition(range
.caret
.Position());
1133 const int linesOnScreen
= LinesOnScreen();
1134 const int halfScreen
= Platform::Maximum(linesOnScreen
- 1, 2) / 2;
1135 const bool bSlop
= (caretYPolicy
& CARET_SLOP
) != 0;
1136 const bool bStrict
= (caretYPolicy
& CARET_STRICT
) != 0;
1137 const bool bJump
= (caretYPolicy
& CARET_JUMPS
) != 0;
1138 const bool bEven
= (caretYPolicy
& CARET_EVEN
) != 0;
1140 // It should be possible to scroll the window to show the caret,
1141 // but this fails to remove the caret on GTK+
1142 if (bSlop
) { // A margin is defined
1145 int yMarginT
, yMarginB
;
1146 if (!(options
& xysUseMargin
)) {
1147 // In drag mode, avoid moves
1148 // otherwise, a double click will select several lines.
1149 yMarginT
= yMarginB
= 0;
1151 // yMarginT must equal to caretYSlop, with a minimum of 1 and
1152 // a maximum of slightly less than half the heigth of the text area.
1153 yMarginT
= Platform::Clamp(caretYSlop
, 1, halfScreen
);
1155 yMarginB
= yMarginT
;
1157 yMarginB
= linesOnScreen
- yMarginT
- 1;
1163 yMoveT
= Platform::Clamp(caretYSlop
* 3, 1, halfScreen
);
1167 yMoveB
= linesOnScreen
- yMoveT
- 1;
1169 if (lineCaret
< topLine
+ yMarginT
) {
1170 // Caret goes too high
1171 newXY
.topLine
= lineCaret
- yMoveT
;
1172 } else if (lineCaret
> topLine
+ linesOnScreen
- 1 - yMarginB
) {
1173 // Caret goes too low
1174 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1176 } else { // Not strict
1177 yMoveT
= bJump
? caretYSlop
* 3 : caretYSlop
;
1178 yMoveT
= Platform::Clamp(yMoveT
, 1, halfScreen
);
1182 yMoveB
= linesOnScreen
- yMoveT
- 1;
1184 if (lineCaret
< topLine
) {
1185 // Caret goes too high
1186 newXY
.topLine
= lineCaret
- yMoveT
;
1187 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1188 // Caret goes too low
1189 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1 + yMoveB
;
1193 if (!bStrict
&& !bJump
) {
1195 if (lineCaret
< topLine
) {
1196 // Caret goes too high
1197 newXY
.topLine
= lineCaret
;
1198 } else if (lineCaret
> topLine
+ linesOnScreen
- 1) {
1199 // Caret goes too low
1201 newXY
.topLine
= lineCaret
- linesOnScreen
+ 1;
1203 newXY
.topLine
= lineCaret
;
1206 } else { // Strict or going out of display
1208 // Always center caret
1209 newXY
.topLine
= lineCaret
- halfScreen
;
1211 // Always put caret on top of display
1212 newXY
.topLine
= lineCaret
;
1216 if (!(range
.caret
== range
.anchor
)) {
1217 const int lineAnchor
= DisplayFromPosition(range
.anchor
.Position());
1218 if (lineAnchor
< lineCaret
) {
1219 // Shift up to show anchor or as much of range as possible
1220 newXY
.topLine
= std::min(newXY
.topLine
, lineAnchor
);
1221 newXY
.topLine
= std::max(newXY
.topLine
, lineCaret
- LinesOnScreen());
1223 // Shift down to show anchor or as much of range as possible
1224 newXY
.topLine
= std::max(newXY
.topLine
, lineAnchor
- LinesOnScreen());
1225 newXY
.topLine
= std::min(newXY
.topLine
, lineCaret
);
1228 newXY
.topLine
= Platform::Clamp(newXY
.topLine
, 0, MaxScrollPos());
1231 // Horizontal positioning
1232 if ((options
& xysHorizontal
) && !Wrapping()) {
1233 const int halfScreen
= Platform::Maximum(static_cast<int>(rcClient
.Width()) - 4, 4) / 2;
1234 const bool bSlop
= (caretXPolicy
& CARET_SLOP
) != 0;
1235 const bool bStrict
= (caretXPolicy
& CARET_STRICT
) != 0;
1236 const bool bJump
= (caretXPolicy
& CARET_JUMPS
) != 0;
1237 const bool bEven
= (caretXPolicy
& CARET_EVEN
) != 0;
1239 if (bSlop
) { // A margin is defined
1242 int xMarginL
, xMarginR
;
1243 if (!(options
& xysUseMargin
)) {
1244 // In drag mode, avoid moves unless very near of the margin
1245 // otherwise, a simple click will select text.
1246 xMarginL
= xMarginR
= 2;
1248 // xMargin must equal to caretXSlop, with a minimum of 2 and
1249 // a maximum of slightly less than half the width of the text area.
1250 xMarginR
= Platform::Clamp(caretXSlop
, 2, halfScreen
);
1252 xMarginL
= xMarginR
;
1254 xMarginL
= static_cast<int>(rcClient
.Width()) - xMarginR
- 4;
1257 if (bJump
&& bEven
) {
1258 // Jump is used only in even mode
1259 xMoveL
= xMoveR
= Platform::Clamp(caretXSlop
* 3, 1, halfScreen
);
1261 xMoveL
= xMoveR
= 0; // Not used, avoid a warning
1263 if (pt
.x
< rcClient
.left
+ xMarginL
) {
1264 // Caret is on the left of the display
1265 if (bJump
&& bEven
) {
1266 newXY
.xOffset
-= xMoveL
;
1268 // Move just enough to allow to display the caret
1269 newXY
.xOffset
-= static_cast<int>((rcClient
.left
+ xMarginL
) - pt
.x
);
1271 } else if (pt
.x
>= rcClient
.right
- xMarginR
) {
1272 // Caret is on the right of the display
1273 if (bJump
&& bEven
) {
1274 newXY
.xOffset
+= xMoveR
;
1276 // Move just enough to allow to display the caret
1277 newXY
.xOffset
+= static_cast<int>(pt
.x
- (rcClient
.right
- xMarginR
) + 1);
1280 } else { // Not strict
1281 xMoveR
= bJump
? caretXSlop
* 3 : caretXSlop
;
1282 xMoveR
= Platform::Clamp(xMoveR
, 1, halfScreen
);
1286 xMoveL
= static_cast<int>(rcClient
.Width()) - xMoveR
- 4;
1288 if (pt
.x
< rcClient
.left
) {
1289 // Caret is on the left of the display
1290 newXY
.xOffset
-= xMoveL
;
1291 } else if (pt
.x
>= rcClient
.right
) {
1292 // Caret is on the right of the display
1293 newXY
.xOffset
+= xMoveR
;
1298 (bJump
&& (pt
.x
< rcClient
.left
|| pt
.x
>= rcClient
.right
))) {
1299 // Strict or going out of display
1302 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.left
- halfScreen
);
1304 // Put caret on right
1305 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
+ 1);
1308 // Move just enough to allow to display the caret
1309 if (pt
.x
< rcClient
.left
) {
1310 // Caret is on the left of the display
1312 newXY
.xOffset
-= static_cast<int>(rcClient
.left
- pt
.x
);
1314 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1316 } else if (pt
.x
>= rcClient
.right
) {
1317 // Caret is on the right of the display
1318 newXY
.xOffset
+= static_cast<int>(pt
.x
- rcClient
.right
) + 1;
1322 // In case of a jump (find result) largely out of display, adjust the offset to display the caret
1323 if (pt
.x
+ xOffset
< rcClient
.left
+ newXY
.xOffset
) {
1324 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 2;
1325 } else if (pt
.x
+ xOffset
>= rcClient
.right
+ newXY
.xOffset
) {
1326 newXY
.xOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 2;
1327 if ((vs
.caretStyle
== CARETSTYLE_BLOCK
) || view
.imeCaretBlockOverride
) {
1328 // Ensure we can see a good portion of the block caret
1329 newXY
.xOffset
+= static_cast<int>(vs
.aveCharWidth
);
1332 if (!(range
.caret
== range
.anchor
)) {
1333 if (ptAnchor
.x
< pt
.x
) {
1334 // Shift to left to show anchor or as much of range as possible
1335 int maxOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.left
) - 1;
1336 int minOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.right
) + 1;
1337 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1338 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1340 // Shift to right to show anchor or as much of range as possible
1341 int minOffset
= static_cast<int>(ptAnchor
.x
+ xOffset
- rcClient
.right
) + 1;
1342 int maxOffset
= static_cast<int>(pt
.x
+ xOffset
- rcClient
.left
) - 1;
1343 newXY
.xOffset
= std::max(newXY
.xOffset
, minOffset
);
1344 newXY
.xOffset
= std::min(newXY
.xOffset
, maxOffset
);
1347 if (newXY
.xOffset
< 0) {
1355 void Editor::SetXYScroll(XYScrollPosition newXY
) {
1356 if ((newXY
.topLine
!= topLine
) || (newXY
.xOffset
!= xOffset
)) {
1357 if (newXY
.topLine
!= topLine
) {
1358 SetTopLine(newXY
.topLine
);
1359 SetVerticalScrollPos();
1361 if (newXY
.xOffset
!= xOffset
) {
1362 xOffset
= newXY
.xOffset
;
1363 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
1364 if (newXY
.xOffset
> 0) {
1365 PRectangle rcText
= GetTextRectangle();
1366 if (horizontalScrollBarVisible
&&
1367 rcText
.Width() + xOffset
> scrollWidth
) {
1368 scrollWidth
= xOffset
+ static_cast<int>(rcText
.Width());
1372 SetHorizontalScrollPos();
1375 UpdateSystemCaret();
1379 void Editor::ScrollRange(SelectionRange range
) {
1380 SetXYScroll(XYScrollToMakeVisible(range
, xysDefault
));
1383 void Editor::EnsureCaretVisible(bool useMargin
, bool vert
, bool horiz
) {
1384 SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag
.IsValid() ? posDrag
: sel
.RangeMain().caret
),
1385 static_cast<XYScrollOptions
>((useMargin
?xysUseMargin
:0)|(vert
?xysVertical
:0)|(horiz
?xysHorizontal
:0))));
1388 void Editor::ShowCaretAtCurrentPosition() {
1390 caret
.active
= true;
1392 if (FineTickerAvailable()) {
1393 FineTickerCancel(tickCaret
);
1394 if (caret
.period
> 0)
1395 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1400 caret
.active
= false;
1402 if (FineTickerAvailable()) {
1403 FineTickerCancel(tickCaret
);
1409 void Editor::DropCaret() {
1410 caret
.active
= false;
1411 if (FineTickerAvailable()) {
1412 FineTickerCancel(tickCaret
);
1417 void Editor::CaretSetPeriod(int period
) {
1418 if (caret
.period
!= period
) {
1419 caret
.period
= period
;
1421 if (FineTickerAvailable()) {
1422 FineTickerCancel(tickCaret
);
1423 if ((caret
.active
) && (caret
.period
> 0))
1424 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
1430 void Editor::InvalidateCaret() {
1431 if (posDrag
.IsValid()) {
1432 InvalidateRange(posDrag
.Position(), posDrag
.Position() + 1);
1434 for (size_t r
=0; r
<sel
.Count(); r
++) {
1435 InvalidateRange(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1);
1438 UpdateSystemCaret();
1441 void Editor::UpdateSystemCaret() {
1444 bool Editor::Wrapping() const {
1445 return vs
.wrapState
!= eWrapNone
;
1448 void Editor::NeedWrapping(int docLineStart
, int docLineEnd
) {
1449 //Platform::DebugPrintf("\nNeedWrapping: %0d..%0d\n", docLineStart, docLineEnd);
1450 if (wrapPending
.AddRange(docLineStart
, docLineEnd
)) {
1451 view
.llc
.Invalidate(LineLayout::llPositions
);
1453 // Wrap lines during idle.
1454 if (Wrapping() && wrapPending
.NeedsWrap()) {
1459 bool Editor::WrapOneLine(Surface
*surface
, int lineToWrap
) {
1460 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(lineToWrap
, *this));
1461 int linesWrapped
= 1;
1463 view
.LayoutLine(*this, lineToWrap
, surface
, vs
, ll
, wrapWidth
);
1464 linesWrapped
= ll
->lines
;
1466 return cs
.SetHeight(lineToWrap
, linesWrapped
+
1467 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineToWrap
) : 0));
1470 // Perform wrapping for a subset of the lines needing wrapping.
1471 // wsAll: wrap all lines which need wrapping in this single call
1472 // wsVisible: wrap currently visible lines
1473 // wsIdle: wrap one page + 100 lines
1474 // Return true if wrapping occurred.
1475 bool Editor::WrapLines(enum wrapScope ws
) {
1476 int goodTopLine
= topLine
;
1477 bool wrapOccurred
= false;
1479 if (wrapWidth
!= LineLayout::wrapWidthInfinite
) {
1480 wrapWidth
= LineLayout::wrapWidthInfinite
;
1481 for (int lineDoc
= 0; lineDoc
< pdoc
->LinesTotal(); lineDoc
++) {
1482 cs
.SetHeight(lineDoc
, 1 +
1483 (vs
.annotationVisible
? pdoc
->AnnotationLines(lineDoc
) : 0));
1485 wrapOccurred
= true;
1487 wrapPending
.Reset();
1489 } else if (wrapPending
.NeedsWrap()) {
1490 wrapPending
.start
= std::min(wrapPending
.start
, pdoc
->LinesTotal());
1491 if (!SetIdle(true)) {
1492 // Idle processing not supported so full wrap required.
1495 // Decide where to start wrapping
1496 int lineToWrap
= wrapPending
.start
;
1497 int lineToWrapEnd
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1498 const int lineDocTop
= cs
.DocFromDisplay(topLine
);
1499 const int subLineTop
= topLine
- cs
.DisplayFromDoc(lineDocTop
);
1500 if (ws
== wsVisible
) {
1501 lineToWrap
= Platform::Clamp(lineDocTop
-5, wrapPending
.start
, pdoc
->LinesTotal());
1502 // Priority wrap to just after visible area.
1503 // Since wrapping could reduce display lines, treat each
1504 // as taking only one display line.
1505 lineToWrapEnd
= lineDocTop
;
1506 int lines
= LinesOnScreen() + 1;
1507 while ((lineToWrapEnd
< cs
.LinesInDoc()) && (lines
>0)) {
1508 if (cs
.GetVisible(lineToWrapEnd
))
1512 // .. and if the paint window is outside pending wraps
1513 if ((lineToWrap
> wrapPending
.end
) || (lineToWrapEnd
< wrapPending
.start
)) {
1514 // Currently visible text does not need wrapping
1517 } else if (ws
== wsIdle
) {
1518 lineToWrapEnd
= lineToWrap
+ LinesOnScreen() + 100;
1520 const int lineEndNeedWrap
= std::min(wrapPending
.end
, pdoc
->LinesTotal());
1521 lineToWrapEnd
= std::min(lineToWrapEnd
, lineEndNeedWrap
);
1523 // Ensure all lines being wrapped are styled.
1524 pdoc
->EnsureStyledTo(pdoc
->LineStart(lineToWrapEnd
));
1526 if (lineToWrap
< lineToWrapEnd
) {
1528 PRectangle rcTextArea
= GetClientRectangle();
1529 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1530 rcTextArea
.right
-= vs
.rightMarginWidth
;
1531 wrapWidth
= static_cast<int>(rcTextArea
.Width());
1533 AutoSurface
surface(this);
1535 //Platform::DebugPrintf("Wraplines: scope=%0d need=%0d..%0d perform=%0d..%0d\n", ws, wrapPending.start, wrapPending.end, lineToWrap, lineToWrapEnd);
1537 while (lineToWrap
< lineToWrapEnd
) {
1538 if (WrapOneLine(surface
, lineToWrap
)) {
1539 wrapOccurred
= true;
1541 wrapPending
.Wrapped(lineToWrap
);
1545 goodTopLine
= cs
.DisplayFromDoc(lineDocTop
) + std::min(subLineTop
, cs
.GetHeight(lineDocTop
)-1);
1549 // If wrapping is done, bring it to resting position
1550 if (wrapPending
.start
>= lineEndNeedWrap
) {
1551 wrapPending
.Reset();
1557 SetTopLine(Platform::Clamp(goodTopLine
, 0, MaxScrollPos()));
1558 SetVerticalScrollPos();
1561 return wrapOccurred
;
1564 void Editor::LinesJoin() {
1565 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1567 bool prevNonWS
= true;
1568 for (int pos
= targetStart
; pos
< targetEnd
; pos
++) {
1569 if (pdoc
->IsPositionInLineEnd(pos
)) {
1570 targetEnd
-= pdoc
->LenChar(pos
);
1573 // Ensure at least one space separating previous lines
1574 const int lengthInserted
= pdoc
->InsertString(pos
, " ", 1);
1575 targetEnd
+= lengthInserted
;
1578 prevNonWS
= pdoc
->CharAt(pos
) != ' ';
1584 const char *Editor::StringFromEOLMode(int eolMode
) {
1585 if (eolMode
== SC_EOL_CRLF
) {
1587 } else if (eolMode
== SC_EOL_CR
) {
1594 void Editor::LinesSplit(int pixelWidth
) {
1595 if (!RangeContainsProtected(targetStart
, targetEnd
)) {
1596 if (pixelWidth
== 0) {
1597 PRectangle rcText
= GetTextRectangle();
1598 pixelWidth
= static_cast<int>(rcText
.Width());
1600 int lineStart
= pdoc
->LineFromPosition(targetStart
);
1601 int lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1602 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
1604 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
1605 AutoSurface
surface(this);
1606 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
1607 if (surface
&& ll
) {
1608 unsigned int posLineStart
= pdoc
->LineStart(line
);
1609 view
.LayoutLine(*this, line
, surface
, vs
, ll
, pixelWidth
);
1610 int lengthInsertedTotal
= 0;
1611 for (int subLine
= 1; subLine
< ll
->lines
; subLine
++) {
1612 const int lengthInserted
= pdoc
->InsertString(
1613 static_cast<int>(posLineStart
+ lengthInsertedTotal
+
1614 ll
->LineStart(subLine
)),
1616 targetEnd
+= lengthInserted
;
1617 lengthInsertedTotal
+= lengthInserted
;
1620 lineEnd
= pdoc
->LineFromPosition(targetEnd
);
1625 void Editor::PaintSelMargin(Surface
*surfWindow
, PRectangle
&rc
) {
1626 if (vs
.fixedColumnWidth
== 0)
1631 RefreshPixMaps(surfWindow
);
1633 // On GTK+ with Ubuntu overlay scroll bars, the surface may have been finished
1634 // at this point. The Initialised call checks for this case and sets the status
1635 // to be bad which avoids crashes in following calls.
1636 if (!surfWindow
->Initialised()) {
1640 PRectangle rcMargin
= GetClientRectangle();
1641 Point ptOrigin
= GetVisibleOriginInMain();
1642 rcMargin
.Move(0, -ptOrigin
.y
);
1644 rcMargin
.right
= static_cast<XYPOSITION
>(vs
.fixedColumnWidth
);
1646 if (!rc
.Intersects(rcMargin
))
1650 if (view
.bufferedDraw
) {
1651 surface
= marginView
.pixmapSelMargin
;
1653 surface
= surfWindow
;
1656 // Clip vertically to paint area to avoid drawing line numbers
1657 if (rcMargin
.bottom
> rc
.bottom
)
1658 rcMargin
.bottom
= rc
.bottom
;
1659 if (rcMargin
.top
< rc
.top
)
1660 rcMargin
.top
= rc
.top
;
1662 marginView
.PaintMargin(surface
, topLine
, rc
, rcMargin
, *this, vs
);
1664 if (view
.bufferedDraw
) {
1665 surfWindow
->Copy(rcMargin
, Point(rcMargin
.left
, rcMargin
.top
), *marginView
.pixmapSelMargin
);
1669 void Editor::RefreshPixMaps(Surface
*surfaceWindow
) {
1670 view
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1671 marginView
.RefreshPixMaps(surfaceWindow
, wMain
.GetID(), vs
);
1672 if (view
.bufferedDraw
) {
1673 PRectangle rcClient
= GetClientRectangle();
1674 if (!view
.pixmapLine
->Initialised()) {
1676 view
.pixmapLine
->InitPixMap(static_cast<int>(rcClient
.Width()), vs
.lineHeight
,
1677 surfaceWindow
, wMain
.GetID());
1679 if (!marginView
.pixmapSelMargin
->Initialised()) {
1680 marginView
.pixmapSelMargin
->InitPixMap(vs
.fixedColumnWidth
,
1681 static_cast<int>(rcClient
.Height()), surfaceWindow
, wMain
.GetID());
1686 void Editor::Paint(Surface
*surfaceWindow
, PRectangle rcArea
) {
1687 //Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",
1688 // paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom);
1692 if (paintState
== paintAbandoned
)
1693 return; // Scroll bars may have changed so need redraw
1694 RefreshPixMaps(surfaceWindow
);
1696 paintAbandonedByStyling
= false;
1698 StyleAreaBounded(rcArea
, false);
1700 PRectangle rcClient
= GetClientRectangle();
1701 //Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
1702 // rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
1704 if (NotifyUpdateUI()) {
1706 RefreshPixMaps(surfaceWindow
);
1709 // Wrap the visible lines if needed.
1710 if (WrapLines(wsVisible
)) {
1711 // The wrapping process has changed the height of some lines so
1712 // abandon this paint for a complete repaint.
1713 if (AbandonPaint()) {
1716 RefreshPixMaps(surfaceWindow
); // In case pixmaps invalidated by scrollbar change
1718 PLATFORM_ASSERT(marginView
.pixmapSelPattern
->Initialised());
1720 if (!view
.bufferedDraw
)
1721 surfaceWindow
->SetClip(rcArea
);
1723 if (paintState
!= paintAbandoned
) {
1724 if (vs
.marginInside
) {
1725 PaintSelMargin(surfaceWindow
, rcArea
);
1726 PRectangle rcRightMargin
= rcClient
;
1727 rcRightMargin
.left
= rcRightMargin
.right
- vs
.rightMarginWidth
;
1728 if (rcArea
.Intersects(rcRightMargin
)) {
1729 surfaceWindow
->FillRectangle(rcRightMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1731 } else { // Else separate view so separate paint event but leftMargin included to allow overlap
1732 PRectangle rcLeftMargin
= rcArea
;
1733 rcLeftMargin
.left
= 0;
1734 rcLeftMargin
.right
= rcLeftMargin
.left
+ vs
.leftMarginWidth
;
1735 if (rcArea
.Intersects(rcLeftMargin
)) {
1736 surfaceWindow
->FillRectangle(rcLeftMargin
, vs
.styles
[STYLE_DEFAULT
].back
);
1741 if (paintState
== paintAbandoned
) {
1742 // Either styling or NotifyUpdateUI noticed that painting is needed
1743 // outside the current painting rectangle
1744 //Platform::DebugPrintf("Abandoning paint\n");
1746 if (paintAbandonedByStyling
) {
1747 // Styling has spilled over a line end, such as occurs by starting a multiline
1748 // comment. The width of subsequent text may have changed, so rewrap.
1749 NeedWrapping(cs
.DocFromDisplay(topLine
));
1755 view
.PaintText(surfaceWindow
, *this, rcArea
, rcClient
, vs
);
1757 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
1758 if (FineTickerAvailable()) {
1759 scrollWidth
= view
.lineWidthMaxSeen
;
1760 if (!FineTickerRunning(tickWiden
)) {
1761 FineTickerStart(tickWiden
, 50, 5);
1769 // This is mostly copied from the Paint method but with some things omitted
1770 // such as the margin markers, line numbers, selection and caret
1771 // Should be merged back into a combined Draw method.
1772 long Editor::FormatRange(bool draw
, Sci_RangeToFormat
*pfr
) {
1776 AutoSurface
surface(pfr
->hdc
, this, SC_TECHNOLOGY_DEFAULT
);
1779 AutoSurface
surfaceMeasure(pfr
->hdcTarget
, this, SC_TECHNOLOGY_DEFAULT
);
1780 if (!surfaceMeasure
) {
1783 return view
.FormatRange(draw
, pfr
, surface
, surfaceMeasure
, *this, vs
);
1786 int Editor::TextWidth(int style
, const char *text
) {
1788 AutoSurface
surface(this);
1790 return static_cast<int>(surface
->WidthText(vs
.styles
[style
].font
, text
, istrlen(text
)));
1796 // Empty method is overridden on GTK+ to show / hide scrollbars
1797 void Editor::ReconfigureScrollBars() {}
1799 void Editor::SetScrollBars() {
1802 int nMax
= MaxScrollPos();
1803 int nPage
= LinesOnScreen();
1804 bool modified
= ModifyScrollBars(nMax
+ nPage
- 1, nPage
);
1809 // TODO: ensure always showing as many lines as possible
1810 // May not be, if, for example, window made larger
1811 if (topLine
> MaxScrollPos()) {
1812 SetTopLine(Platform::Clamp(topLine
, 0, MaxScrollPos()));
1813 SetVerticalScrollPos();
1817 if (!AbandonPaint())
1820 //Platform::DebugPrintf("end max = %d page = %d\n", nMax, nPage);
1823 void Editor::ChangeSize() {
1824 DropGraphics(false);
1827 PRectangle rcTextArea
= GetClientRectangle();
1828 rcTextArea
.left
= static_cast<XYPOSITION
>(vs
.textStart
);
1829 rcTextArea
.right
-= vs
.rightMarginWidth
;
1830 if (wrapWidth
!= rcTextArea
.Width()) {
1837 int Editor::InsertSpace(int position
, unsigned int spaces
) {
1839 std::string
spaceText(spaces
, ' ');
1840 const int lengthInserted
= pdoc
->InsertString(position
, spaceText
.c_str(), spaces
);
1841 position
+= lengthInserted
;
1846 void Editor::AddChar(char ch
) {
1853 void Editor::FilterSelections() {
1854 if (!additionalSelectionTyping
&& (sel
.Count() > 1)) {
1855 InvalidateWholeSelection();
1856 sel
.DropAdditionalRanges();
1860 static bool cmpSelPtrs(const SelectionRange
*a
, const SelectionRange
*b
) {
1864 // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.
1865 void Editor::AddCharUTF(const char *s
, unsigned int len
, bool treatAsDBCS
) {
1868 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1870 // Vector elements point into selection in order to change selection.
1871 std::vector
<SelectionRange
*> selPtrs
;
1872 for (size_t r
= 0; r
< sel
.Count(); r
++) {
1873 selPtrs
.push_back(&sel
.Range(r
));
1875 // Order selections by position in document.
1876 std::sort(selPtrs
.begin(), selPtrs
.end(), cmpSelPtrs
);
1878 // Loop in reverse to avoid disturbing positions of selections yet to be processed.
1879 for (std::vector
<SelectionRange
*>::reverse_iterator rit
= selPtrs
.rbegin();
1880 rit
!= selPtrs
.rend(); ++rit
) {
1881 SelectionRange
*currentSel
= *rit
;
1882 if (!RangeContainsProtected(currentSel
->Start().Position(),
1883 currentSel
->End().Position())) {
1884 int positionInsert
= currentSel
->Start().Position();
1885 if (!currentSel
->Empty()) {
1886 if (currentSel
->Length()) {
1887 pdoc
->DeleteChars(positionInsert
, currentSel
->Length());
1888 currentSel
->ClearVirtualSpace();
1890 // Range is all virtual so collapse to start of virtual space
1891 currentSel
->MinimizeVirtualSpace();
1893 } else if (inOverstrike
) {
1894 if (positionInsert
< pdoc
->Length()) {
1895 if (!pdoc
->IsPositionInLineEnd(positionInsert
)) {
1896 pdoc
->DelChar(positionInsert
);
1897 currentSel
->ClearVirtualSpace();
1901 positionInsert
= InsertSpace(positionInsert
, currentSel
->caret
.VirtualSpace());
1902 const int lengthInserted
= pdoc
->InsertString(positionInsert
, s
, len
);
1903 if (lengthInserted
> 0) {
1904 currentSel
->caret
.SetPosition(positionInsert
+ lengthInserted
);
1905 currentSel
->anchor
.SetPosition(positionInsert
+ lengthInserted
);
1907 currentSel
->ClearVirtualSpace();
1908 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1910 AutoSurface
surface(this);
1912 if (WrapOneLine(surface
, pdoc
->LineFromPosition(positionInsert
))) {
1914 SetVerticalScrollPos();
1925 ThinRectangularRange();
1926 // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information
1927 EnsureCaretVisible();
1928 // Avoid blinking during rapid typing:
1929 ShowCaretAtCurrentPosition();
1930 if ((caretSticky
== SC_CARETSTICKY_OFF
) ||
1931 ((caretSticky
== SC_CARETSTICKY_WHITESPACE
) && !IsAllSpacesOrTabs(s
, len
))) {
1936 NotifyChar((static_cast<unsigned char>(s
[0]) << 8) |
1937 static_cast<unsigned char>(s
[1]));
1938 } else if (len
> 0) {
1939 int byte
= static_cast<unsigned char>(s
[0]);
1940 if ((byte
< 0xC0) || (1 == len
)) {
1941 // Handles UTF-8 characters between 0x01 and 0x7F and single byte
1942 // characters when not in UTF-8 mode.
1943 // Also treats \0 and naked trail bytes 0x80 to 0xBF as valid
1944 // characters representing themselves.
1946 unsigned int utf32
[1] = { 0 };
1947 UTF32FromUTF8(s
, len
, utf32
, ELEMENTS(utf32
));
1953 if (recordingMacro
) {
1954 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(s
));
1958 void Editor::ClearBeforeTentativeStart() {
1959 // Make positions for the first composition string.
1961 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty() || inOverstrike
);
1962 for (size_t r
= 0; r
<sel
.Count(); r
++) {
1963 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1964 sel
.Range(r
).End().Position())) {
1965 int positionInsert
= sel
.Range(r
).Start().Position();
1966 if (!sel
.Range(r
).Empty()) {
1967 if (sel
.Range(r
).Length()) {
1968 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1969 sel
.Range(r
).ClearVirtualSpace();
1971 // Range is all virtual so collapse to start of virtual space
1972 sel
.Range(r
).MinimizeVirtualSpace();
1975 InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
1976 sel
.Range(r
).ClearVirtualSpace();
1981 void Editor::InsertPaste(const char *text
, int len
) {
1982 if (multiPasteMode
== SC_MULTIPASTE_ONCE
) {
1983 SelectionPosition selStart
= sel
.Start();
1984 selStart
= SelectionPosition(InsertSpace(selStart
.Position(), selStart
.VirtualSpace()));
1985 const int lengthInserted
= pdoc
->InsertString(selStart
.Position(), text
, len
);
1986 if (lengthInserted
> 0) {
1987 SetEmptySelection(selStart
.Position() + lengthInserted
);
1990 // SC_MULTIPASTE_EACH
1991 for (size_t r
=0; r
<sel
.Count(); r
++) {
1992 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
1993 sel
.Range(r
).End().Position())) {
1994 int positionInsert
= sel
.Range(r
).Start().Position();
1995 if (!sel
.Range(r
).Empty()) {
1996 if (sel
.Range(r
).Length()) {
1997 pdoc
->DeleteChars(positionInsert
, sel
.Range(r
).Length());
1998 sel
.Range(r
).ClearVirtualSpace();
2000 // Range is all virtual so collapse to start of virtual space
2001 sel
.Range(r
).MinimizeVirtualSpace();
2004 positionInsert
= InsertSpace(positionInsert
, sel
.Range(r
).caret
.VirtualSpace());
2005 const int lengthInserted
= pdoc
->InsertString(positionInsert
, text
, len
);
2006 if (lengthInserted
> 0) {
2007 sel
.Range(r
).caret
.SetPosition(positionInsert
+ lengthInserted
);
2008 sel
.Range(r
).anchor
.SetPosition(positionInsert
+ lengthInserted
);
2010 sel
.Range(r
).ClearVirtualSpace();
2016 void Editor::InsertPasteShape(const char *text
, int len
, PasteShape shape
) {
2017 std::string convertedText
;
2018 if (convertPastes
) {
2019 // Convert line endings of the paste into our local line-endings mode
2020 convertedText
= Document::TransformLineEnds(text
, len
, pdoc
->eolMode
);
2021 len
= static_cast<int>(convertedText
.length());
2022 text
= convertedText
.c_str();
2024 if (shape
== pasteRectangular
) {
2025 PasteRectangular(sel
.Start(), text
, len
);
2027 if (shape
== pasteLine
) {
2028 int insertPos
= pdoc
->LineStart(pdoc
->LineFromPosition(sel
.MainCaret()));
2029 int lengthInserted
= pdoc
->InsertString(insertPos
, text
, len
);
2030 // add the newline if necessary
2031 if ((len
> 0) && (text
[len
- 1] != '\n' && text
[len
- 1] != '\r')) {
2032 const char *endline
= StringFromEOLMode(pdoc
->eolMode
);
2033 int length
= static_cast<int>(strlen(endline
));
2034 lengthInserted
+= pdoc
->InsertString(insertPos
+ lengthInserted
, endline
, length
);
2036 if (sel
.MainCaret() == insertPos
) {
2037 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
2040 InsertPaste(text
, len
);
2045 void Editor::ClearSelection(bool retainMultipleSelections
) {
2046 if (!sel
.IsRectangular() && !retainMultipleSelections
)
2049 for (size_t r
=0; r
<sel
.Count(); r
++) {
2050 if (!sel
.Range(r
).Empty()) {
2051 if (!RangeContainsProtected(sel
.Range(r
).Start().Position(),
2052 sel
.Range(r
).End().Position())) {
2053 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(),
2054 sel
.Range(r
).Length());
2055 sel
.Range(r
) = SelectionRange(sel
.Range(r
).Start());
2059 ThinRectangularRange();
2060 sel
.RemoveDuplicates();
2062 SetHoverIndicatorPosition(sel
.MainCaret());
2065 void Editor::ClearAll() {
2068 if (0 != pdoc
->Length()) {
2069 pdoc
->DeleteChars(0, pdoc
->Length());
2071 if (!pdoc
->IsReadOnly()) {
2073 pdoc
->AnnotationClearAll();
2074 pdoc
->MarginClearAll();
2078 view
.ClearAllTabstops();
2082 SetVerticalScrollPos();
2083 InvalidateStyleRedraw();
2086 void Editor::ClearDocumentStyle() {
2087 Decoration
*deco
= pdoc
->decorations
.root
;
2089 // Save next in case deco deleted
2090 Decoration
*decoNext
= deco
->next
;
2091 if (deco
->indicator
< INDIC_CONTAINER
) {
2092 pdoc
->decorations
.SetCurrentIndicator(deco
->indicator
);
2093 pdoc
->DecorationFillRange(0, 0, pdoc
->Length());
2097 pdoc
->StartStyling(0, '\377');
2098 pdoc
->SetStyleFor(pdoc
->Length(), 0);
2100 SetAnnotationHeights(0, pdoc
->LinesTotal());
2101 pdoc
->ClearLevels();
2104 void Editor::CopyAllowLine() {
2105 SelectionText selectedText
;
2106 CopySelectionRange(&selectedText
, true);
2107 CopyToClipboard(selectedText
);
2110 void Editor::Cut() {
2111 pdoc
->CheckReadOnly();
2112 if (!pdoc
->IsReadOnly() && !SelectionContainsProtected()) {
2118 void Editor::PasteRectangular(SelectionPosition pos
, const char *ptr
, int len
) {
2119 if (pdoc
->IsReadOnly() || SelectionContainsProtected()) {
2123 sel
.RangeMain() = SelectionRange(pos
);
2124 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2126 sel
.RangeMain().caret
= SelectionPosition(
2127 InsertSpace(sel
.RangeMain().caret
.Position(), sel
.RangeMain().caret
.VirtualSpace()));
2128 int xInsert
= XFromPosition(sel
.RangeMain().caret
);
2129 bool prevCr
= false;
2130 while ((len
> 0) && IsEOLChar(ptr
[len
-1]))
2132 for (int i
= 0; i
< len
; i
++) {
2133 if (IsEOLChar(ptr
[i
])) {
2134 if ((ptr
[i
] == '\r') || (!prevCr
))
2136 if (line
>= pdoc
->LinesTotal()) {
2137 if (pdoc
->eolMode
!= SC_EOL_LF
)
2138 pdoc
->InsertString(pdoc
->Length(), "\r", 1);
2139 if (pdoc
->eolMode
!= SC_EOL_CR
)
2140 pdoc
->InsertString(pdoc
->Length(), "\n", 1);
2142 // Pad the end of lines with spaces if required
2143 sel
.RangeMain().caret
.SetPosition(PositionFromLineX(line
, xInsert
));
2144 if ((XFromPosition(sel
.MainCaret()) < xInsert
) && (i
+ 1 < len
)) {
2145 while (XFromPosition(sel
.MainCaret()) < xInsert
) {
2147 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), " ", 1);
2148 sel
.RangeMain().caret
.Add(lengthInserted
);
2151 prevCr
= ptr
[i
] == '\r';
2153 const int lengthInserted
= pdoc
->InsertString(sel
.MainCaret(), ptr
+ i
, 1);
2154 sel
.RangeMain().caret
.Add(lengthInserted
);
2158 SetEmptySelection(pos
);
2161 bool Editor::CanPaste() {
2162 return !pdoc
->IsReadOnly() && !SelectionContainsProtected();
2165 void Editor::Clear() {
2166 // If multiple selections, don't delete EOLS
2168 bool singleVirtual
= false;
2169 if ((sel
.Count() == 1) &&
2170 !RangeContainsProtected(sel
.MainCaret(), sel
.MainCaret() + 1) &&
2171 sel
.RangeMain().Start().VirtualSpace()) {
2172 singleVirtual
= true;
2174 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || singleVirtual
);
2175 for (size_t r
=0; r
<sel
.Count(); r
++) {
2176 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.Position() + 1)) {
2177 if (sel
.Range(r
).Start().VirtualSpace()) {
2178 if (sel
.Range(r
).anchor
< sel
.Range(r
).caret
)
2179 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).anchor
.Position(), sel
.Range(r
).anchor
.VirtualSpace()));
2181 sel
.Range(r
) = SelectionRange(InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
2183 if ((sel
.Count() == 1) || !pdoc
->IsPositionInLineEnd(sel
.Range(r
).caret
.Position())) {
2184 pdoc
->DelChar(sel
.Range(r
).caret
.Position());
2185 sel
.Range(r
).ClearVirtualSpace();
2186 } // else multiple selection so don't eat line ends
2188 sel
.Range(r
).ClearVirtualSpace();
2194 sel
.RemoveDuplicates();
2195 ShowCaretAtCurrentPosition(); // Avoid blinking
2198 void Editor::SelectAll() {
2200 SetSelection(0, pdoc
->Length());
2204 void Editor::Undo() {
2205 if (pdoc
->CanUndo()) {
2207 int newPos
= pdoc
->Undo();
2209 SetEmptySelection(newPos
);
2210 EnsureCaretVisible();
2214 void Editor::Redo() {
2215 if (pdoc
->CanRedo()) {
2216 int newPos
= pdoc
->Redo();
2218 SetEmptySelection(newPos
);
2219 EnsureCaretVisible();
2223 void Editor::DelCharBack(bool allowLineStartDeletion
) {
2225 if (!sel
.IsRectangular())
2227 if (sel
.IsRectangular())
2228 allowLineStartDeletion
= false;
2229 UndoGroup
ug(pdoc
, (sel
.Count() > 1) || !sel
.Empty());
2231 for (size_t r
=0; r
<sel
.Count(); r
++) {
2232 if (!RangeContainsProtected(sel
.Range(r
).caret
.Position() - 1, sel
.Range(r
).caret
.Position())) {
2233 if (sel
.Range(r
).caret
.VirtualSpace()) {
2234 sel
.Range(r
).caret
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace() - 1);
2235 sel
.Range(r
).anchor
.SetVirtualSpace(sel
.Range(r
).caret
.VirtualSpace());
2237 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2238 if (allowLineStartDeletion
|| (pdoc
->LineStart(lineCurrentPos
) != sel
.Range(r
).caret
.Position())) {
2239 if (pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
2240 pdoc
->GetColumn(sel
.Range(r
).caret
.Position()) > 0 && pdoc
->backspaceUnindents
) {
2241 UndoGroup
ugInner(pdoc
, !ug
.Needed());
2242 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
2243 int indentationStep
= pdoc
->IndentSize();
2244 int indentationChange
= indentation
% indentationStep
;
2245 if (indentationChange
== 0)
2246 indentationChange
= indentationStep
;
2247 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationChange
);
2248 // SetEmptySelection
2249 sel
.Range(r
) = SelectionRange(posSelect
);
2251 pdoc
->DelCharBack(sel
.Range(r
).caret
.Position());
2256 sel
.Range(r
).ClearVirtualSpace();
2259 ThinRectangularRange();
2263 sel
.RemoveDuplicates();
2264 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
2265 // Avoid blinking during rapid typing:
2266 ShowCaretAtCurrentPosition();
2269 int Editor::ModifierFlags(bool shift
, bool ctrl
, bool alt
, bool meta
, bool super
) {
2271 (shift
? SCI_SHIFT
: 0) |
2272 (ctrl
? SCI_CTRL
: 0) |
2273 (alt
? SCI_ALT
: 0) |
2274 (meta
? SCI_META
: 0) |
2275 (super
? SCI_SUPER
: 0);
2278 void Editor::NotifyFocus(bool focus
) {
2279 SCNotification scn
= {};
2280 scn
.nmhdr
.code
= focus
? SCN_FOCUSIN
: SCN_FOCUSOUT
;
2284 void Editor::SetCtrlID(int identifier
) {
2285 ctrlID
= identifier
;
2288 void Editor::NotifyStyleToNeeded(int endStyleNeeded
) {
2289 SCNotification scn
= {};
2290 scn
.nmhdr
.code
= SCN_STYLENEEDED
;
2291 scn
.position
= endStyleNeeded
;
2295 void Editor::NotifyStyleNeeded(Document
*, void *, int endStyleNeeded
) {
2296 NotifyStyleToNeeded(endStyleNeeded
);
2299 void Editor::NotifyLexerChanged(Document
*, void *) {
2302 void Editor::NotifyErrorOccurred(Document
*, void *, int status
) {
2303 errorStatus
= status
;
2306 void Editor::NotifyChar(int ch
) {
2307 SCNotification scn
= {};
2308 scn
.nmhdr
.code
= SCN_CHARADDED
;
2313 void Editor::NotifySavePoint(bool isSavePoint
) {
2314 SCNotification scn
= {};
2316 scn
.nmhdr
.code
= SCN_SAVEPOINTREACHED
;
2318 scn
.nmhdr
.code
= SCN_SAVEPOINTLEFT
;
2323 void Editor::NotifyModifyAttempt() {
2324 SCNotification scn
= {};
2325 scn
.nmhdr
.code
= SCN_MODIFYATTEMPTRO
;
2329 void Editor::NotifyDoubleClick(Point pt
, int modifiers
) {
2330 SCNotification scn
= {};
2331 scn
.nmhdr
.code
= SCN_DOUBLECLICK
;
2332 scn
.line
= LineFromLocation(pt
);
2333 scn
.position
= PositionFromLocation(pt
, true);
2334 scn
.modifiers
= modifiers
;
2338 void Editor::NotifyDoubleClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2339 NotifyDoubleClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2342 void Editor::NotifyHotSpotDoubleClicked(int position
, int modifiers
) {
2343 SCNotification scn
= {};
2344 scn
.nmhdr
.code
= SCN_HOTSPOTDOUBLECLICK
;
2345 scn
.position
= position
;
2346 scn
.modifiers
= modifiers
;
2350 void Editor::NotifyHotSpotDoubleClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2351 NotifyHotSpotDoubleClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2354 void Editor::NotifyHotSpotClicked(int position
, int modifiers
) {
2355 SCNotification scn
= {};
2356 scn
.nmhdr
.code
= SCN_HOTSPOTCLICK
;
2357 scn
.position
= position
;
2358 scn
.modifiers
= modifiers
;
2362 void Editor::NotifyHotSpotClicked(int position
, bool shift
, bool ctrl
, bool alt
) {
2363 NotifyHotSpotClicked(position
, ModifierFlags(shift
, ctrl
, alt
));
2366 void Editor::NotifyHotSpotReleaseClick(int position
, int modifiers
) {
2367 SCNotification scn
= {};
2368 scn
.nmhdr
.code
= SCN_HOTSPOTRELEASECLICK
;
2369 scn
.position
= position
;
2370 scn
.modifiers
= modifiers
;
2374 void Editor::NotifyHotSpotReleaseClick(int position
, bool shift
, bool ctrl
, bool alt
) {
2375 NotifyHotSpotReleaseClick(position
, ModifierFlags(shift
, ctrl
, alt
));
2378 bool Editor::NotifyUpdateUI() {
2380 SCNotification scn
= {};
2381 scn
.nmhdr
.code
= SCN_UPDATEUI
;
2382 scn
.updated
= needUpdateUI
;
2390 void Editor::NotifyPainted() {
2391 SCNotification scn
= {};
2392 scn
.nmhdr
.code
= SCN_PAINTED
;
2396 void Editor::NotifyIndicatorClick(bool click
, int position
, int modifiers
) {
2397 int mask
= pdoc
->decorations
.AllOnFor(position
);
2398 if ((click
&& mask
) || pdoc
->decorations
.clickNotified
) {
2399 SCNotification scn
= {};
2400 pdoc
->decorations
.clickNotified
= click
;
2401 scn
.nmhdr
.code
= click
? SCN_INDICATORCLICK
: SCN_INDICATORRELEASE
;
2402 scn
.modifiers
= modifiers
;
2403 scn
.position
= position
;
2408 void Editor::NotifyIndicatorClick(bool click
, int position
, bool shift
, bool ctrl
, bool alt
) {
2409 NotifyIndicatorClick(click
, position
, ModifierFlags(shift
, ctrl
, alt
));
2412 bool Editor::NotifyMarginClick(Point pt
, int modifiers
) {
2413 int marginClicked
= -1;
2414 int x
= vs
.textStart
- vs
.fixedColumnWidth
;
2415 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
2416 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
2417 marginClicked
= margin
;
2418 x
+= vs
.ms
[margin
].width
;
2420 if ((marginClicked
>= 0) && vs
.ms
[marginClicked
].sensitive
) {
2421 int position
= pdoc
->LineStart(LineFromLocation(pt
));
2422 if ((vs
.ms
[marginClicked
].mask
& SC_MASK_FOLDERS
) && (foldAutomatic
& SC_AUTOMATICFOLD_CLICK
)) {
2423 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
2424 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
2425 int lineClick
= pdoc
->LineFromPosition(position
);
2426 if (shift
&& ctrl
) {
2427 FoldAll(SC_FOLDACTION_TOGGLE
);
2429 int levelClick
= pdoc
->GetLevel(lineClick
);
2430 if (levelClick
& SC_FOLDLEVELHEADERFLAG
) {
2432 // Ensure all children visible
2433 FoldExpand(lineClick
, SC_FOLDACTION_EXPAND
, levelClick
);
2435 FoldExpand(lineClick
, SC_FOLDACTION_TOGGLE
, levelClick
);
2438 FoldLine(lineClick
, SC_FOLDACTION_TOGGLE
);
2444 SCNotification scn
= {};
2445 scn
.nmhdr
.code
= SCN_MARGINCLICK
;
2446 scn
.modifiers
= modifiers
;
2447 scn
.position
= position
;
2448 scn
.margin
= marginClicked
;
2456 bool Editor::NotifyMarginClick(Point pt
, bool shift
, bool ctrl
, bool alt
) {
2457 return NotifyMarginClick(pt
, ModifierFlags(shift
, ctrl
, alt
));
2460 void Editor::NotifyNeedShown(int pos
, int len
) {
2461 SCNotification scn
= {};
2462 scn
.nmhdr
.code
= SCN_NEEDSHOWN
;
2468 void Editor::NotifyDwelling(Point pt
, bool state
) {
2469 SCNotification scn
= {};
2470 scn
.nmhdr
.code
= state
? SCN_DWELLSTART
: SCN_DWELLEND
;
2471 scn
.position
= PositionFromLocation(pt
, true);
2472 scn
.x
= static_cast<int>(pt
.x
+ vs
.ExternalMarginWidth());
2473 scn
.y
= static_cast<int>(pt
.y
);
2477 void Editor::NotifyZoom() {
2478 SCNotification scn
= {};
2479 scn
.nmhdr
.code
= SCN_ZOOM
;
2483 // Notifications from document
2484 void Editor::NotifyModifyAttempt(Document
*, void *) {
2485 //Platform::DebugPrintf("** Modify Attempt\n");
2486 NotifyModifyAttempt();
2489 void Editor::NotifySavePoint(Document
*, void *, bool atSavePoint
) {
2490 //Platform::DebugPrintf("** Save Point %s\n", atSavePoint ? "On" : "Off");
2491 NotifySavePoint(atSavePoint
);
2494 void Editor::CheckModificationForWrap(DocModification mh
) {
2495 if (mh
.modificationType
& (SC_MOD_INSERTTEXT
| SC_MOD_DELETETEXT
)) {
2496 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2497 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2498 int lines
= Platform::Maximum(0, mh
.linesAdded
);
2500 NeedWrapping(lineDoc
, lineDoc
+ lines
+ 1);
2503 // Fix up annotation heights
2504 SetAnnotationHeights(lineDoc
, lineDoc
+ lines
+ 2);
2508 // Move a position so it is still after the same character as before the insertion.
2509 static inline int MovePositionForInsertion(int position
, int startInsertion
, int length
) {
2510 if (position
> startInsertion
) {
2511 return position
+ length
;
2516 // Move a position so it is still after the same character as before the deletion if that
2517 // character is still present else after the previous surviving character.
2518 static inline int MovePositionForDeletion(int position
, int startDeletion
, int length
) {
2519 if (position
> startDeletion
) {
2520 int endDeletion
= startDeletion
+ length
;
2521 if (position
> endDeletion
) {
2522 return position
- length
;
2524 return startDeletion
;
2531 void Editor::NotifyModified(Document
*, DocModification mh
, void *) {
2532 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
2533 if (paintState
== painting
) {
2534 CheckForChangeOutsidePaint(Range(mh
.position
, mh
.position
+ mh
.length
));
2536 if (mh
.modificationType
& SC_MOD_CHANGELINESTATE
) {
2537 if (paintState
== painting
) {
2538 CheckForChangeOutsidePaint(
2539 Range(pdoc
->LineStart(mh
.line
), pdoc
->LineStart(mh
.line
+ 1)));
2541 // Could check that change is before last visible line.
2545 if (mh
.modificationType
& SC_MOD_CHANGETABSTOPS
) {
2548 if (mh
.modificationType
& SC_MOD_LEXERSTATE
) {
2549 if (paintState
== painting
) {
2550 CheckForChangeOutsidePaint(
2551 Range(mh
.position
, mh
.position
+ mh
.length
));
2556 if (mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) {
2557 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2558 pdoc
->IncrementStyleClock();
2560 if (paintState
== notPainting
) {
2561 if (mh
.position
< pdoc
->LineStart(topLine
)) {
2562 // Styling performed before this view
2565 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2568 if (mh
.modificationType
& SC_MOD_CHANGESTYLE
) {
2569 view
.llc
.Invalidate(LineLayout::llCheckTextAndStyle
);
2572 // Move selection and brace highlights
2573 if (mh
.modificationType
& SC_MOD_INSERTTEXT
) {
2574 sel
.MovePositions(true, mh
.position
, mh
.length
);
2575 braces
[0] = MovePositionForInsertion(braces
[0], mh
.position
, mh
.length
);
2576 braces
[1] = MovePositionForInsertion(braces
[1], mh
.position
, mh
.length
);
2577 } else if (mh
.modificationType
& SC_MOD_DELETETEXT
) {
2578 sel
.MovePositions(false, mh
.position
, mh
.length
);
2579 braces
[0] = MovePositionForDeletion(braces
[0], mh
.position
, mh
.length
);
2580 braces
[1] = MovePositionForDeletion(braces
[1], mh
.position
, mh
.length
);
2582 if ((mh
.modificationType
& (SC_MOD_BEFOREINSERT
| SC_MOD_BEFOREDELETE
)) && cs
.HiddenLines()) {
2583 // Some lines are hidden so may need shown.
2584 const int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2585 int endNeedShown
= mh
.position
;
2586 if (mh
.modificationType
& SC_MOD_BEFOREINSERT
) {
2587 if (pdoc
->ContainsLineEnd(mh
.text
, mh
.length
) && (mh
.position
!= pdoc
->LineStart(lineOfPos
)))
2588 endNeedShown
= pdoc
->LineStart(lineOfPos
+1);
2589 } else if (mh
.modificationType
& SC_MOD_BEFOREDELETE
) {
2590 // Extend the need shown area over any folded lines
2591 endNeedShown
= mh
.position
+ mh
.length
;
2592 int lineLast
= pdoc
->LineFromPosition(mh
.position
+mh
.length
);
2593 for (int line
= lineOfPos
; line
<= lineLast
; line
++) {
2594 const int lineMaxSubord
= pdoc
->GetLastChild(line
, -1, -1);
2595 if (lineLast
< lineMaxSubord
) {
2596 lineLast
= lineMaxSubord
;
2597 endNeedShown
= pdoc
->LineEnd(lineLast
);
2601 NeedShown(mh
.position
, endNeedShown
- mh
.position
);
2603 if (mh
.linesAdded
!= 0) {
2604 // Update contraction state for inserted and removed lines
2605 // lineOfPos should be calculated in context of state before modification, shouldn't it
2606 int lineOfPos
= pdoc
->LineFromPosition(mh
.position
);
2607 if (mh
.position
> pdoc
->LineStart(lineOfPos
))
2608 lineOfPos
++; // Affecting subsequent lines
2609 if (mh
.linesAdded
> 0) {
2610 cs
.InsertLines(lineOfPos
, mh
.linesAdded
);
2612 cs
.DeleteLines(lineOfPos
, -mh
.linesAdded
);
2614 view
.LinesAddedOrRemoved(lineOfPos
, mh
.linesAdded
);
2616 if (mh
.modificationType
& SC_MOD_CHANGEANNOTATION
) {
2617 int lineDoc
= pdoc
->LineFromPosition(mh
.position
);
2618 if (vs
.annotationVisible
) {
2619 cs
.SetHeight(lineDoc
, cs
.GetHeight(lineDoc
) + mh
.annotationLinesAdded
);
2623 CheckModificationForWrap(mh
);
2624 if (mh
.linesAdded
!= 0) {
2625 // Avoid scrolling of display if change before current display
2626 if (mh
.position
< posTopLine
&& !CanDeferToLastStep(mh
)) {
2627 int newTop
= Platform::Clamp(topLine
+ mh
.linesAdded
, 0, MaxScrollPos());
2628 if (newTop
!= topLine
) {
2630 SetVerticalScrollPos();
2634 if (paintState
== notPainting
&& !CanDeferToLastStep(mh
)) {
2635 QueueIdleWork(WorkNeeded::workStyle
, pdoc
->Length());
2639 if (paintState
== notPainting
&& mh
.length
&& !CanEliminate(mh
)) {
2640 QueueIdleWork(WorkNeeded::workStyle
, mh
.position
+ mh
.length
);
2641 InvalidateRange(mh
.position
, mh
.position
+ mh
.length
);
2646 if (mh
.linesAdded
!= 0 && !CanDeferToLastStep(mh
)) {
2650 if ((mh
.modificationType
& SC_MOD_CHANGEMARKER
) || (mh
.modificationType
& SC_MOD_CHANGEMARGIN
)) {
2651 if ((!willRedrawAll
) && ((paintState
== notPainting
) || !PaintContainsMargin())) {
2652 if (mh
.modificationType
& SC_MOD_CHANGEFOLD
) {
2653 // Fold changes can affect the drawing of following lines so redraw whole margin
2654 RedrawSelMargin(marginView
.highlightDelimiter
.isEnabled
? -1 : mh
.line
- 1, true);
2656 RedrawSelMargin(mh
.line
);
2660 if ((mh
.modificationType
& SC_MOD_CHANGEFOLD
) && (foldAutomatic
& SC_AUTOMATICFOLD_CHANGE
)) {
2661 FoldChanged(mh
.line
, mh
.foldLevelNow
, mh
.foldLevelPrev
);
2664 // NOW pay the piper WRT "deferred" visual updates
2665 if (IsLastStep(mh
)) {
2670 // If client wants to see this modification
2671 if (mh
.modificationType
& modEventMask
) {
2672 if ((mh
.modificationType
& (SC_MOD_CHANGESTYLE
| SC_MOD_CHANGEINDICATOR
)) == 0) {
2673 // Real modification made to text of document.
2674 NotifyChange(); // Send EN_CHANGE
2677 SCNotification scn
= {};
2678 scn
.nmhdr
.code
= SCN_MODIFIED
;
2679 scn
.position
= mh
.position
;
2680 scn
.modificationType
= mh
.modificationType
;
2682 scn
.length
= mh
.length
;
2683 scn
.linesAdded
= mh
.linesAdded
;
2685 scn
.foldLevelNow
= mh
.foldLevelNow
;
2686 scn
.foldLevelPrev
= mh
.foldLevelPrev
;
2687 scn
.token
= mh
.token
;
2688 scn
.annotationLinesAdded
= mh
.annotationLinesAdded
;
2693 void Editor::NotifyDeleted(Document
*, void *) {
2697 void Editor::NotifyMacroRecord(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
2699 // Enumerates all macroable messages
2705 case SCI_REPLACESEL
:
2707 case SCI_INSERTTEXT
:
2708 case SCI_APPENDTEXT
:
2713 case SCI_SEARCHANCHOR
:
2714 case SCI_SEARCHNEXT
:
2715 case SCI_SEARCHPREV
:
2717 case SCI_LINEDOWNEXTEND
:
2719 case SCI_PARADOWNEXTEND
:
2721 case SCI_LINEUPEXTEND
:
2723 case SCI_PARAUPEXTEND
:
2725 case SCI_CHARLEFTEXTEND
:
2727 case SCI_CHARRIGHTEXTEND
:
2729 case SCI_WORDLEFTEXTEND
:
2731 case SCI_WORDRIGHTEXTEND
:
2732 case SCI_WORDPARTLEFT
:
2733 case SCI_WORDPARTLEFTEXTEND
:
2734 case SCI_WORDPARTRIGHT
:
2735 case SCI_WORDPARTRIGHTEXTEND
:
2736 case SCI_WORDLEFTEND
:
2737 case SCI_WORDLEFTENDEXTEND
:
2738 case SCI_WORDRIGHTEND
:
2739 case SCI_WORDRIGHTENDEXTEND
:
2741 case SCI_HOMEEXTEND
:
2743 case SCI_LINEENDEXTEND
:
2745 case SCI_HOMEWRAPEXTEND
:
2746 case SCI_LINEENDWRAP
:
2747 case SCI_LINEENDWRAPEXTEND
:
2748 case SCI_DOCUMENTSTART
:
2749 case SCI_DOCUMENTSTARTEXTEND
:
2750 case SCI_DOCUMENTEND
:
2751 case SCI_DOCUMENTENDEXTEND
:
2752 case SCI_STUTTEREDPAGEUP
:
2753 case SCI_STUTTEREDPAGEUPEXTEND
:
2754 case SCI_STUTTEREDPAGEDOWN
:
2755 case SCI_STUTTEREDPAGEDOWNEXTEND
:
2757 case SCI_PAGEUPEXTEND
:
2759 case SCI_PAGEDOWNEXTEND
:
2760 case SCI_EDITTOGGLEOVERTYPE
:
2762 case SCI_DELETEBACK
:
2767 case SCI_VCHOMEEXTEND
:
2768 case SCI_VCHOMEWRAP
:
2769 case SCI_VCHOMEWRAPEXTEND
:
2770 case SCI_VCHOMEDISPLAY
:
2771 case SCI_VCHOMEDISPLAYEXTEND
:
2772 case SCI_DELWORDLEFT
:
2773 case SCI_DELWORDRIGHT
:
2774 case SCI_DELWORDRIGHTEND
:
2775 case SCI_DELLINELEFT
:
2776 case SCI_DELLINERIGHT
:
2779 case SCI_LINEDELETE
:
2780 case SCI_LINETRANSPOSE
:
2781 case SCI_LINEDUPLICATE
:
2784 case SCI_LINESCROLLDOWN
:
2785 case SCI_LINESCROLLUP
:
2786 case SCI_DELETEBACKNOTLINE
:
2787 case SCI_HOMEDISPLAY
:
2788 case SCI_HOMEDISPLAYEXTEND
:
2789 case SCI_LINEENDDISPLAY
:
2790 case SCI_LINEENDDISPLAYEXTEND
:
2791 case SCI_SETSELECTIONMODE
:
2792 case SCI_LINEDOWNRECTEXTEND
:
2793 case SCI_LINEUPRECTEXTEND
:
2794 case SCI_CHARLEFTRECTEXTEND
:
2795 case SCI_CHARRIGHTRECTEXTEND
:
2796 case SCI_HOMERECTEXTEND
:
2797 case SCI_VCHOMERECTEXTEND
:
2798 case SCI_LINEENDRECTEXTEND
:
2799 case SCI_PAGEUPRECTEXTEND
:
2800 case SCI_PAGEDOWNRECTEXTEND
:
2801 case SCI_SELECTIONDUPLICATE
:
2802 case SCI_COPYALLOWLINE
:
2803 case SCI_VERTICALCENTRECARET
:
2804 case SCI_MOVESELECTEDLINESUP
:
2805 case SCI_MOVESELECTEDLINESDOWN
:
2806 case SCI_SCROLLTOSTART
:
2807 case SCI_SCROLLTOEND
:
2810 // Filter out all others like display changes. Also, newlines are redundant
2811 // with char insert messages.
2814 // printf("Filtered out %ld of macro recording\n", iMessage);
2818 // Send notification
2819 SCNotification scn
= {};
2820 scn
.nmhdr
.code
= SCN_MACRORECORD
;
2821 scn
.message
= iMessage
;
2822 scn
.wParam
= wParam
;
2823 scn
.lParam
= lParam
;
2827 // Something has changed that the container should know about
2828 void Editor::ContainerNeedsUpdate(int flags
) {
2829 needUpdateUI
|= flags
;
2833 * Force scroll and keep position relative to top of window.
2835 * If stuttered = true and not already at first/last row, move to first/last row of window.
2836 * If stuttered = true and already at first/last row, scroll as normal.
2838 void Editor::PageMove(int direction
, Selection::selTypes selt
, bool stuttered
) {
2840 SelectionPosition newPos
;
2842 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
2843 int topStutterLine
= topLine
+ caretYSlop
;
2844 int bottomStutterLine
=
2845 pdoc
->LineFromPosition(PositionFromLocation(
2846 Point::FromInts(lastXChosen
- xOffset
, direction
* vs
.lineHeight
* LinesToScroll())))
2849 if (stuttered
&& (direction
< 0 && currentLine
> topStutterLine
)) {
2850 topLineNew
= topLine
;
2851 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* caretYSlop
),
2852 false, false, UserVirtualSpace());
2854 } else if (stuttered
&& (direction
> 0 && currentLine
< bottomStutterLine
)) {
2855 topLineNew
= topLine
;
2856 newPos
= SPositionFromLocation(Point::FromInts(lastXChosen
- xOffset
, vs
.lineHeight
* (LinesToScroll() - caretYSlop
)),
2857 false, false, UserVirtualSpace());
2860 Point pt
= LocationFromPosition(sel
.MainCaret());
2862 topLineNew
= Platform::Clamp(
2863 topLine
+ direction
* LinesToScroll(), 0, MaxScrollPos());
2864 newPos
= SPositionFromLocation(
2865 Point::FromInts(lastXChosen
- xOffset
, static_cast<int>(pt
.y
) + direction
* (vs
.lineHeight
* LinesToScroll())),
2866 false, false, UserVirtualSpace());
2869 if (topLineNew
!= topLine
) {
2870 SetTopLine(topLineNew
);
2871 MovePositionTo(newPos
, selt
);
2873 SetVerticalScrollPos();
2875 MovePositionTo(newPos
, selt
);
2879 void Editor::ChangeCaseOfSelection(int caseMapping
) {
2881 for (size_t r
=0; r
<sel
.Count(); r
++) {
2882 SelectionRange current
= sel
.Range(r
);
2883 SelectionRange currentNoVS
= current
;
2884 currentNoVS
.ClearVirtualSpace();
2885 size_t rangeBytes
= currentNoVS
.Length();
2886 if (rangeBytes
> 0) {
2887 std::string sText
= RangeText(currentNoVS
.Start().Position(), currentNoVS
.End().Position());
2889 std::string sMapped
= CaseMapString(sText
, caseMapping
);
2891 if (sMapped
!= sText
) {
2892 size_t firstDifference
= 0;
2893 while (sMapped
[firstDifference
] == sText
[firstDifference
])
2895 size_t lastDifferenceText
= sText
.size() - 1;
2896 size_t lastDifferenceMapped
= sMapped
.size() - 1;
2897 while (sMapped
[lastDifferenceMapped
] == sText
[lastDifferenceText
]) {
2898 lastDifferenceText
--;
2899 lastDifferenceMapped
--;
2901 size_t endDifferenceText
= sText
.size() - 1 - lastDifferenceText
;
2903 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2904 static_cast<int>(rangeBytes
- firstDifference
- endDifferenceText
));
2905 const int lengthChange
= static_cast<int>(lastDifferenceMapped
- firstDifference
+ 1);
2906 const int lengthInserted
= pdoc
->InsertString(
2907 static_cast<int>(currentNoVS
.Start().Position() + firstDifference
),
2908 sMapped
.c_str() + firstDifference
,
2910 // Automatic movement changes selection so reset to exactly the same as it was.
2911 int diffSizes
= static_cast<int>(sMapped
.size() - sText
.size()) + lengthInserted
- lengthChange
;
2912 if (diffSizes
!= 0) {
2913 if (current
.anchor
> current
.caret
)
2914 current
.anchor
.Add(diffSizes
);
2916 current
.caret
.Add(diffSizes
);
2918 sel
.Range(r
) = current
;
2924 void Editor::LineTranspose() {
2925 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
2929 const int startPrevious
= pdoc
->LineStart(line
- 1);
2930 const std::string linePrevious
= RangeText(startPrevious
, pdoc
->LineEnd(line
- 1));
2932 int startCurrent
= pdoc
->LineStart(line
);
2933 const std::string lineCurrent
= RangeText(startCurrent
, pdoc
->LineEnd(line
));
2935 pdoc
->DeleteChars(startCurrent
, static_cast<int>(lineCurrent
.length()));
2936 pdoc
->DeleteChars(startPrevious
, static_cast<int>(linePrevious
.length()));
2937 startCurrent
-= static_cast<int>(linePrevious
.length());
2939 startCurrent
+= pdoc
->InsertString(startPrevious
, lineCurrent
.c_str(),
2940 static_cast<int>(lineCurrent
.length()));
2941 pdoc
->InsertString(startCurrent
, linePrevious
.c_str(),
2942 static_cast<int>(linePrevious
.length()));
2943 // Move caret to start of current line
2944 MovePositionTo(SelectionPosition(startCurrent
));
2948 void Editor::Duplicate(bool forLine
) {
2953 const char *eol
= "";
2956 eol
= StringFromEOLMode(pdoc
->eolMode
);
2957 eolLen
= istrlen(eol
);
2959 for (size_t r
=0; r
<sel
.Count(); r
++) {
2960 SelectionPosition start
= sel
.Range(r
).Start();
2961 SelectionPosition end
= sel
.Range(r
).End();
2963 int line
= pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position());
2964 start
= SelectionPosition(pdoc
->LineStart(line
));
2965 end
= SelectionPosition(pdoc
->LineEnd(line
));
2967 std::string text
= RangeText(start
.Position(), end
.Position());
2968 int lengthInserted
= eolLen
;
2970 lengthInserted
= pdoc
->InsertString(end
.Position(), eol
, eolLen
);
2971 pdoc
->InsertString(end
.Position() + lengthInserted
, text
.c_str(), static_cast<int>(text
.length()));
2973 if (sel
.Count() && sel
.IsRectangular()) {
2974 SelectionPosition last
= sel
.Last();
2976 int line
= pdoc
->LineFromPosition(last
.Position());
2977 last
= SelectionPosition(last
.Position() + pdoc
->LineStart(line
+1) - pdoc
->LineStart(line
));
2979 if (sel
.Rectangular().anchor
> sel
.Rectangular().caret
)
2980 sel
.Rectangular().anchor
= last
;
2982 sel
.Rectangular().caret
= last
;
2983 SetRectangularRange();
2987 void Editor::CancelModes() {
2988 sel
.SetMoveExtends(false);
2991 void Editor::NewLine() {
2992 InvalidateWholeSelection();
2993 if (sel
.IsRectangular() || !additionalSelectionTyping
) {
2994 // Remove non-main ranges
2995 sel
.DropAdditionalRanges();
2998 UndoGroup
ug(pdoc
, !sel
.Empty() || (sel
.Count() > 1));
3005 // Insert each line end
3006 size_t countInsertions
= 0;
3007 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3008 sel
.Range(r
).ClearVirtualSpace();
3009 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3010 const int positionInsert
= sel
.Range(r
).caret
.Position();
3011 const int insertLength
= pdoc
->InsertString(positionInsert
, eol
, istrlen(eol
));
3012 if (insertLength
> 0) {
3013 sel
.Range(r
) = SelectionRange(positionInsert
+ insertLength
);
3018 // Perform notifications after all the changes as the application may change the
3019 // selections in response to the characters.
3020 for (size_t i
= 0; i
< countInsertions
; i
++) {
3021 const char *eol
= StringFromEOLMode(pdoc
->eolMode
);
3024 if (recordingMacro
) {
3028 NotifyMacroRecord(SCI_REPLACESEL
, 0, reinterpret_cast<sptr_t
>(txt
));
3036 EnsureCaretVisible();
3037 // Avoid blinking during rapid typing:
3038 ShowCaretAtCurrentPosition();
3041 SelectionPosition
Editor::PositionUpOrDown(SelectionPosition spStart
, int direction
, int lastX
) {
3042 const Point pt
= LocationFromPosition(spStart
);
3045 if (vs
.annotationVisible
) {
3046 const int lineDoc
= pdoc
->LineFromPosition(spStart
.Position());
3047 const Point ptStartLine
= LocationFromPosition(pdoc
->LineStart(lineDoc
));
3048 const int subLine
= static_cast<int>(pt
.y
- ptStartLine
.y
) / vs
.lineHeight
;
3050 if (direction
< 0 && subLine
== 0) {
3051 const int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
3052 if (lineDisplay
> 0) {
3053 skipLines
= pdoc
->AnnotationLines(cs
.DocFromDisplay(lineDisplay
- 1));
3055 } else if (direction
> 0 && subLine
>= (cs
.GetHeight(lineDoc
) - 1 - pdoc
->AnnotationLines(lineDoc
))) {
3056 skipLines
= pdoc
->AnnotationLines(lineDoc
);
3060 const int newY
= static_cast<int>(pt
.y
) + (1 + skipLines
) * direction
* vs
.lineHeight
;
3062 lastX
= static_cast<int>(pt
.x
) + xOffset
;
3064 SelectionPosition posNew
= SPositionFromLocation(
3065 Point::FromInts(lastX
- xOffset
, newY
), false, false, UserVirtualSpace());
3067 if (direction
< 0) {
3068 // Line wrapping may lead to a location on the same line, so
3069 // seek back if that is the case.
3070 Point ptNew
= LocationFromPosition(posNew
.Position());
3071 while ((posNew
.Position() > 0) && (pt
.y
== ptNew
.y
)) {
3073 posNew
.SetVirtualSpace(0);
3074 ptNew
= LocationFromPosition(posNew
.Position());
3076 } else if (direction
> 0 && posNew
.Position() != pdoc
->Length()) {
3077 // There is an equivalent case when moving down which skips
3079 Point ptNew
= LocationFromPosition(posNew
.Position());
3080 while ((posNew
.Position() > spStart
.Position()) && (ptNew
.y
> newY
)) {
3082 posNew
.SetVirtualSpace(0);
3083 ptNew
= LocationFromPosition(posNew
.Position());
3089 void Editor::CursorUpOrDown(int direction
, Selection::selTypes selt
) {
3090 SelectionPosition caretToUse
= sel
.Range(sel
.Main()).caret
;
3091 if (sel
.IsRectangular()) {
3092 if (selt
== Selection::noSel
) {
3093 caretToUse
= (direction
> 0) ? sel
.Limits().end
: sel
.Limits().start
;
3095 caretToUse
= sel
.Rectangular().caret
;
3098 if (selt
== Selection::selRectangle
) {
3099 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3100 if (!sel
.IsRectangular()) {
3101 InvalidateWholeSelection();
3102 sel
.DropAdditionalRanges();
3104 const SelectionPosition posNew
= MovePositionSoVisible(
3105 PositionUpOrDown(caretToUse
, direction
, lastXChosen
), direction
);
3106 sel
.selType
= Selection::selRectangle
;
3107 sel
.Rectangular() = SelectionRange(posNew
, rangeBase
.anchor
);
3108 SetRectangularRange();
3109 MovedCaret(posNew
, caretToUse
, true);
3111 InvalidateWholeSelection();
3112 if (!additionalSelectionTyping
|| (sel
.IsRectangular())) {
3113 sel
.DropAdditionalRanges();
3115 sel
.selType
= Selection::selStream
;
3116 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3117 const int lastX
= (r
== sel
.Main()) ? lastXChosen
: -1;
3118 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3119 const SelectionPosition posNew
= MovePositionSoVisible(
3120 PositionUpOrDown(spCaretNow
, direction
, lastX
), direction
);
3121 sel
.Range(r
) = selt
== Selection::selStream
?
3122 SelectionRange(posNew
, sel
.Range(r
).anchor
) : SelectionRange(posNew
);
3124 sel
.RemoveDuplicates();
3125 MovedCaret(sel
.RangeMain().caret
, caretToUse
, true);
3129 void Editor::ParaUpOrDown(int direction
, Selection::selTypes selt
) {
3130 int lineDoc
, savedPos
= sel
.MainCaret();
3132 MovePositionTo(SelectionPosition(direction
> 0 ? pdoc
->ParaDown(sel
.MainCaret()) : pdoc
->ParaUp(sel
.MainCaret())), selt
);
3133 lineDoc
= pdoc
->LineFromPosition(sel
.MainCaret());
3134 if (direction
> 0) {
3135 if (sel
.MainCaret() >= pdoc
->Length() && !cs
.GetVisible(lineDoc
)) {
3136 if (selt
== Selection::noSel
) {
3137 MovePositionTo(SelectionPosition(pdoc
->LineEndPosition(savedPos
)));
3142 } while (!cs
.GetVisible(lineDoc
));
3145 int Editor::StartEndDisplayLine(int pos
, bool start
) {
3147 AutoSurface
surface(this);
3148 int posRet
= view
.StartEndDisplayLine(surface
, *this, pos
, start
, vs
);
3149 if (posRet
== INVALID_POSITION
) {
3158 unsigned int WithExtends(unsigned int iMessage
) {
3160 case SCI_CHARLEFT
: return SCI_CHARLEFTEXTEND
;
3161 case SCI_CHARRIGHT
: return SCI_CHARRIGHTEXTEND
;
3163 case SCI_WORDLEFT
: return SCI_WORDLEFTEXTEND
;
3164 case SCI_WORDRIGHT
: return SCI_WORDRIGHTEXTEND
;
3165 case SCI_WORDLEFTEND
: return SCI_WORDLEFTENDEXTEND
;
3166 case SCI_WORDRIGHTEND
: return SCI_WORDRIGHTENDEXTEND
;
3167 case SCI_WORDPARTLEFT
: return SCI_WORDPARTLEFTEXTEND
;
3168 case SCI_WORDPARTRIGHT
: return SCI_WORDPARTRIGHTEXTEND
;
3170 case SCI_HOME
: return SCI_HOMEEXTEND
;
3171 case SCI_HOMEDISPLAY
: return SCI_HOMEDISPLAYEXTEND
;
3172 case SCI_HOMEWRAP
: return SCI_HOMEWRAPEXTEND
;
3173 case SCI_VCHOME
: return SCI_VCHOMEEXTEND
;
3174 case SCI_VCHOMEDISPLAY
: return SCI_VCHOMEDISPLAYEXTEND
;
3175 case SCI_VCHOMEWRAP
: return SCI_VCHOMEWRAPEXTEND
;
3177 case SCI_LINEEND
: return SCI_LINEENDEXTEND
;
3178 case SCI_LINEENDDISPLAY
: return SCI_LINEENDDISPLAYEXTEND
;
3179 case SCI_LINEENDWRAP
: return SCI_LINEENDWRAPEXTEND
;
3181 default: return iMessage
;
3185 int NaturalDirection(unsigned int iMessage
) {
3188 case SCI_CHARLEFTEXTEND
:
3189 case SCI_CHARLEFTRECTEXTEND
:
3191 case SCI_WORDLEFTEXTEND
:
3192 case SCI_WORDLEFTEND
:
3193 case SCI_WORDLEFTENDEXTEND
:
3194 case SCI_WORDPARTLEFT
:
3195 case SCI_WORDPARTLEFTEXTEND
:
3197 case SCI_HOMEEXTEND
:
3198 case SCI_HOMEDISPLAY
:
3199 case SCI_HOMEDISPLAYEXTEND
:
3201 case SCI_HOMEWRAPEXTEND
:
3202 // VC_HOME* mostly goes back
3204 case SCI_VCHOMEEXTEND
:
3205 case SCI_VCHOMEDISPLAY
:
3206 case SCI_VCHOMEDISPLAYEXTEND
:
3207 case SCI_VCHOMEWRAP
:
3208 case SCI_VCHOMEWRAPEXTEND
:
3216 bool IsRectExtend(unsigned int iMessage
) {
3218 case SCI_CHARLEFTRECTEXTEND
:
3219 case SCI_CHARRIGHTRECTEXTEND
:
3220 case SCI_HOMERECTEXTEND
:
3221 case SCI_VCHOMERECTEXTEND
:
3222 case SCI_LINEENDRECTEXTEND
:
3231 int Editor::VCHomeDisplayPosition(int position
) {
3232 const int homePos
= pdoc
->VCHomePosition(position
);
3233 const int viewLineStart
= StartEndDisplayLine(position
, true);
3234 if (viewLineStart
> homePos
)
3235 return viewLineStart
;
3240 int Editor::VCHomeWrapPosition(int position
) {
3241 const int homePos
= pdoc
->VCHomePosition(position
);
3242 const int viewLineStart
= StartEndDisplayLine(position
, true);
3243 if ((viewLineStart
< position
) && (viewLineStart
> homePos
))
3244 return viewLineStart
;
3249 int Editor::LineEndWrapPosition(int position
) {
3250 const int endPos
= StartEndDisplayLine(position
, false);
3251 const int realEndPos
= pdoc
->LineEndPosition(position
);
3252 if (endPos
> realEndPos
// if moved past visible EOLs
3253 || position
>= endPos
) // if at end of display line already
3259 int Editor::HorizontalMove(unsigned int iMessage
) {
3260 if (sel
.MoveExtends()) {
3261 iMessage
= WithExtends(iMessage
);
3264 if (!multipleSelection
&& !sel
.IsRectangular()) {
3265 // Simplify selection down to 1
3266 sel
.SetSelection(sel
.RangeMain());
3269 // Invalidate each of the current selections
3270 InvalidateWholeSelection();
3272 if (IsRectExtend(iMessage
)) {
3273 const SelectionRange rangeBase
= sel
.IsRectangular() ? sel
.Rectangular() : sel
.RangeMain();
3274 if (!sel
.IsRectangular()) {
3275 sel
.DropAdditionalRanges();
3277 // Will change to rectangular if not currently rectangular
3278 SelectionPosition spCaret
= rangeBase
.caret
;
3280 case SCI_CHARLEFTRECTEXTEND
:
3281 if (pdoc
->IsLineEndPosition(spCaret
.Position()) && spCaret
.VirtualSpace()) {
3282 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3284 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3287 case SCI_CHARRIGHTRECTEXTEND
:
3288 if ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) && pdoc
->IsLineEndPosition(sel
.MainCaret())) {
3289 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3291 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3294 case SCI_HOMERECTEXTEND
:
3295 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3297 case SCI_VCHOMERECTEXTEND
:
3298 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3300 case SCI_LINEENDRECTEXTEND
:
3301 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3304 const int directionMove
= (spCaret
< rangeBase
.caret
) ? -1 : 1;
3305 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3306 sel
.selType
= Selection::selRectangle
;
3307 sel
.Rectangular() = SelectionRange(spCaret
, rangeBase
.anchor
);
3308 SetRectangularRange();
3310 if (sel
.IsRectangular()) {
3311 // Not a rectangular extension so switch to stream.
3312 SelectionPosition selAtLimit
= (NaturalDirection(iMessage
) > 0) ? sel
.Limits().end
: sel
.Limits().start
;
3313 sel
.selType
= Selection::selStream
;
3314 sel
.SetSelection(SelectionRange(selAtLimit
));
3316 if (!additionalSelectionTyping
) {
3317 InvalidateWholeSelection();
3318 sel
.DropAdditionalRanges();
3320 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3321 const SelectionPosition spCaretNow
= sel
.Range(r
).caret
;
3322 SelectionPosition spCaret
= spCaretNow
;
3325 case SCI_CHARLEFTEXTEND
:
3326 if (spCaret
.VirtualSpace()) {
3327 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() - 1);
3329 spCaret
= SelectionPosition(spCaret
.Position() - 1);
3333 case SCI_CHARRIGHTEXTEND
:
3334 if ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) && pdoc
->IsLineEndPosition(spCaret
.Position())) {
3335 spCaret
.SetVirtualSpace(spCaret
.VirtualSpace() + 1);
3337 spCaret
= SelectionPosition(spCaret
.Position() + 1);
3341 case SCI_WORDLEFTEXTEND
:
3342 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), -1));
3345 case SCI_WORDRIGHTEXTEND
:
3346 spCaret
= SelectionPosition(pdoc
->NextWordStart(spCaret
.Position(), 1));
3348 case SCI_WORDLEFTEND
:
3349 case SCI_WORDLEFTENDEXTEND
:
3350 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), -1));
3352 case SCI_WORDRIGHTEND
:
3353 case SCI_WORDRIGHTENDEXTEND
:
3354 spCaret
= SelectionPosition(pdoc
->NextWordEnd(spCaret
.Position(), 1));
3356 case SCI_WORDPARTLEFT
:
3357 case SCI_WORDPARTLEFTEXTEND
:
3358 spCaret
= SelectionPosition(pdoc
->WordPartLeft(spCaret
.Position()));
3360 case SCI_WORDPARTRIGHT
:
3361 case SCI_WORDPARTRIGHTEXTEND
:
3362 spCaret
= SelectionPosition(pdoc
->WordPartRight(spCaret
.Position()));
3365 case SCI_HOMEEXTEND
:
3366 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3368 case SCI_HOMEDISPLAY
:
3369 case SCI_HOMEDISPLAYEXTEND
:
3370 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), true));
3373 case SCI_HOMEWRAPEXTEND
:
3374 spCaret
= MovePositionSoVisible(StartEndDisplayLine(spCaret
.Position(), true), -1);
3375 if (spCaretNow
<= spCaret
)
3376 spCaret
= SelectionPosition(pdoc
->LineStart(pdoc
->LineFromPosition(spCaret
.Position())));
3379 case SCI_VCHOMEEXTEND
:
3380 // VCHome alternates between beginning of line and beginning of text so may move back or forwards
3381 spCaret
= SelectionPosition(pdoc
->VCHomePosition(spCaret
.Position()));
3383 case SCI_VCHOMEDISPLAY
:
3384 case SCI_VCHOMEDISPLAYEXTEND
:
3385 spCaret
= SelectionPosition(VCHomeDisplayPosition(spCaret
.Position()));
3387 case SCI_VCHOMEWRAP
:
3388 case SCI_VCHOMEWRAPEXTEND
:
3389 spCaret
= SelectionPosition(VCHomeWrapPosition(spCaret
.Position()));
3392 case SCI_LINEENDEXTEND
:
3393 spCaret
= SelectionPosition(pdoc
->LineEndPosition(spCaret
.Position()));
3395 case SCI_LINEENDDISPLAY
:
3396 case SCI_LINEENDDISPLAYEXTEND
:
3397 spCaret
= SelectionPosition(StartEndDisplayLine(spCaret
.Position(), false));
3399 case SCI_LINEENDWRAP
:
3400 case SCI_LINEENDWRAPEXTEND
:
3401 spCaret
= SelectionPosition(LineEndWrapPosition(spCaret
.Position()));
3405 PLATFORM_ASSERT(false);
3408 const int directionMove
= (spCaret
< spCaretNow
) ? -1 : 1;
3409 spCaret
= MovePositionSoVisible(spCaret
, directionMove
);
3411 // Handle move versus extend, and special behaviour for non-emoty left/right
3415 if (sel
.Range(r
).Empty()) {
3416 sel
.Range(r
) = SelectionRange(spCaret
);
3418 sel
.Range(r
) = SelectionRange(
3419 (iMessage
== SCI_CHARLEFT
) ? sel
.Range(r
).Start() : sel
.Range(r
).End());
3425 case SCI_WORDLEFTEND
:
3426 case SCI_WORDRIGHTEND
:
3427 case SCI_WORDPARTLEFT
:
3428 case SCI_WORDPARTRIGHT
:
3430 case SCI_HOMEDISPLAY
:
3433 case SCI_VCHOMEDISPLAY
:
3434 case SCI_VCHOMEWRAP
:
3436 case SCI_LINEENDDISPLAY
:
3437 case SCI_LINEENDWRAP
:
3438 sel
.Range(r
) = SelectionRange(spCaret
);
3441 case SCI_CHARLEFTEXTEND
:
3442 case SCI_CHARRIGHTEXTEND
:
3443 case SCI_WORDLEFTEXTEND
:
3444 case SCI_WORDRIGHTEXTEND
:
3445 case SCI_WORDLEFTENDEXTEND
:
3446 case SCI_WORDRIGHTENDEXTEND
:
3447 case SCI_WORDPARTLEFTEXTEND
:
3448 case SCI_WORDPARTRIGHTEXTEND
:
3449 case SCI_HOMEEXTEND
:
3450 case SCI_HOMEDISPLAYEXTEND
:
3451 case SCI_HOMEWRAPEXTEND
:
3452 case SCI_VCHOMEEXTEND
:
3453 case SCI_VCHOMEDISPLAYEXTEND
:
3454 case SCI_VCHOMEWRAPEXTEND
:
3455 case SCI_LINEENDEXTEND
:
3456 case SCI_LINEENDDISPLAYEXTEND
:
3457 case SCI_LINEENDWRAPEXTEND
: {
3458 SelectionRange rangeNew
= SelectionRange(spCaret
, sel
.Range(r
).anchor
);
3459 sel
.TrimOtherSelections(r
, SelectionRange(rangeNew
));
3460 sel
.Range(r
) = rangeNew
;
3465 PLATFORM_ASSERT(false);
3470 sel
.RemoveDuplicates();
3472 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3474 // Invalidate the new state of the selection
3475 InvalidateWholeSelection();
3478 // Need the line moving and so forth from MovePositionTo
3482 int Editor::DelWordOrLine(unsigned int iMessage
) {
3483 // Virtual space may be realised for SCI_DELWORDRIGHT or SCI_DELWORDRIGHTEND
3484 // which means 2 actions so wrap in an undo group.
3486 // Rightwards and leftwards deletions differ in treatment of virtual space.
3487 // Clear virtual space for leftwards, realise for rightwards.
3488 const bool leftwards
= (iMessage
== SCI_DELWORDLEFT
) || (iMessage
== SCI_DELLINELEFT
);
3490 if (!additionalSelectionTyping
) {
3491 InvalidateWholeSelection();
3492 sel
.DropAdditionalRanges();
3495 UndoGroup
ug0(pdoc
, (sel
.Count() > 1) || !leftwards
);
3497 for (size_t r
= 0; r
< sel
.Count(); r
++) {
3499 // Delete to the left so first clear the virtual space.
3500 sel
.Range(r
).ClearVirtualSpace();
3502 // Delete to the right so first realise the virtual space.
3503 sel
.Range(r
) = SelectionRange(
3504 InsertSpace(sel
.Range(r
).caret
.Position(), sel
.Range(r
).caret
.VirtualSpace()));
3509 case SCI_DELWORDLEFT
:
3510 rangeDelete
= Range(
3511 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), -1),
3512 sel
.Range(r
).caret
.Position());
3514 case SCI_DELWORDRIGHT
:
3515 rangeDelete
= Range(
3516 sel
.Range(r
).caret
.Position(),
3517 pdoc
->NextWordStart(sel
.Range(r
).caret
.Position(), 1));
3519 case SCI_DELWORDRIGHTEND
:
3520 rangeDelete
= Range(
3521 sel
.Range(r
).caret
.Position(),
3522 pdoc
->NextWordEnd(sel
.Range(r
).caret
.Position(), 1));
3524 case SCI_DELLINELEFT
:
3525 rangeDelete
= Range(
3526 pdoc
->LineStart(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())),
3527 sel
.Range(r
).caret
.Position());
3529 case SCI_DELLINERIGHT
:
3530 rangeDelete
= Range(
3531 sel
.Range(r
).caret
.Position(),
3532 pdoc
->LineEnd(pdoc
->LineFromPosition(sel
.Range(r
).caret
.Position())));
3535 if (!RangeContainsProtected(rangeDelete
.start
, rangeDelete
.end
)) {
3536 pdoc
->DeleteChars(rangeDelete
.start
, rangeDelete
.end
- rangeDelete
.start
);
3540 // May need something stronger here: can selections overlap at this point?
3541 sel
.RemoveDuplicates();
3543 MovedCaret(sel
.RangeMain().caret
, SelectionPosition(INVALID_POSITION
), true);
3545 // Invalidate the new state of the selection
3546 InvalidateWholeSelection();
3552 int Editor::KeyCommand(unsigned int iMessage
) {
3555 CursorUpOrDown(1, Selection::noSel
);
3557 case SCI_LINEDOWNEXTEND
:
3558 CursorUpOrDown(1, Selection::selStream
);
3560 case SCI_LINEDOWNRECTEXTEND
:
3561 CursorUpOrDown(1, Selection::selRectangle
);
3564 ParaUpOrDown(1, Selection::noSel
);
3566 case SCI_PARADOWNEXTEND
:
3567 ParaUpOrDown(1, Selection::selStream
);
3569 case SCI_LINESCROLLDOWN
:
3570 ScrollTo(topLine
+ 1);
3571 MoveCaretInsideView(false);
3574 CursorUpOrDown(-1, Selection::noSel
);
3576 case SCI_LINEUPEXTEND
:
3577 CursorUpOrDown(-1, Selection::selStream
);
3579 case SCI_LINEUPRECTEXTEND
:
3580 CursorUpOrDown(-1, Selection::selRectangle
);
3583 ParaUpOrDown(-1, Selection::noSel
);
3585 case SCI_PARAUPEXTEND
:
3586 ParaUpOrDown(-1, Selection::selStream
);
3588 case SCI_LINESCROLLUP
:
3589 ScrollTo(topLine
- 1);
3590 MoveCaretInsideView(false);
3594 case SCI_CHARLEFTEXTEND
:
3595 case SCI_CHARLEFTRECTEXTEND
:
3597 case SCI_CHARRIGHTEXTEND
:
3598 case SCI_CHARRIGHTRECTEXTEND
:
3600 case SCI_WORDLEFTEXTEND
:
3602 case SCI_WORDRIGHTEXTEND
:
3603 case SCI_WORDLEFTEND
:
3604 case SCI_WORDLEFTENDEXTEND
:
3605 case SCI_WORDRIGHTEND
:
3606 case SCI_WORDRIGHTENDEXTEND
:
3607 case SCI_WORDPARTLEFT
:
3608 case SCI_WORDPARTLEFTEXTEND
:
3609 case SCI_WORDPARTRIGHT
:
3610 case SCI_WORDPARTRIGHTEXTEND
:
3612 case SCI_HOMEEXTEND
:
3613 case SCI_HOMERECTEXTEND
:
3614 case SCI_HOMEDISPLAY
:
3615 case SCI_HOMEDISPLAYEXTEND
:
3617 case SCI_HOMEWRAPEXTEND
:
3619 case SCI_VCHOMEEXTEND
:
3620 case SCI_VCHOMERECTEXTEND
:
3621 case SCI_VCHOMEDISPLAY
:
3622 case SCI_VCHOMEDISPLAYEXTEND
:
3623 case SCI_VCHOMEWRAP
:
3624 case SCI_VCHOMEWRAPEXTEND
:
3626 case SCI_LINEENDEXTEND
:
3627 case SCI_LINEENDRECTEXTEND
:
3628 case SCI_LINEENDDISPLAY
:
3629 case SCI_LINEENDDISPLAYEXTEND
:
3630 case SCI_LINEENDWRAP
:
3631 case SCI_LINEENDWRAPEXTEND
:
3632 return HorizontalMove(iMessage
);
3634 case SCI_DOCUMENTSTART
:
3638 case SCI_DOCUMENTSTARTEXTEND
:
3639 MovePositionTo(0, Selection::selStream
);
3642 case SCI_DOCUMENTEND
:
3643 MovePositionTo(pdoc
->Length());
3646 case SCI_DOCUMENTENDEXTEND
:
3647 MovePositionTo(pdoc
->Length(), Selection::selStream
);
3650 case SCI_STUTTEREDPAGEUP
:
3651 PageMove(-1, Selection::noSel
, true);
3653 case SCI_STUTTEREDPAGEUPEXTEND
:
3654 PageMove(-1, Selection::selStream
, true);
3656 case SCI_STUTTEREDPAGEDOWN
:
3657 PageMove(1, Selection::noSel
, true);
3659 case SCI_STUTTEREDPAGEDOWNEXTEND
:
3660 PageMove(1, Selection::selStream
, true);
3665 case SCI_PAGEUPEXTEND
:
3666 PageMove(-1, Selection::selStream
);
3668 case SCI_PAGEUPRECTEXTEND
:
3669 PageMove(-1, Selection::selRectangle
);
3674 case SCI_PAGEDOWNEXTEND
:
3675 PageMove(1, Selection::selStream
);
3677 case SCI_PAGEDOWNRECTEXTEND
:
3678 PageMove(1, Selection::selRectangle
);
3680 case SCI_EDITTOGGLEOVERTYPE
:
3681 inOverstrike
= !inOverstrike
;
3682 ShowCaretAtCurrentPosition();
3683 ContainerNeedsUpdate(SC_UPDATE_CONTENT
);
3686 case SCI_CANCEL
: // Cancel any modes - handled in subclass
3687 // Also unselect text
3689 if (sel
.Count() > 1) {
3690 // Drop additional selections
3691 InvalidateWholeSelection();
3692 sel
.DropAdditionalRanges();
3695 case SCI_DELETEBACK
:
3697 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3700 EnsureCaretVisible();
3702 case SCI_DELETEBACKNOTLINE
:
3704 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3707 EnsureCaretVisible();
3711 if (caretSticky
== SC_CARETSTICKY_OFF
) {
3714 EnsureCaretVisible();
3715 ShowCaretAtCurrentPosition(); // Avoid blinking
3719 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
3722 EnsureCaretVisible();
3723 ShowCaretAtCurrentPosition(); // Avoid blinking
3732 if (vs
.zoomLevel
< 20) {
3734 InvalidateStyleRedraw();
3739 if (vs
.zoomLevel
> -10) {
3741 InvalidateStyleRedraw();
3746 case SCI_DELWORDLEFT
:
3747 case SCI_DELWORDRIGHT
:
3748 case SCI_DELWORDRIGHTEND
:
3749 case SCI_DELLINELEFT
:
3750 case SCI_DELLINERIGHT
:
3751 return DelWordOrLine(iMessage
);
3753 case SCI_LINECOPY
: {
3754 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3755 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3756 CopyRangeToClipboard(pdoc
->LineStart(lineStart
),
3757 pdoc
->LineStart(lineEnd
+ 1));
3761 int lineStart
= pdoc
->LineFromPosition(SelectionStart().Position());
3762 int lineEnd
= pdoc
->LineFromPosition(SelectionEnd().Position());
3763 int start
= pdoc
->LineStart(lineStart
);
3764 int end
= pdoc
->LineStart(lineEnd
+ 1);
3765 SetSelection(start
, end
);
3770 case SCI_LINEDELETE
: {
3771 int line
= pdoc
->LineFromPosition(sel
.MainCaret());
3772 int start
= pdoc
->LineStart(line
);
3773 int end
= pdoc
->LineStart(line
+ 1);
3774 pdoc
->DeleteChars(start
, end
- start
);
3777 case SCI_LINETRANSPOSE
:
3780 case SCI_LINEDUPLICATE
:
3783 case SCI_SELECTIONDUPLICATE
:
3787 ChangeCaseOfSelection(cmLower
);
3790 ChangeCaseOfSelection(cmUpper
);
3792 case SCI_SCROLLTOSTART
:
3795 case SCI_SCROLLTOEND
:
3796 ScrollTo(MaxScrollPos());
3802 int Editor::KeyDefault(int, int) {
3806 int Editor::KeyDownWithModifiers(int key
, int modifiers
, bool *consumed
) {
3808 int msg
= kmap
.Find(key
, modifiers
);
3812 return static_cast<int>(WndProc(msg
, 0, 0));
3816 return KeyDefault(key
, modifiers
);
3820 int Editor::KeyDown(int key
, bool shift
, bool ctrl
, bool alt
, bool *consumed
) {
3821 return KeyDownWithModifiers(key
, ModifierFlags(shift
, ctrl
, alt
), consumed
);
3824 void Editor::Indent(bool forwards
) {
3826 for (size_t r
=0; r
<sel
.Count(); r
++) {
3827 int lineOfAnchor
= pdoc
->LineFromPosition(sel
.Range(r
).anchor
.Position());
3828 int caretPosition
= sel
.Range(r
).caret
.Position();
3829 int lineCurrentPos
= pdoc
->LineFromPosition(caretPosition
);
3830 if (lineOfAnchor
== lineCurrentPos
) {
3832 pdoc
->DeleteChars(sel
.Range(r
).Start().Position(), sel
.Range(r
).Length());
3833 caretPosition
= sel
.Range(r
).caret
.Position();
3834 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetColumn(pdoc
->GetLineIndentPosition(lineCurrentPos
)) &&
3836 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3837 int indentationStep
= pdoc
->IndentSize();
3838 const int posSelect
= pdoc
->SetLineIndentation(
3839 lineCurrentPos
, indentation
+ indentationStep
- indentation
% indentationStep
);
3840 sel
.Range(r
) = SelectionRange(posSelect
);
3842 if (pdoc
->useTabs
) {
3843 const int lengthInserted
= pdoc
->InsertString(caretPosition
, "\t", 1);
3844 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3846 int numSpaces
= (pdoc
->tabInChars
) -
3847 (pdoc
->GetColumn(caretPosition
) % (pdoc
->tabInChars
));
3849 numSpaces
= pdoc
->tabInChars
;
3850 const std::string
spaceText(numSpaces
, ' ');
3851 const int lengthInserted
= pdoc
->InsertString(caretPosition
, spaceText
.c_str(),
3852 static_cast<int>(spaceText
.length()));
3853 sel
.Range(r
) = SelectionRange(caretPosition
+ lengthInserted
);
3857 if (pdoc
->GetColumn(caretPosition
) <= pdoc
->GetLineIndentation(lineCurrentPos
) &&
3859 int indentation
= pdoc
->GetLineIndentation(lineCurrentPos
);
3860 int indentationStep
= pdoc
->IndentSize();
3861 const int posSelect
= pdoc
->SetLineIndentation(lineCurrentPos
, indentation
- indentationStep
);
3862 sel
.Range(r
) = SelectionRange(posSelect
);
3864 int newColumn
= ((pdoc
->GetColumn(caretPosition
) - 1) / pdoc
->tabInChars
) *
3868 int newPos
= caretPosition
;
3869 while (pdoc
->GetColumn(newPos
) > newColumn
)
3871 sel
.Range(r
) = SelectionRange(newPos
);
3874 } else { // Multiline
3875 int anchorPosOnLine
= sel
.Range(r
).anchor
.Position() - pdoc
->LineStart(lineOfAnchor
);
3876 int currentPosPosOnLine
= caretPosition
- pdoc
->LineStart(lineCurrentPos
);
3877 // Multiple lines selected so indent / dedent
3878 int lineTopSel
= Platform::Minimum(lineOfAnchor
, lineCurrentPos
);
3879 int lineBottomSel
= Platform::Maximum(lineOfAnchor
, lineCurrentPos
);
3880 if (pdoc
->LineStart(lineBottomSel
) == sel
.Range(r
).anchor
.Position() || pdoc
->LineStart(lineBottomSel
) == caretPosition
)
3881 lineBottomSel
--; // If not selecting any characters on a line, do not indent
3882 pdoc
->Indent(forwards
, lineBottomSel
, lineTopSel
);
3883 if (lineOfAnchor
< lineCurrentPos
) {
3884 if (currentPosPosOnLine
== 0)
3885 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3887 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
+ 1), pdoc
->LineStart(lineOfAnchor
));
3889 if (anchorPosOnLine
== 0)
3890 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
));
3892 sel
.Range(r
) = SelectionRange(pdoc
->LineStart(lineCurrentPos
), pdoc
->LineStart(lineOfAnchor
+ 1));
3896 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
3899 class CaseFolderASCII
: public CaseFolderTable
{
3904 ~CaseFolderASCII() {
3909 CaseFolder
*Editor::CaseFolderForEncoding() {
3910 // Simple default that only maps ASCII upper case to lower case.
3911 return new CaseFolderASCII();
3915 * Search of a text in the document, in the given range.
3916 * @return The position of the found text, -1 if not found.
3918 long Editor::FindText(
3919 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3920 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3921 sptr_t lParam
) { ///< @c TextToFind structure: The text to search for in the given range.
3923 Sci_TextToFind
*ft
= reinterpret_cast<Sci_TextToFind
*>(lParam
);
3924 int lengthFound
= istrlen(ft
->lpstrText
);
3925 if (!pdoc
->HasCaseFolder())
3926 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3928 long pos
= pdoc
->FindText(
3929 static_cast<int>(ft
->chrg
.cpMin
),
3930 static_cast<int>(ft
->chrg
.cpMax
),
3932 static_cast<int>(wParam
),
3935 ft
->chrgText
.cpMin
= pos
;
3936 ft
->chrgText
.cpMax
= pos
+ lengthFound
;
3938 return static_cast<int>(pos
);
3939 } catch (RegexError
&) {
3940 errorStatus
= SC_STATUS_WARN_REGEX
;
3946 * Relocatable search support : Searches relative to current selection
3947 * point and sets the selection to the found text range with
3951 * Anchor following searches at current selection start: This allows
3952 * multiple incremental interactive searches to be macro recorded
3953 * while still setting the selection to found text so the find/select
3954 * operation is self-contained.
3956 void Editor::SearchAnchor() {
3957 searchAnchor
= SelectionStart().Position();
3961 * Find text from current search anchor: Must call @c SearchAnchor first.
3962 * Used for next text and previous text requests.
3963 * @return The position of the found text, -1 if not found.
3965 long Editor::SearchText(
3966 unsigned int iMessage
, ///< Accepts both @c SCI_SEARCHNEXT and @c SCI_SEARCHPREV.
3967 uptr_t wParam
, ///< Search modes : @c SCFIND_MATCHCASE, @c SCFIND_WHOLEWORD,
3968 ///< @c SCFIND_WORDSTART, @c SCFIND_REGEXP or @c SCFIND_POSIX.
3969 sptr_t lParam
) { ///< The text to search for.
3971 const char *txt
= reinterpret_cast<char *>(lParam
);
3973 int lengthFound
= istrlen(txt
);
3974 if (!pdoc
->HasCaseFolder())
3975 pdoc
->SetCaseFolder(CaseFolderForEncoding());
3977 if (iMessage
== SCI_SEARCHNEXT
) {
3978 pos
= pdoc
->FindText(searchAnchor
, pdoc
->Length(), txt
,
3979 static_cast<int>(wParam
),
3982 pos
= pdoc
->FindText(searchAnchor
, 0, txt
,
3983 static_cast<int>(wParam
),
3986 } catch (RegexError
&) {
3987 errorStatus
= SC_STATUS_WARN_REGEX
;
3991 SetSelection(static_cast<int>(pos
), static_cast<int>(pos
+ lengthFound
));
3997 std::string
Editor::CaseMapString(const std::string
&s
, int caseMapping
) {
3999 for (size_t i
=0; i
<ret
.size(); i
++) {
4000 switch (caseMapping
) {
4002 if (ret
[i
] >= 'a' && ret
[i
] <= 'z')
4003 ret
[i
] = static_cast<char>(ret
[i
] - 'a' + 'A');
4006 if (ret
[i
] >= 'A' && ret
[i
] <= 'Z')
4007 ret
[i
] = static_cast<char>(ret
[i
] - 'A' + 'a');
4015 * Search for text in the target range of the document.
4016 * @return The position of the found text, -1 if not found.
4018 long Editor::SearchInTarget(const char *text
, int length
) {
4019 int lengthFound
= length
;
4021 if (!pdoc
->HasCaseFolder())
4022 pdoc
->SetCaseFolder(CaseFolderForEncoding());
4024 long pos
= pdoc
->FindText(targetStart
, targetEnd
, text
,
4028 targetStart
= static_cast<int>(pos
);
4029 targetEnd
= static_cast<int>(pos
+ lengthFound
);
4032 } catch (RegexError
&) {
4033 errorStatus
= SC_STATUS_WARN_REGEX
;
4038 void Editor::GoToLine(int lineNo
) {
4039 if (lineNo
> pdoc
->LinesTotal())
4040 lineNo
= pdoc
->LinesTotal();
4043 SetEmptySelection(pdoc
->LineStart(lineNo
));
4044 ShowCaretAtCurrentPosition();
4045 EnsureCaretVisible();
4048 static bool Close(Point pt1
, Point pt2
, Point threshold
) {
4049 if (std::abs(pt1
.x
- pt2
.x
) > threshold
.x
)
4051 if (std::abs(pt1
.y
- pt2
.y
) > threshold
.y
)
4056 std::string
Editor::RangeText(int start
, int end
) const {
4058 int len
= end
- start
;
4059 std::string
ret(len
, '\0');
4060 for (int i
= 0; i
< len
; i
++) {
4061 ret
[i
] = pdoc
->CharAt(start
+ i
);
4065 return std::string();
4068 void Editor::CopySelectionRange(SelectionText
*ss
, bool allowLineCopy
) {
4070 if (allowLineCopy
) {
4071 int currentLine
= pdoc
->LineFromPosition(sel
.MainCaret());
4072 int start
= pdoc
->LineStart(currentLine
);
4073 int end
= pdoc
->LineEnd(currentLine
);
4075 std::string text
= RangeText(start
, end
);
4076 if (pdoc
->eolMode
!= SC_EOL_LF
)
4077 text
.push_back('\r');
4078 if (pdoc
->eolMode
!= SC_EOL_CR
)
4079 text
.push_back('\n');
4080 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4081 vs
.styles
[STYLE_DEFAULT
].characterSet
, false, true);
4085 std::vector
<SelectionRange
> rangesInOrder
= sel
.RangesCopy();
4086 if (sel
.selType
== Selection::selRectangle
)
4087 std::sort(rangesInOrder
.begin(), rangesInOrder
.end());
4088 for (size_t r
=0; r
<rangesInOrder
.size(); r
++) {
4089 SelectionRange current
= rangesInOrder
[r
];
4090 text
.append(RangeText(current
.Start().Position(), current
.End().Position()));
4091 if (sel
.selType
== Selection::selRectangle
) {
4092 if (pdoc
->eolMode
!= SC_EOL_LF
)
4093 text
.push_back('\r');
4094 if (pdoc
->eolMode
!= SC_EOL_CR
)
4095 text
.push_back('\n');
4098 ss
->Copy(text
, pdoc
->dbcsCodePage
,
4099 vs
.styles
[STYLE_DEFAULT
].characterSet
, sel
.IsRectangular(), sel
.selType
== Selection::selLines
);
4103 void Editor::CopyRangeToClipboard(int start
, int end
) {
4104 start
= pdoc
->ClampPositionIntoDocument(start
);
4105 end
= pdoc
->ClampPositionIntoDocument(end
);
4106 SelectionText selectedText
;
4107 std::string text
= RangeText(start
, end
);
4108 selectedText
.Copy(text
,
4109 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4110 CopyToClipboard(selectedText
);
4113 void Editor::CopyText(int length
, const char *text
) {
4114 SelectionText selectedText
;
4115 selectedText
.Copy(std::string(text
, length
),
4116 pdoc
->dbcsCodePage
, vs
.styles
[STYLE_DEFAULT
].characterSet
, false, false);
4117 CopyToClipboard(selectedText
);
4120 void Editor::SetDragPosition(SelectionPosition newPos
) {
4121 if (newPos
.Position() >= 0) {
4122 newPos
= MovePositionOutsideChar(newPos
, 1);
4125 if (!(posDrag
== newPos
)) {
4127 if (FineTickerAvailable()) {
4128 FineTickerCancel(tickCaret
);
4129 if ((caret
.active
) && (caret
.period
> 0) && (newPos
.Position() < 0))
4130 FineTickerStart(tickCaret
, caret
.period
, caret
.period
/10);
4140 void Editor::DisplayCursor(Window::Cursor c
) {
4141 if (cursorMode
== SC_CURSORNORMAL
)
4144 wMain
.SetCursor(static_cast<Window::Cursor
>(cursorMode
));
4147 bool Editor::DragThreshold(Point ptStart
, Point ptNow
) {
4148 int xMove
= static_cast<int>(ptStart
.x
- ptNow
.x
);
4149 int yMove
= static_cast<int>(ptStart
.y
- ptNow
.y
);
4150 int distanceSquared
= xMove
* xMove
+ yMove
* yMove
;
4151 return distanceSquared
> 16;
4154 void Editor::StartDrag() {
4155 // Always handled by subclasses
4156 //SetMouseCapture(true);
4157 //DisplayCursor(Window::cursorArrow);
4160 void Editor::DropAt(SelectionPosition position
, const char *value
, size_t lengthValue
, bool moving
, bool rectangular
) {
4161 //Platform::DebugPrintf("DropAt %d %d\n", inDragDrop, position);
4162 if (inDragDrop
== ddDragging
)
4163 dropWentOutside
= false;
4165 bool positionWasInSelection
= PositionInSelection(position
.Position());
4167 bool positionOnEdgeOfSelection
=
4168 (position
== SelectionStart()) || (position
== SelectionEnd());
4170 if ((inDragDrop
!= ddDragging
) || !(positionWasInSelection
) ||
4171 (positionOnEdgeOfSelection
&& !moving
)) {
4173 SelectionPosition selStart
= SelectionStart();
4174 SelectionPosition selEnd
= SelectionEnd();
4178 SelectionPosition positionAfterDeletion
= position
;
4179 if ((inDragDrop
== ddDragging
) && moving
) {
4180 // Remove dragged out text
4181 if (rectangular
|| sel
.selType
== Selection::selLines
) {
4182 for (size_t r
=0; r
<sel
.Count(); r
++) {
4183 if (position
>= sel
.Range(r
).Start()) {
4184 if (position
> sel
.Range(r
).End()) {
4185 positionAfterDeletion
.Add(-sel
.Range(r
).Length());
4187 positionAfterDeletion
.Add(-SelectionRange(position
, sel
.Range(r
).Start()).Length());
4192 if (position
> selStart
) {
4193 positionAfterDeletion
.Add(-SelectionRange(selEnd
, selStart
).Length());
4198 position
= positionAfterDeletion
;
4200 std::string convertedText
= Document::TransformLineEnds(value
, lengthValue
, pdoc
->eolMode
);
4203 PasteRectangular(position
, convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4204 // Should try to select new rectangle but it may not be a rectangle now so just select the drop position
4205 SetEmptySelection(position
);
4207 position
= MovePositionOutsideChar(position
, sel
.MainCaret() - position
.Position());
4208 position
= SelectionPosition(InsertSpace(position
.Position(), position
.VirtualSpace()));
4209 const int lengthInserted
= pdoc
->InsertString(
4210 position
.Position(), convertedText
.c_str(), static_cast<int>(convertedText
.length()));
4211 if (lengthInserted
> 0) {
4212 SelectionPosition posAfterInsertion
= position
;
4213 posAfterInsertion
.Add(lengthInserted
);
4214 SetSelection(posAfterInsertion
, position
);
4217 } else if (inDragDrop
== ddDragging
) {
4218 SetEmptySelection(position
);
4222 void Editor::DropAt(SelectionPosition position
, const char *value
, bool moving
, bool rectangular
) {
4223 DropAt(position
, value
, strlen(value
), moving
, rectangular
);
4227 * @return true if given position is inside the selection,
4229 bool Editor::PositionInSelection(int pos
) {
4230 pos
= MovePositionOutsideChar(pos
, sel
.MainCaret() - pos
);
4231 for (size_t r
=0; r
<sel
.Count(); r
++) {
4232 if (sel
.Range(r
).Contains(pos
))
4238 bool Editor::PointInSelection(Point pt
) {
4239 SelectionPosition pos
= SPositionFromLocation(pt
, false, true);
4240 Point ptPos
= LocationFromPosition(pos
);
4241 for (size_t r
=0; r
<sel
.Count(); r
++) {
4242 SelectionRange range
= sel
.Range(r
);
4243 if (range
.Contains(pos
)) {
4245 if (pos
== range
.Start()) {
4246 // see if just before selection
4247 if (pt
.x
< ptPos
.x
) {
4251 if (pos
== range
.End()) {
4252 // see if just after selection
4253 if (pt
.x
> ptPos
.x
) {
4264 bool Editor::PointInSelMargin(Point pt
) const {
4265 // Really means: "Point in a margin"
4266 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4267 PRectangle rcSelMargin
= GetClientRectangle();
4268 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.leftMarginWidth
);
4269 rcSelMargin
.left
= static_cast<XYPOSITION
>(vs
.textStart
- vs
.fixedColumnWidth
);
4270 return rcSelMargin
.ContainsWholePixel(pt
);
4276 Window::Cursor
Editor::GetMarginCursor(Point pt
) const {
4278 for (int margin
= 0; margin
<= SC_MAX_MARGIN
; margin
++) {
4279 if ((pt
.x
>= x
) && (pt
.x
< x
+ vs
.ms
[margin
].width
))
4280 return static_cast<Window::Cursor
>(vs
.ms
[margin
].cursor
);
4281 x
+= vs
.ms
[margin
].width
;
4283 return Window::cursorReverseArrow
;
4286 void Editor::TrimAndSetSelection(int currentPos_
, int anchor_
) {
4287 sel
.TrimSelection(SelectionRange(currentPos_
, anchor_
));
4288 SetSelection(currentPos_
, anchor_
);
4291 void Editor::LineSelection(int lineCurrentPos_
, int lineAnchorPos_
, bool wholeLine
) {
4292 int selCurrentPos
, selAnchorPos
;
4294 int lineCurrent_
= pdoc
->LineFromPosition(lineCurrentPos_
);
4295 int lineAnchor_
= pdoc
->LineFromPosition(lineAnchorPos_
);
4296 if (lineAnchorPos_
< lineCurrentPos_
) {
4297 selCurrentPos
= pdoc
->LineStart(lineCurrent_
+ 1);
4298 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4299 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4300 selCurrentPos
= pdoc
->LineStart(lineCurrent_
);
4301 selAnchorPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4302 } else { // Same line, select it
4303 selCurrentPos
= pdoc
->LineStart(lineAnchor_
+ 1);
4304 selAnchorPos
= pdoc
->LineStart(lineAnchor_
);
4307 if (lineAnchorPos_
< lineCurrentPos_
) {
4308 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, false) + 1;
4309 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4310 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4311 } else if (lineAnchorPos_
> lineCurrentPos_
) {
4312 selCurrentPos
= StartEndDisplayLine(lineCurrentPos_
, true);
4313 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4314 selAnchorPos
= pdoc
->MovePositionOutsideChar(selAnchorPos
, 1);
4315 } else { // Same line, select it
4316 selCurrentPos
= StartEndDisplayLine(lineAnchorPos_
, false) + 1;
4317 selCurrentPos
= pdoc
->MovePositionOutsideChar(selCurrentPos
, 1);
4318 selAnchorPos
= StartEndDisplayLine(lineAnchorPos_
, true);
4321 TrimAndSetSelection(selCurrentPos
, selAnchorPos
);
4324 void Editor::WordSelection(int pos
) {
4325 if (pos
< wordSelectAnchorStartPos
) {
4326 // Extend backward to the word containing pos.
4327 // Skip ExtendWordSelect if the line is empty or if pos is after the last character.
4328 // This ensures that a series of empty lines isn't counted as a single "word".
4329 if (!pdoc
->IsLineEndPosition(pos
))
4330 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
+ 1, 1), -1);
4331 TrimAndSetSelection(pos
, wordSelectAnchorEndPos
);
4332 } else if (pos
> wordSelectAnchorEndPos
) {
4333 // Extend forward to the word containing the character to the left of pos.
4334 // Skip ExtendWordSelect if the line is empty or if pos is the first position on the line.
4335 // This ensures that a series of empty lines isn't counted as a single "word".
4336 if (pos
> pdoc
->LineStart(pdoc
->LineFromPosition(pos
)))
4337 pos
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(pos
- 1, -1), 1);
4338 TrimAndSetSelection(pos
, wordSelectAnchorStartPos
);
4340 // Select only the anchored word
4341 if (pos
>= originalAnchorPos
)
4342 TrimAndSetSelection(wordSelectAnchorEndPos
, wordSelectAnchorStartPos
);
4344 TrimAndSetSelection(wordSelectAnchorStartPos
, wordSelectAnchorEndPos
);
4348 void Editor::DwellEnd(bool mouseMoved
) {
4350 ticksToDwell
= dwellDelay
;
4352 ticksToDwell
= SC_TIME_FOREVER
;
4353 if (dwelling
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4355 NotifyDwelling(ptMouseLast
, dwelling
);
4357 if (FineTickerAvailable()) {
4358 FineTickerCancel(tickDwell
);
4359 if (mouseMoved
&& (dwellDelay
< SC_TIME_FOREVER
)) {
4360 //FineTickerStart(tickDwell, dwellDelay, dwellDelay/10);
4365 void Editor::MouseLeave() {
4366 SetHotSpotRange(NULL
);
4367 if (!HaveMouseCapture()) {
4368 ptMouseLast
= Point(-1,-1);
4373 static bool AllowVirtualSpace(int virtualSpaceOptions
, bool rectangular
) {
4374 return (!rectangular
&& ((virtualSpaceOptions
& SCVS_USERACCESSIBLE
) != 0))
4375 || (rectangular
&& ((virtualSpaceOptions
& SCVS_RECTANGULARSELECTION
) != 0));
4378 void Editor::ButtonDownWithModifiers(Point pt
, unsigned int curTime
, int modifiers
) {
4379 SetHoverIndicatorPoint(pt
);
4380 //Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);
4382 const bool ctrl
= (modifiers
& SCI_CTRL
) != 0;
4383 const bool shift
= (modifiers
& SCI_SHIFT
) != 0;
4384 const bool alt
= (modifiers
& SCI_ALT
) != 0;
4385 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false, AllowVirtualSpace(virtualSpaceOptions
, alt
));
4386 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4387 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4388 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4389 inDragDrop
= ddNone
;
4390 sel
.SetMoveExtends(false);
4392 if (NotifyMarginClick(pt
, modifiers
))
4395 NotifyIndicatorClick(true, newPos
.Position(), modifiers
);
4397 bool inSelMargin
= PointInSelMargin(pt
);
4398 // In margin ctrl+(double)click should always select everything
4399 if (ctrl
&& inSelMargin
) {
4401 lastClickTime
= curTime
;
4405 if (shift
&& !inSelMargin
) {
4406 SetSelection(newPos
);
4408 if (((curTime
- lastClickTime
) < Platform::DoubleClickTime()) && Close(pt
, lastClick
, doubleClickCloseThreshold
)) {
4409 //Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);
4410 SetMouseCapture(true);
4411 if (FineTickerAvailable()) {
4412 FineTickerStart(tickScroll
, 100, 10);
4414 if (!ctrl
|| !multipleSelection
|| (selectionType
!= selChar
&& selectionType
!= selWord
))
4415 SetEmptySelection(newPos
.Position());
4416 bool doubleClick
= false;
4417 // Stop mouse button bounce changing selection type
4418 if (!Platform::MouseButtonBounce() || curTime
!= lastClickTime
) {
4420 // Inside margin selection type should be either selSubLine or selWholeLine.
4421 if (selectionType
== selSubLine
) {
4422 // If it is selSubLine, we're inside a *double* click and word wrap is enabled,
4423 // so we switch to selWholeLine in order to select whole line.
4424 selectionType
= selWholeLine
;
4425 } else if (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
) {
4426 // If it is neither, reset selection type to line selection.
4427 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4430 if (selectionType
== selChar
) {
4431 selectionType
= selWord
;
4433 } else if (selectionType
== selWord
) {
4434 // Since we ended up here, we're inside a *triple* click, which should always select
4435 // whole line regardless of word wrap being enabled or not.
4436 selectionType
= selWholeLine
;
4438 selectionType
= selChar
;
4439 originalAnchorPos
= sel
.MainCaret();
4444 if (selectionType
== selWord
) {
4445 int charPos
= originalAnchorPos
;
4446 if (sel
.MainCaret() == originalAnchorPos
) {
4447 charPos
= PositionFromLocation(pt
, false, true);
4448 charPos
= MovePositionOutsideChar(charPos
, -1);
4451 int startWord
, endWord
;
4452 if ((sel
.MainCaret() >= originalAnchorPos
) && !pdoc
->IsLineEndPosition(charPos
)) {
4453 startWord
= pdoc
->ExtendWordSelect(pdoc
->MovePositionOutsideChar(charPos
+ 1, 1), -1);
4454 endWord
= pdoc
->ExtendWordSelect(charPos
, 1);
4456 // Selecting backwards, or anchor beyond last character on line. In these cases,
4457 // we select the word containing the character to the *left* of the anchor.
4458 if (charPos
> pdoc
->LineStart(pdoc
->LineFromPosition(charPos
))) {
4459 startWord
= pdoc
->ExtendWordSelect(charPos
, -1);
4460 endWord
= pdoc
->ExtendWordSelect(startWord
, 1);
4462 // Anchor at start of line; select nothing to begin with.
4463 startWord
= charPos
;
4468 wordSelectAnchorStartPos
= startWord
;
4469 wordSelectAnchorEndPos
= endWord
;
4470 wordSelectInitialCaretPos
= sel
.MainCaret();
4471 WordSelection(wordSelectInitialCaretPos
);
4472 } else if (selectionType
== selSubLine
|| selectionType
== selWholeLine
) {
4473 lineAnchorPos
= newPos
.Position();
4474 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4475 //Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);
4477 SetEmptySelection(sel
.MainCaret());
4479 //Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);
4481 NotifyDoubleClick(pt
, modifiers
);
4482 if (PositionIsHotspot(newCharPos
.Position()))
4483 NotifyHotSpotDoubleClicked(newCharPos
.Position(), modifiers
);
4485 } else { // Single click
4487 sel
.selType
= Selection::selStream
;
4489 // Single click in margin: select whole line or only subline if word wrap is enabled
4490 lineAnchorPos
= newPos
.Position();
4491 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4492 LineSelection(lineAnchorPos
, lineAnchorPos
, selectionType
== selWholeLine
);
4494 // Single shift+click in margin: select from line anchor to clicked line
4495 if (sel
.MainAnchor() > sel
.MainCaret())
4496 lineAnchorPos
= sel
.MainAnchor() - 1;
4498 lineAnchorPos
= sel
.MainAnchor();
4499 // Reset selection type if there is an empty selection.
4500 // This ensures that we don't end up stuck in previous selection mode, which is no longer valid.
4501 // Otherwise, if there's a non empty selection, reset selection type only if it differs from selSubLine and selWholeLine.
4502 // This ensures that we continue selecting in the same selection mode.
4503 if (sel
.Empty() || (selectionType
!= selSubLine
&& selectionType
!= selWholeLine
))
4504 selectionType
= (Wrapping() && (marginOptions
& SC_MARGINOPTION_SUBLINESELECT
)) ? selSubLine
: selWholeLine
;
4505 LineSelection(newPos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4508 SetDragPosition(SelectionPosition(invalidPosition
));
4509 SetMouseCapture(true);
4510 if (FineTickerAvailable()) {
4511 FineTickerStart(tickScroll
, 100, 10);
4514 if (PointIsHotspot(pt
)) {
4515 NotifyHotSpotClicked(newCharPos
.Position(), modifiers
);
4516 hotSpotClickPos
= newCharPos
.Position();
4519 if (PointInSelection(pt
) && !SelectionEmpty())
4520 inDragDrop
= ddInitial
;
4522 inDragDrop
= ddNone
;
4524 SetMouseCapture(true);
4525 if (FineTickerAvailable()) {
4526 FineTickerStart(tickScroll
, 100, 10);
4528 if (inDragDrop
!= ddInitial
) {
4529 SetDragPosition(SelectionPosition(invalidPosition
));
4531 if (ctrl
&& multipleSelection
) {
4532 SelectionRange
range(newPos
);
4533 sel
.TentativeSelection(range
);
4534 InvalidateSelection(range
, true);
4536 InvalidateSelection(SelectionRange(newPos
), true);
4537 if (sel
.Count() > 1)
4539 if ((sel
.Count() > 1) || (sel
.selType
!= Selection::selStream
))
4541 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4542 SetSelection(newPos
, newPos
);
4545 SelectionPosition anchorCurrent
= newPos
;
4547 anchorCurrent
= sel
.IsRectangular() ?
4548 sel
.Rectangular().anchor
: sel
.RangeMain().anchor
;
4549 sel
.selType
= alt
? Selection::selRectangle
: Selection::selStream
;
4550 selectionType
= selChar
;
4551 originalAnchorPos
= sel
.MainCaret();
4552 sel
.Rectangular() = SelectionRange(newPos
, anchorCurrent
);
4553 SetRectangularRange();
4557 lastClickTime
= curTime
;
4559 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4560 ShowCaretAtCurrentPosition();
4563 void Editor::ButtonDown(Point pt
, unsigned int curTime
, bool shift
, bool ctrl
, bool alt
) {
4564 return ButtonDownWithModifiers(pt
, curTime
, ModifierFlags(shift
, ctrl
, alt
));
4567 bool Editor::PositionIsHotspot(int position
) const {
4568 return vs
.styles
[pdoc
->StyleIndexAt(position
)].hotspot
;
4571 bool Editor::PointIsHotspot(Point pt
) {
4572 int pos
= PositionFromLocation(pt
, true, true);
4573 if (pos
== INVALID_POSITION
)
4575 return PositionIsHotspot(pos
);
4578 void Editor::SetHoverIndicatorPosition(int position
) {
4579 int hoverIndicatorPosPrev
= hoverIndicatorPos
;
4580 hoverIndicatorPos
= INVALID_POSITION
;
4581 if (vs
.indicatorsDynamic
== 0)
4583 if (position
!= INVALID_POSITION
) {
4584 for (Decoration
*deco
= pdoc
->decorations
.root
; deco
; deco
= deco
->next
) {
4585 if (vs
.indicators
[deco
->indicator
].IsDynamic()) {
4586 if (pdoc
->decorations
.ValueAt(deco
->indicator
, position
)) {
4587 hoverIndicatorPos
= position
;
4592 if (hoverIndicatorPosPrev
!= hoverIndicatorPos
) {
4597 void Editor::SetHoverIndicatorPoint(Point pt
) {
4598 if (vs
.indicatorsDynamic
== 0) {
4599 SetHoverIndicatorPosition(INVALID_POSITION
);
4601 SetHoverIndicatorPosition(PositionFromLocation(pt
, true, true));
4605 void Editor::SetHotSpotRange(Point
*pt
) {
4607 int pos
= PositionFromLocation(*pt
, false, true);
4609 // If we don't limit this to word characters then the
4610 // range can encompass more than the run range and then
4611 // the underline will not be drawn properly.
4613 hsNew
.start
= pdoc
->ExtendStyleRange(pos
, -1, vs
.hotspotSingleLine
);
4614 hsNew
.end
= pdoc
->ExtendStyleRange(pos
, 1, vs
.hotspotSingleLine
);
4616 // Only invalidate the range if the hotspot range has changed...
4617 if (!(hsNew
== hotspot
)) {
4618 if (hotspot
.Valid()) {
4619 InvalidateRange(hotspot
.start
, hotspot
.end
);
4622 InvalidateRange(hotspot
.start
, hotspot
.end
);
4625 if (hotspot
.Valid()) {
4626 InvalidateRange(hotspot
.start
, hotspot
.end
);
4628 hotspot
= Range(invalidPosition
);
4632 Range
Editor::GetHotSpotRange() const {
4636 void Editor::ButtonMoveWithModifiers(Point pt
, int modifiers
) {
4637 if ((ptMouseLast
.x
!= pt
.x
) || (ptMouseLast
.y
!= pt
.y
)) {
4641 SelectionPosition movePos
= SPositionFromLocation(pt
, false, false,
4642 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4643 movePos
= MovePositionOutsideChar(movePos
, sel
.MainCaret() - movePos
.Position());
4645 if (inDragDrop
== ddInitial
) {
4646 if (DragThreshold(ptMouseLast
, pt
)) {
4647 SetMouseCapture(false);
4648 if (FineTickerAvailable()) {
4649 FineTickerCancel(tickScroll
);
4651 SetDragPosition(movePos
);
4652 CopySelectionRange(&drag
);
4659 PRectangle rcClient
= GetClientRectangle();
4660 Point ptOrigin
= GetVisibleOriginInMain();
4661 rcClient
.Move(0, -ptOrigin
.y
);
4662 if (FineTickerAvailable() && (dwellDelay
< SC_TIME_FOREVER
) && rcClient
.Contains(pt
)) {
4663 FineTickerStart(tickDwell
, dwellDelay
, dwellDelay
/10);
4665 //Platform::DebugPrintf("Move %d %d\n", pt.x, pt.y);
4666 if (HaveMouseCapture()) {
4668 // Slow down autoscrolling/selection
4669 autoScrollTimer
.ticksToWait
-= timer
.tickSize
;
4670 if (autoScrollTimer
.ticksToWait
> 0)
4672 autoScrollTimer
.ticksToWait
= autoScrollDelay
;
4675 if (posDrag
.IsValid()) {
4676 SetDragPosition(movePos
);
4678 if (selectionType
== selChar
) {
4679 if (sel
.selType
== Selection::selStream
&& (modifiers
& SCI_ALT
) && mouseSelectionRectangularSwitch
) {
4680 sel
.selType
= Selection::selRectangle
;
4682 if (sel
.IsRectangular()) {
4683 sel
.Rectangular() = SelectionRange(movePos
, sel
.Rectangular().anchor
);
4684 SetSelection(movePos
, sel
.RangeMain().anchor
);
4685 } else if (sel
.Count() > 1) {
4686 InvalidateSelection(sel
.RangeMain(), false);
4687 SelectionRange
range(movePos
, sel
.RangeMain().anchor
);
4688 sel
.TentativeSelection(range
);
4689 InvalidateSelection(range
, true);
4691 SetSelection(movePos
, sel
.RangeMain().anchor
);
4693 } else if (selectionType
== selWord
) {
4694 // Continue selecting by word
4695 if (movePos
.Position() == wordSelectInitialCaretPos
) { // Didn't move
4696 // No need to do anything. Previously this case was lumped
4697 // in with "Moved forward", but that can be harmful in this
4698 // case: a handler for the NotifyDoubleClick re-adjusts
4699 // the selection for a fancier definition of "word" (for
4700 // example, in Perl it is useful to include the leading
4701 // '$', '%' or '@' on variables for word selection). In this
4702 // the ButtonMove() called via Tick() for auto-scrolling
4703 // could result in the fancier word selection adjustment
4706 wordSelectInitialCaretPos
= -1;
4707 WordSelection(movePos
.Position());
4710 // Continue selecting by line
4711 LineSelection(movePos
.Position(), lineAnchorPos
, selectionType
== selWholeLine
);
4716 int lineMove
= DisplayFromPosition(movePos
.Position());
4717 if (pt
.y
> rcClient
.bottom
) {
4718 ScrollTo(lineMove
- LinesOnScreen() + 1);
4720 } else if (pt
.y
< rcClient
.top
) {
4724 EnsureCaretVisible(false, false, true);
4726 if (hotspot
.Valid() && !PointIsHotspot(pt
))
4727 SetHotSpotRange(NULL
);
4729 if (hotSpotClickPos
!= INVALID_POSITION
&& PositionFromLocation(pt
,true,true) != hotSpotClickPos
) {
4730 if (inDragDrop
== ddNone
) {
4731 DisplayCursor(Window::cursorText
);
4733 hotSpotClickPos
= INVALID_POSITION
;
4737 if (vs
.fixedColumnWidth
> 0) { // There is a margin
4738 if (PointInSelMargin(pt
)) {
4739 DisplayCursor(GetMarginCursor(pt
));
4740 SetHotSpotRange(NULL
);
4741 return; // No need to test for selection
4744 // Display regular (drag) cursor over selection
4745 if (PointInSelection(pt
) && !SelectionEmpty()) {
4746 DisplayCursor(Window::cursorArrow
);
4748 SetHoverIndicatorPoint(pt
);
4749 if (PointIsHotspot(pt
)) {
4750 DisplayCursor(Window::cursorHand
);
4751 SetHotSpotRange(&pt
);
4753 if (hoverIndicatorPos
!= invalidPosition
)
4754 DisplayCursor(Window::cursorHand
);
4756 DisplayCursor(Window::cursorText
);
4757 SetHotSpotRange(NULL
);
4763 void Editor::ButtonMove(Point pt
) {
4764 ButtonMoveWithModifiers(pt
, 0);
4767 void Editor::ButtonUp(Point pt
, unsigned int curTime
, bool ctrl
) {
4768 //Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop);
4769 SelectionPosition newPos
= SPositionFromLocation(pt
, false, false,
4770 AllowVirtualSpace(virtualSpaceOptions
, sel
.IsRectangular()));
4771 if (hoverIndicatorPos
!= INVALID_POSITION
)
4772 InvalidateRange(newPos
.Position(), newPos
.Position() + 1);
4773 newPos
= MovePositionOutsideChar(newPos
, sel
.MainCaret() - newPos
.Position());
4774 if (inDragDrop
== ddInitial
) {
4775 inDragDrop
= ddNone
;
4776 SetEmptySelection(newPos
);
4777 selectionType
= selChar
;
4778 originalAnchorPos
= sel
.MainCaret();
4780 if (hotSpotClickPos
!= INVALID_POSITION
&& PointIsHotspot(pt
)) {
4781 hotSpotClickPos
= INVALID_POSITION
;
4782 SelectionPosition newCharPos
= SPositionFromLocation(pt
, false, true, false);
4783 newCharPos
= MovePositionOutsideChar(newCharPos
, -1);
4784 NotifyHotSpotReleaseClick(newCharPos
.Position(), ctrl
? SCI_CTRL
: 0);
4786 if (HaveMouseCapture()) {
4787 if (PointInSelMargin(pt
)) {
4788 DisplayCursor(GetMarginCursor(pt
));
4790 DisplayCursor(Window::cursorText
);
4791 SetHotSpotRange(NULL
);
4794 SetMouseCapture(false);
4795 if (FineTickerAvailable()) {
4796 FineTickerCancel(tickScroll
);
4798 NotifyIndicatorClick(false, newPos
.Position(), 0);
4799 if (inDragDrop
== ddDragging
) {
4800 SelectionPosition selStart
= SelectionStart();
4801 SelectionPosition selEnd
= SelectionEnd();
4802 if (selStart
< selEnd
) {
4803 if (drag
.Length()) {
4804 const int length
= static_cast<int>(drag
.Length());
4806 const int lengthInserted
= pdoc
->InsertString(
4807 newPos
.Position(), drag
.Data(), length
);
4808 if (lengthInserted
> 0) {
4809 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4811 } else if (newPos
< selStart
) {
4812 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4813 const int lengthInserted
= pdoc
->InsertString(
4814 newPos
.Position(), drag
.Data(), length
);
4815 if (lengthInserted
> 0) {
4816 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4818 } else if (newPos
> selEnd
) {
4819 pdoc
->DeleteChars(selStart
.Position(), static_cast<int>(drag
.Length()));
4820 newPos
.Add(-static_cast<int>(drag
.Length()));
4821 const int lengthInserted
= pdoc
->InsertString(
4822 newPos
.Position(), drag
.Data(), length
);
4823 if (lengthInserted
> 0) {
4824 SetSelection(newPos
.Position(), newPos
.Position() + lengthInserted
);
4827 SetEmptySelection(newPos
.Position());
4831 selectionType
= selChar
;
4834 if (selectionType
== selChar
) {
4835 if (sel
.Count() > 1) {
4837 SelectionRange(newPos
, sel
.Range(sel
.Count() - 1).anchor
);
4838 InvalidateWholeSelection();
4840 SetSelection(newPos
, sel
.RangeMain().anchor
);
4843 sel
.CommitTentative();
4845 SetRectangularRange();
4846 lastClickTime
= curTime
;
4848 lastXChosen
= static_cast<int>(pt
.x
) + xOffset
;
4849 if (sel
.selType
== Selection::selStream
) {
4852 inDragDrop
= ddNone
;
4853 EnsureCaretVisible(false);
4857 // Called frequently to perform background UI including
4858 // caret blinking and automatic scrolling.
4859 void Editor::Tick() {
4860 if (HaveMouseCapture()) {
4862 ButtonMove(ptMouseLast
);
4864 if (caret
.period
> 0) {
4865 timer
.ticksToWait
-= timer
.tickSize
;
4866 if (timer
.ticksToWait
<= 0) {
4867 caret
.on
= !caret
.on
;
4868 timer
.ticksToWait
= caret
.period
;
4874 if (horizontalScrollBarVisible
&& trackLineWidth
&& (view
.lineWidthMaxSeen
> scrollWidth
)) {
4875 scrollWidth
= view
.lineWidthMaxSeen
;
4878 if ((dwellDelay
< SC_TIME_FOREVER
) &&
4879 (ticksToDwell
> 0) &&
4880 (!HaveMouseCapture()) &&
4881 (ptMouseLast
.y
>= 0)) {
4882 ticksToDwell
-= timer
.tickSize
;
4883 if (ticksToDwell
<= 0) {
4885 NotifyDwelling(ptMouseLast
, dwelling
);
4890 bool Editor::Idle() {
4891 bool needWrap
= Wrapping() && wrapPending
.NeedsWrap();
4894 // Wrap lines during idle.
4897 needWrap
= wrapPending
.NeedsWrap();
4898 } else if (needIdleStyling
) {
4902 // Add more idle things to do here, but make sure idleDone is
4903 // set correctly before the function returns. returning
4904 // false will stop calling this idle function until SetIdle() is
4907 const bool idleDone
= !needWrap
&& !needIdleStyling
; // && thatDone && theOtherThingDone...
4912 void Editor::SetTicking(bool) {
4913 // SetTicking is deprecated. In the past it was pure virtual and was overridden in each
4914 // derived platform class but fine grained timers should now be implemented.
4915 // Either way, execution should not arrive here so assert failure.
4919 void Editor::TickFor(TickReason reason
) {
4922 caret
.on
= !caret
.on
;
4929 ButtonMove(ptMouseLast
);
4933 FineTickerCancel(tickWiden
);
4936 if ((!HaveMouseCapture()) &&
4937 (ptMouseLast
.y
>= 0)) {
4939 NotifyDwelling(ptMouseLast
, dwelling
);
4941 FineTickerCancel(tickDwell
);
4944 // tickPlatform handled by subclass
4949 bool Editor::FineTickerAvailable() {
4953 // FineTickerStart is be overridden by subclasses that support fine ticking so
4954 // this method should never be called.
4955 bool Editor::FineTickerRunning(TickReason
) {
4960 // FineTickerStart is be overridden by subclasses that support fine ticking so
4961 // this method should never be called.
4962 void Editor::FineTickerStart(TickReason
, int, int) {
4966 // FineTickerCancel is be overridden by subclasses that support fine ticking so
4967 // this method should never be called.
4968 void Editor::FineTickerCancel(TickReason
) {
4972 void Editor::SetFocusState(bool focusState
) {
4973 hasFocus
= focusState
;
4974 NotifyFocus(hasFocus
);
4978 ShowCaretAtCurrentPosition();
4981 int Editor::PositionAfterArea(PRectangle rcArea
) const {
4982 // The start of the document line after the display line after the area
4983 // This often means that the line after a modification is restyled which helps
4984 // detect multiline comment additions and heals single line comments
4985 int lineAfter
= TopLineOfMain() + static_cast<int>(rcArea
.bottom
- 1) / vs
.lineHeight
+ 1;
4986 if (lineAfter
< cs
.LinesDisplayed())
4987 return pdoc
->LineStart(cs
.DocFromDisplay(lineAfter
) + 1);
4989 return pdoc
->Length();
4992 // Style to a position within the view. If this causes a change at end of last line then
4993 // affects later lines so style all the viewed text.
4994 void Editor::StyleToPositionInView(Position pos
) {
4995 int endWindow
= PositionAfterArea(GetClientDrawingRectangle());
4996 if (pos
> endWindow
)
4998 const int styleAtEnd
= pdoc
->StyleIndexAt(pos
-1);
4999 pdoc
->EnsureStyledTo(pos
);
5000 if ((endWindow
> pos
) && (styleAtEnd
!= pdoc
->StyleIndexAt(pos
-1))) {
5001 // Style at end of line changed so is multi-line change like starting a comment
5002 // so require rest of window to be styled.
5003 DiscardOverdraw(); // Prepared bitmaps may be invalid
5004 // DiscardOverdraw may have truncated client drawing area so recalculate endWindow
5005 endWindow
= PositionAfterArea(GetClientDrawingRectangle());
5006 pdoc
->EnsureStyledTo(endWindow
);
5010 int Editor::PositionAfterMaxStyling(int posMax
, bool scrolling
) const {
5011 if ((idleStyling
== SC_IDLESTYLING_NONE
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5012 // Both states do not limit styling
5016 // Try to keep time taken by styling reasonable so interaction remains smooth.
5017 // When scrolling, allow less time to ensure responsive
5018 const double secondsAllowed
= scrolling
? 0.005 : 0.02;
5020 const int linesToStyle
= Platform::Clamp(static_cast<int>(secondsAllowed
/ pdoc
->durationStyleOneLine
),
5022 const int stylingMaxLine
= std::min(
5023 static_cast<int>(pdoc
->LineFromPosition(pdoc
->GetEndStyled()) + linesToStyle
),
5024 pdoc
->LinesTotal());
5025 return std::min(static_cast<int>(pdoc
->LineStart(stylingMaxLine
)), posMax
);
5028 void Editor::StartIdleStyling(bool truncatedLastStyling
) {
5029 if ((idleStyling
== SC_IDLESTYLING_ALL
) || (idleStyling
== SC_IDLESTYLING_AFTERVISIBLE
)) {
5030 if (pdoc
->GetEndStyled() < pdoc
->Length()) {
5031 // Style remainder of document in idle time
5032 needIdleStyling
= true;
5034 } else if (truncatedLastStyling
) {
5035 needIdleStyling
= true;
5038 if (needIdleStyling
) {
5043 // Style for an area but bound the amount of styling to remain responsive
5044 void Editor::StyleAreaBounded(PRectangle rcArea
, bool scrolling
) {
5045 const int posAfterArea
= PositionAfterArea(rcArea
);
5046 const int posAfterMax
= PositionAfterMaxStyling(posAfterArea
, scrolling
);
5047 if (posAfterMax
< posAfterArea
) {
5048 // Idle styling may be performed before current visible area
5049 // Style a bit now then style further in idle time
5050 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5052 // Can style all wanted now.
5053 StyleToPositionInView(posAfterArea
);
5055 StartIdleStyling(posAfterMax
< posAfterArea
);
5058 void Editor::IdleStyling() {
5059 const int posAfterArea
= PositionAfterArea(GetClientRectangle());
5060 const int endGoal
= (idleStyling
>= SC_IDLESTYLING_AFTERVISIBLE
) ?
5061 pdoc
->Length() : posAfterArea
;
5062 const int posAfterMax
= PositionAfterMaxStyling(endGoal
, false);
5063 pdoc
->StyleToAdjustingLineDuration(posAfterMax
);
5064 if (pdoc
->GetEndStyled() >= endGoal
) {
5065 needIdleStyling
= false;
5069 void Editor::IdleWork() {
5070 // Style the line after the modification as this allows modifications that change just the
5071 // line of the modification to heal instead of propagating to the rest of the window.
5072 if (workNeeded
.items
& WorkNeeded::workStyle
) {
5073 StyleToPositionInView(pdoc
->LineStart(pdoc
->LineFromPosition(workNeeded
.upTo
) + 2));
5079 void Editor::QueueIdleWork(WorkNeeded::workItems items
, int upTo
) {
5080 workNeeded
.Need(items
, upTo
);
5083 bool Editor::PaintContains(PRectangle rc
) {
5087 return rcPaint
.Contains(rc
);
5091 bool Editor::PaintContainsMargin() {
5092 if (wMargin
.GetID()) {
5093 // With separate margin view, paint of text view
5094 // never contains margin.
5097 PRectangle rcSelMargin
= GetClientRectangle();
5098 rcSelMargin
.right
= static_cast<XYPOSITION
>(vs
.textStart
);
5099 return PaintContains(rcSelMargin
);
5102 void Editor::CheckForChangeOutsidePaint(Range r
) {
5103 if (paintState
== painting
&& !paintingAllText
) {
5104 //Platform::DebugPrintf("Checking range in paint %d-%d\n", r.start, r.end);
5108 PRectangle rcRange
= RectangleFromRange(r
, 0);
5109 PRectangle rcText
= GetTextRectangle();
5110 if (rcRange
.top
< rcText
.top
) {
5111 rcRange
.top
= rcText
.top
;
5113 if (rcRange
.bottom
> rcText
.bottom
) {
5114 rcRange
.bottom
= rcText
.bottom
;
5117 if (!PaintContains(rcRange
)) {
5119 paintAbandonedByStyling
= true;
5124 void Editor::SetBraceHighlight(Position pos0
, Position pos1
, int matchStyle
) {
5125 if ((pos0
!= braces
[0]) || (pos1
!= braces
[1]) || (matchStyle
!= bracesMatchStyle
)) {
5126 if ((braces
[0] != pos0
) || (matchStyle
!= bracesMatchStyle
)) {
5127 CheckForChangeOutsidePaint(Range(braces
[0]));
5128 CheckForChangeOutsidePaint(Range(pos0
));
5131 if ((braces
[1] != pos1
) || (matchStyle
!= bracesMatchStyle
)) {
5132 CheckForChangeOutsidePaint(Range(braces
[1]));
5133 CheckForChangeOutsidePaint(Range(pos1
));
5136 bracesMatchStyle
= matchStyle
;
5137 if (paintState
== notPainting
) {
5143 void Editor::SetAnnotationHeights(int start
, int end
) {
5144 if (vs
.annotationVisible
) {
5146 bool changedHeight
= false;
5147 for (int line
=start
; line
<end
&& line
<pdoc
->LinesTotal(); line
++) {
5148 int linesWrapped
= 1;
5150 AutoSurface
surface(this);
5151 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5152 if (surface
&& ll
) {
5153 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5154 linesWrapped
= ll
->lines
;
5157 if (cs
.SetHeight(line
, pdoc
->AnnotationLines(line
) + linesWrapped
))
5158 changedHeight
= true;
5160 if (changedHeight
) {
5166 void Editor::SetDocPointer(Document
*document
) {
5167 //Platform::DebugPrintf("** %x setdoc to %x\n", pdoc, document);
5168 pdoc
->RemoveWatcher(this, 0);
5170 if (document
== NULL
) {
5171 pdoc
= new Document();
5177 // Ensure all positions within document
5182 braces
[0] = invalidPosition
;
5183 braces
[1] = invalidPosition
;
5185 vs
.ReleaseAllExtendedStyles();
5187 SetRepresentations();
5189 // Reset the contraction state to fully shown.
5191 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
5192 SetAnnotationHeights(0, pdoc
->LinesTotal());
5193 view
.llc
.Deallocate();
5196 hotspot
= Range(invalidPosition
);
5197 hoverIndicatorPos
= invalidPosition
;
5199 view
.ClearAllTabstops();
5201 pdoc
->AddWatcher(this, 0);
5206 void Editor::SetAnnotationVisible(int visible
) {
5207 if (vs
.annotationVisible
!= visible
) {
5208 bool changedFromOrToHidden
= ((vs
.annotationVisible
!= 0) != (visible
!= 0));
5209 vs
.annotationVisible
= visible
;
5210 if (changedFromOrToHidden
) {
5211 int dir
= vs
.annotationVisible
? 1 : -1;
5212 for (int line
=0; line
<pdoc
->LinesTotal(); line
++) {
5213 int annotationLines
= pdoc
->AnnotationLines(line
);
5214 if (annotationLines
> 0) {
5215 cs
.SetHeight(line
, cs
.GetHeight(line
) + annotationLines
* dir
);
5224 * Recursively expand a fold, making lines visible except where they have an unexpanded parent.
5226 int Editor::ExpandLine(int line
) {
5227 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5229 while (line
<= lineMaxSubord
) {
5230 cs
.SetVisible(line
, line
, true);
5231 int level
= pdoc
->GetLevel(line
);
5232 if (level
& SC_FOLDLEVELHEADERFLAG
) {
5233 if (cs
.GetExpanded(line
)) {
5234 line
= ExpandLine(line
);
5236 line
= pdoc
->GetLastChild(line
);
5241 return lineMaxSubord
;
5244 void Editor::SetFoldExpanded(int lineDoc
, bool expanded
) {
5245 if (cs
.SetExpanded(lineDoc
, expanded
)) {
5250 void Editor::FoldLine(int line
, int action
) {
5252 if (action
== SC_FOLDACTION_TOGGLE
) {
5253 if ((pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
) == 0) {
5254 line
= pdoc
->GetFoldParent(line
);
5258 action
= (cs
.GetExpanded(line
)) ? SC_FOLDACTION_CONTRACT
: SC_FOLDACTION_EXPAND
;
5261 if (action
== SC_FOLDACTION_CONTRACT
) {
5262 int lineMaxSubord
= pdoc
->GetLastChild(line
);
5263 if (lineMaxSubord
> line
) {
5264 cs
.SetExpanded(line
, 0);
5265 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5267 int lineCurrent
= pdoc
->LineFromPosition(sel
.MainCaret());
5268 if (lineCurrent
> line
&& lineCurrent
<= lineMaxSubord
) {
5269 // This does not re-expand the fold
5270 EnsureCaretVisible();
5275 if (!(cs
.GetVisible(line
))) {
5276 EnsureLineVisible(line
, false);
5279 cs
.SetExpanded(line
, 1);
5288 void Editor::FoldExpand(int line
, int action
, int level
) {
5289 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5290 if (action
== SC_FOLDACTION_TOGGLE
) {
5291 expanding
= !cs
.GetExpanded(line
);
5293 SetFoldExpanded(line
, expanding
);
5294 if (expanding
&& (cs
.HiddenLines() == 0))
5297 int lineMaxSubord
= pdoc
->GetLastChild(line
, LevelNumber(level
));
5299 cs
.SetVisible(line
, lineMaxSubord
, expanding
);
5300 while (line
<= lineMaxSubord
) {
5301 int levelLine
= pdoc
->GetLevel(line
);
5302 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5303 SetFoldExpanded(line
, expanding
);
5311 int Editor::ContractedFoldNext(int lineStart
) const {
5312 for (int line
= lineStart
; line
<pdoc
->LinesTotal();) {
5313 if (!cs
.GetExpanded(line
) && (pdoc
->GetLevel(line
) & SC_FOLDLEVELHEADERFLAG
))
5315 line
= cs
.ContractedNext(line
+1);
5324 * Recurse up from this line to find any folds that prevent this line from being visible
5325 * and unfold them all.
5327 void Editor::EnsureLineVisible(int lineDoc
, bool enforcePolicy
) {
5329 // In case in need of wrapping to ensure DisplayFromDoc works.
5330 if (lineDoc
>= wrapPending
.start
)
5333 if (!cs
.GetVisible(lineDoc
)) {
5334 // Back up to find a non-blank line
5335 int lookLine
= lineDoc
;
5336 int lookLineLevel
= pdoc
->GetLevel(lookLine
);
5337 while ((lookLine
> 0) && (lookLineLevel
& SC_FOLDLEVELWHITEFLAG
)) {
5338 lookLineLevel
= pdoc
->GetLevel(--lookLine
);
5340 int lineParent
= pdoc
->GetFoldParent(lookLine
);
5341 if (lineParent
< 0) {
5342 // Backed up to a top level line, so try to find parent of initial line
5343 lineParent
= pdoc
->GetFoldParent(lineDoc
);
5345 if (lineParent
>= 0) {
5346 if (lineDoc
!= lineParent
)
5347 EnsureLineVisible(lineParent
, enforcePolicy
);
5348 if (!cs
.GetExpanded(lineParent
)) {
5349 cs
.SetExpanded(lineParent
, 1);
5350 ExpandLine(lineParent
);
5356 if (enforcePolicy
) {
5357 int lineDisplay
= cs
.DisplayFromDoc(lineDoc
);
5358 if (visiblePolicy
& VISIBLE_SLOP
) {
5359 if ((topLine
> lineDisplay
) || ((visiblePolicy
& VISIBLE_STRICT
) && (topLine
+ visibleSlop
> lineDisplay
))) {
5360 SetTopLine(Platform::Clamp(lineDisplay
- visibleSlop
, 0, MaxScrollPos()));
5361 SetVerticalScrollPos();
5363 } else if ((lineDisplay
> topLine
+ LinesOnScreen() - 1) ||
5364 ((visiblePolicy
& VISIBLE_STRICT
) && (lineDisplay
> topLine
+ LinesOnScreen() - 1 - visibleSlop
))) {
5365 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() + 1 + visibleSlop
, 0, MaxScrollPos()));
5366 SetVerticalScrollPos();
5370 if ((topLine
> lineDisplay
) || (lineDisplay
> topLine
+ LinesOnScreen() - 1) || (visiblePolicy
& VISIBLE_STRICT
)) {
5371 SetTopLine(Platform::Clamp(lineDisplay
- LinesOnScreen() / 2 + 1, 0, MaxScrollPos()));
5372 SetVerticalScrollPos();
5379 void Editor::FoldAll(int action
) {
5380 pdoc
->EnsureStyledTo(pdoc
->Length());
5381 int maxLine
= pdoc
->LinesTotal();
5382 bool expanding
= action
== SC_FOLDACTION_EXPAND
;
5383 if (action
== SC_FOLDACTION_TOGGLE
) {
5384 // Discover current state
5385 for (int lineSeek
= 0; lineSeek
< maxLine
; lineSeek
++) {
5386 if (pdoc
->GetLevel(lineSeek
) & SC_FOLDLEVELHEADERFLAG
) {
5387 expanding
= !cs
.GetExpanded(lineSeek
);
5393 cs
.SetVisible(0, maxLine
-1, true);
5394 for (int line
= 0; line
< maxLine
; line
++) {
5395 int levelLine
= pdoc
->GetLevel(line
);
5396 if (levelLine
& SC_FOLDLEVELHEADERFLAG
) {
5397 SetFoldExpanded(line
, true);
5401 for (int line
= 0; line
< maxLine
; line
++) {
5402 int level
= pdoc
->GetLevel(line
);
5403 if ((level
& SC_FOLDLEVELHEADERFLAG
) &&
5404 (SC_FOLDLEVELBASE
== LevelNumber(level
))) {
5405 SetFoldExpanded(line
, false);
5406 int lineMaxSubord
= pdoc
->GetLastChild(line
, -1);
5407 if (lineMaxSubord
> line
) {
5408 cs
.SetVisible(line
+ 1, lineMaxSubord
, false);
5417 void Editor::FoldChanged(int line
, int levelNow
, int levelPrev
) {
5418 if (levelNow
& SC_FOLDLEVELHEADERFLAG
) {
5419 if (!(levelPrev
& SC_FOLDLEVELHEADERFLAG
)) {
5420 // Adding a fold point.
5421 if (cs
.SetExpanded(line
, true)) {
5424 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5426 } else if (levelPrev
& SC_FOLDLEVELHEADERFLAG
) {
5427 const int prevLine
= line
- 1;
5428 const int prevLineLevel
= pdoc
->GetLevel(prevLine
);
5430 // Combining two blocks where the first block is collapsed (e.g. by deleting the line(s) which separate(s) the two blocks)
5431 if ((LevelNumber(prevLineLevel
) == LevelNumber(levelNow
)) && !cs
.GetVisible(prevLine
))
5432 FoldLine(pdoc
->GetFoldParent(prevLine
), SC_FOLDACTION_EXPAND
);
5434 if (!cs
.GetExpanded(line
)) {
5435 // Removing the fold from one that has been contracted so should expand
5436 // otherwise lines are left invisible with no way to make them visible
5437 if (cs
.SetExpanded(line
, true)) {
5440 // Combining two blocks where the second one is collapsed (e.g. by adding characters in the line which separates the two blocks)
5441 FoldExpand(line
, SC_FOLDACTION_EXPAND
, levelPrev
);
5444 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) &&
5445 (LevelNumber(levelPrev
) > LevelNumber(levelNow
))) {
5446 if (cs
.HiddenLines()) {
5447 // See if should still be hidden
5448 int parentLine
= pdoc
->GetFoldParent(line
);
5449 if ((parentLine
< 0) || (cs
.GetExpanded(parentLine
) && cs
.GetVisible(parentLine
))) {
5450 cs
.SetVisible(line
, line
, true);
5457 // Combining two blocks where the first one is collapsed (e.g. by adding characters in the line which separates the two blocks)
5458 if (!(levelNow
& SC_FOLDLEVELWHITEFLAG
) && (LevelNumber(levelPrev
) < LevelNumber(levelNow
))) {
5459 if (cs
.HiddenLines()) {
5460 const int parentLine
= pdoc
->GetFoldParent(line
);
5461 if (!cs
.GetExpanded(parentLine
) && cs
.GetExpanded(line
))
5462 FoldLine(parentLine
, SC_FOLDACTION_EXPAND
);
5467 void Editor::NeedShown(int pos
, int len
) {
5468 if (foldAutomatic
& SC_AUTOMATICFOLD_SHOW
) {
5469 int lineStart
= pdoc
->LineFromPosition(pos
);
5470 int lineEnd
= pdoc
->LineFromPosition(pos
+len
);
5471 for (int line
= lineStart
; line
<= lineEnd
; line
++) {
5472 EnsureLineVisible(line
, false);
5475 NotifyNeedShown(pos
, len
);
5479 int Editor::GetTag(char *tagValue
, int tagNumber
) {
5480 const char *text
= 0;
5482 if ((tagNumber
>= 1) && (tagNumber
<= 9)) {
5483 char name
[3] = "\\?";
5484 name
[1] = static_cast<char>(tagNumber
+ '0');
5486 text
= pdoc
->SubstituteByPosition(name
, &length
);
5490 memcpy(tagValue
, text
, length
+ 1);
5497 int Editor::ReplaceTarget(bool replacePatterns
, const char *text
, int length
) {
5500 length
= istrlen(text
);
5501 if (replacePatterns
) {
5502 text
= pdoc
->SubstituteByPosition(text
, &length
);
5507 if (targetStart
!= targetEnd
)
5508 pdoc
->DeleteChars(targetStart
, targetEnd
- targetStart
);
5509 targetEnd
= targetStart
;
5510 const int lengthInserted
= pdoc
->InsertString(targetStart
, text
, length
);
5511 targetEnd
= targetStart
+ lengthInserted
;
5515 bool Editor::IsUnicodeMode() const {
5516 return pdoc
&& (SC_CP_UTF8
== pdoc
->dbcsCodePage
);
5519 int Editor::CodePage() const {
5521 return pdoc
->dbcsCodePage
;
5526 int Editor::WrapCount(int line
) {
5527 AutoSurface
surface(this);
5528 AutoLineLayout
ll(view
.llc
, view
.RetrieveLineLayout(line
, *this));
5530 if (surface
&& ll
) {
5531 view
.LayoutLine(*this, line
, surface
, vs
, ll
, wrapWidth
);
5538 void Editor::AddStyledText(char *buffer
, int appendLength
) {
5539 // The buffer consists of alternating character bytes and style bytes
5540 int textLength
= appendLength
/ 2;
5541 std::string
text(textLength
, '\0');
5543 for (i
= 0; i
< textLength
; i
++) {
5544 text
[i
] = buffer
[i
*2];
5546 const int lengthInserted
= pdoc
->InsertString(CurrentPosition(), text
.c_str(), textLength
);
5547 for (i
= 0; i
< textLength
; i
++) {
5548 text
[i
] = buffer
[i
*2+1];
5550 pdoc
->StartStyling(CurrentPosition(), static_cast<unsigned char>(0xff));
5551 pdoc
->SetStyles(textLength
, text
.c_str());
5552 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5555 static bool ValidMargin(uptr_t wParam
) {
5556 return wParam
<= SC_MAX_MARGIN
;
5559 static char *CharPtrFromSPtr(sptr_t lParam
) {
5560 return reinterpret_cast<char *>(lParam
);
5563 void Editor::StyleSetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5564 vs
.EnsureStyle(wParam
);
5566 case SCI_STYLESETFORE
:
5567 vs
.styles
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
5569 case SCI_STYLESETBACK
:
5570 vs
.styles
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
5572 case SCI_STYLESETBOLD
:
5573 vs
.styles
[wParam
].weight
= lParam
!= 0 ? SC_WEIGHT_BOLD
: SC_WEIGHT_NORMAL
;
5575 case SCI_STYLESETWEIGHT
:
5576 vs
.styles
[wParam
].weight
= static_cast<int>(lParam
);
5578 case SCI_STYLESETITALIC
:
5579 vs
.styles
[wParam
].italic
= lParam
!= 0;
5581 case SCI_STYLESETEOLFILLED
:
5582 vs
.styles
[wParam
].eolFilled
= lParam
!= 0;
5584 case SCI_STYLESETSIZE
:
5585 vs
.styles
[wParam
].size
= static_cast<int>(lParam
* SC_FONT_SIZE_MULTIPLIER
);
5587 case SCI_STYLESETSIZEFRACTIONAL
:
5588 vs
.styles
[wParam
].size
= static_cast<int>(lParam
);
5590 case SCI_STYLESETFONT
:
5592 vs
.SetStyleFontName(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5595 case SCI_STYLESETUNDERLINE
:
5596 vs
.styles
[wParam
].underline
= lParam
!= 0;
5598 case SCI_STYLESETCASE
:
5599 vs
.styles
[wParam
].caseForce
= static_cast<Style::ecaseForced
>(lParam
);
5601 case SCI_STYLESETCHARACTERSET
:
5602 vs
.styles
[wParam
].characterSet
= static_cast<int>(lParam
);
5603 pdoc
->SetCaseFolder(NULL
);
5605 case SCI_STYLESETVISIBLE
:
5606 vs
.styles
[wParam
].visible
= lParam
!= 0;
5608 case SCI_STYLESETCHANGEABLE
:
5609 vs
.styles
[wParam
].changeable
= lParam
!= 0;
5611 case SCI_STYLESETHOTSPOT
:
5612 vs
.styles
[wParam
].hotspot
= lParam
!= 0;
5615 InvalidateStyleRedraw();
5618 sptr_t
Editor::StyleGetMessage(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5619 vs
.EnsureStyle(wParam
);
5621 case SCI_STYLEGETFORE
:
5622 return vs
.styles
[wParam
].fore
.AsLong();
5623 case SCI_STYLEGETBACK
:
5624 return vs
.styles
[wParam
].back
.AsLong();
5625 case SCI_STYLEGETBOLD
:
5626 return vs
.styles
[wParam
].weight
> SC_WEIGHT_NORMAL
;
5627 case SCI_STYLEGETWEIGHT
:
5628 return vs
.styles
[wParam
].weight
;
5629 case SCI_STYLEGETITALIC
:
5630 return vs
.styles
[wParam
].italic
? 1 : 0;
5631 case SCI_STYLEGETEOLFILLED
:
5632 return vs
.styles
[wParam
].eolFilled
? 1 : 0;
5633 case SCI_STYLEGETSIZE
:
5634 return vs
.styles
[wParam
].size
/ SC_FONT_SIZE_MULTIPLIER
;
5635 case SCI_STYLEGETSIZEFRACTIONAL
:
5636 return vs
.styles
[wParam
].size
;
5637 case SCI_STYLEGETFONT
:
5638 return StringResult(lParam
, vs
.styles
[wParam
].fontName
);
5639 case SCI_STYLEGETUNDERLINE
:
5640 return vs
.styles
[wParam
].underline
? 1 : 0;
5641 case SCI_STYLEGETCASE
:
5642 return static_cast<int>(vs
.styles
[wParam
].caseForce
);
5643 case SCI_STYLEGETCHARACTERSET
:
5644 return vs
.styles
[wParam
].characterSet
;
5645 case SCI_STYLEGETVISIBLE
:
5646 return vs
.styles
[wParam
].visible
? 1 : 0;
5647 case SCI_STYLEGETCHANGEABLE
:
5648 return vs
.styles
[wParam
].changeable
? 1 : 0;
5649 case SCI_STYLEGETHOTSPOT
:
5650 return vs
.styles
[wParam
].hotspot
? 1 : 0;
5655 sptr_t
Editor::StringResult(sptr_t lParam
, const char *val
) {
5656 const size_t len
= val
? strlen(val
) : 0;
5658 char *ptr
= CharPtrFromSPtr(lParam
);
5660 memcpy(ptr
, val
, len
+1);
5664 return len
; // Not including NUL
5667 sptr_t
Editor::BytesResult(sptr_t lParam
, const unsigned char *val
, size_t len
) {
5668 // No NUL termination: len is number of valid/displayed bytes
5669 if ((lParam
) && (len
> 0)) {
5670 char *ptr
= CharPtrFromSPtr(lParam
);
5672 memcpy(ptr
, val
, len
);
5676 return val
? len
: 0;
5679 sptr_t
Editor::WndProc(unsigned int iMessage
, uptr_t wParam
, sptr_t lParam
) {
5680 //Platform::DebugPrintf("S start wnd proc %d %d %d\n",iMessage, wParam, lParam);
5682 // Optional macro recording hook
5684 NotifyMacroRecord(iMessage
, wParam
, lParam
);
5690 return pdoc
->Length() + 1;
5693 char *ptr
= CharPtrFromSPtr(lParam
);
5694 unsigned int iChar
= 0;
5695 for (; iChar
< wParam
- 1; iChar
++)
5696 ptr
[iChar
] = pdoc
->CharAt(iChar
);
5705 pdoc
->DeleteChars(0, pdoc
->Length());
5706 SetEmptySelection(0);
5707 const char *text
= CharPtrFromSPtr(lParam
);
5708 pdoc
->InsertString(0, text
, istrlen(text
));
5712 case SCI_GETTEXTLENGTH
:
5713 return pdoc
->Length();
5724 case SCI_COPYALLOWLINE
:
5728 case SCI_VERTICALCENTRECARET
:
5729 VerticalCentreCaret();
5732 case SCI_MOVESELECTEDLINESUP
:
5733 MoveSelectedLinesUp();
5736 case SCI_MOVESELECTEDLINESDOWN
:
5737 MoveSelectedLinesDown();
5741 CopyRangeToClipboard(static_cast<int>(wParam
), static_cast<int>(lParam
));
5745 CopyText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
5750 if ((caretSticky
== SC_CARETSTICKY_OFF
) || (caretSticky
== SC_CARETSTICKY_WHITESPACE
)) {
5753 EnsureCaretVisible();
5759 EnsureCaretVisible();
5768 return (pdoc
->CanUndo() && !pdoc
->IsReadOnly()) ? 1 : 0;
5770 case SCI_EMPTYUNDOBUFFER
:
5771 pdoc
->DeleteUndoHistory();
5774 case SCI_GETFIRSTVISIBLELINE
:
5777 case SCI_SETFIRSTVISIBLELINE
:
5778 ScrollTo(static_cast<int>(wParam
));
5781 case SCI_GETLINE
: { // Risk of overwriting the end of the buffer
5782 int lineStart
= pdoc
->LineStart(static_cast<int>(wParam
));
5783 int lineEnd
= pdoc
->LineStart(static_cast<int>(wParam
+ 1));
5785 return lineEnd
- lineStart
;
5787 char *ptr
= CharPtrFromSPtr(lParam
);
5789 for (int iChar
= lineStart
; iChar
< lineEnd
; iChar
++) {
5790 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
5795 case SCI_GETLINECOUNT
:
5796 if (pdoc
->LinesTotal() == 0)
5799 return pdoc
->LinesTotal();
5802 return !pdoc
->IsSavePoint();
5805 int nStart
= static_cast<int>(wParam
);
5806 int nEnd
= static_cast<int>(lParam
);
5808 nEnd
= pdoc
->Length();
5810 nStart
= nEnd
; // Remove selection
5811 InvalidateSelection(SelectionRange(nStart
, nEnd
));
5813 sel
.selType
= Selection::selStream
;
5814 SetSelection(nEnd
, nStart
);
5815 EnsureCaretVisible();
5819 case SCI_GETSELTEXT
: {
5820 SelectionText selectedText
;
5821 CopySelectionRange(&selectedText
);
5823 return selectedText
.LengthWithTerminator();
5825 char *ptr
= CharPtrFromSPtr(lParam
);
5826 unsigned int iChar
= 0;
5827 if (selectedText
.Length()) {
5828 for (; iChar
< selectedText
.LengthWithTerminator(); iChar
++)
5829 ptr
[iChar
] = selectedText
.Data()[iChar
];
5837 case SCI_LINEFROMPOSITION
:
5838 if (static_cast<int>(wParam
) < 0)
5840 return pdoc
->LineFromPosition(static_cast<int>(wParam
));
5842 case SCI_POSITIONFROMLINE
:
5843 if (static_cast<int>(wParam
) < 0)
5844 wParam
= pdoc
->LineFromPosition(SelectionStart().Position());
5846 return 0; // Even if there is no text, there is a first line that starts at 0
5847 if (static_cast<int>(wParam
) > pdoc
->LinesTotal())
5849 //if (wParam > pdoc->LineFromPosition(pdoc->Length())) // Useful test, anyway...
5851 return pdoc
->LineStart(static_cast<int>(wParam
));
5853 // Replacement of the old Scintilla interpretation of EM_LINELENGTH
5854 case SCI_LINELENGTH
:
5855 if ((static_cast<int>(wParam
) < 0) ||
5856 (static_cast<int>(wParam
) > pdoc
->LineFromPosition(pdoc
->Length())))
5858 return pdoc
->LineStart(static_cast<int>(wParam
) + 1) - pdoc
->LineStart(static_cast<int>(wParam
));
5860 case SCI_REPLACESEL
: {
5865 char *replacement
= CharPtrFromSPtr(lParam
);
5866 const int lengthInserted
= pdoc
->InsertString(
5867 sel
.MainCaret(), replacement
, istrlen(replacement
));
5868 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
5869 EnsureCaretVisible();
5873 case SCI_SETTARGETSTART
:
5874 targetStart
= static_cast<int>(wParam
);
5877 case SCI_GETTARGETSTART
:
5880 case SCI_SETTARGETEND
:
5881 targetEnd
= static_cast<int>(wParam
);
5884 case SCI_GETTARGETEND
:
5887 case SCI_SETTARGETRANGE
:
5888 targetStart
= static_cast<int>(wParam
);
5889 targetEnd
= static_cast<int>(lParam
);
5892 case SCI_TARGETWHOLEDOCUMENT
:
5894 targetEnd
= pdoc
->Length();
5897 case SCI_TARGETFROMSELECTION
:
5898 if (sel
.MainCaret() < sel
.MainAnchor()) {
5899 targetStart
= sel
.MainCaret();
5900 targetEnd
= sel
.MainAnchor();
5902 targetStart
= sel
.MainAnchor();
5903 targetEnd
= sel
.MainCaret();
5907 case SCI_GETTARGETTEXT
: {
5908 std::string text
= RangeText(targetStart
, targetEnd
);
5909 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(text
.c_str()), text
.length());
5912 case SCI_REPLACETARGET
:
5913 PLATFORM_ASSERT(lParam
);
5914 return ReplaceTarget(false, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5916 case SCI_REPLACETARGETRE
:
5917 PLATFORM_ASSERT(lParam
);
5918 return ReplaceTarget(true, CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5920 case SCI_SEARCHINTARGET
:
5921 PLATFORM_ASSERT(lParam
);
5922 return SearchInTarget(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5924 case SCI_SETSEARCHFLAGS
:
5925 searchFlags
= static_cast<int>(wParam
);
5928 case SCI_GETSEARCHFLAGS
:
5932 return GetTag(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
5934 case SCI_POSITIONBEFORE
:
5935 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) - 1, -1, true);
5937 case SCI_POSITIONAFTER
:
5938 return pdoc
->MovePositionOutsideChar(static_cast<int>(wParam
) + 1, 1, true);
5940 case SCI_POSITIONRELATIVE
:
5941 return Platform::Clamp(pdoc
->GetRelativePosition(static_cast<int>(wParam
), static_cast<int>(lParam
)), 0, pdoc
->Length());
5943 case SCI_LINESCROLL
:
5944 ScrollTo(topLine
+ static_cast<int>(lParam
));
5945 HorizontalScrollTo(xOffset
+ static_cast<int>(wParam
)* static_cast<int>(vs
.spaceWidth
));
5948 case SCI_SETXOFFSET
:
5949 xOffset
= static_cast<int>(wParam
);
5950 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
5951 SetHorizontalScrollPos();
5955 case SCI_GETXOFFSET
:
5958 case SCI_CHOOSECARETX
:
5962 case SCI_SCROLLCARET
:
5963 EnsureCaretVisible();
5966 case SCI_SETREADONLY
:
5967 pdoc
->SetReadOnly(wParam
!= 0);
5970 case SCI_GETREADONLY
:
5971 return pdoc
->IsReadOnly();
5976 case SCI_POINTXFROMPOSITION
:
5980 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5981 // Convert to view-relative
5982 return static_cast<int>(pt
.x
) - vs
.textStart
+ vs
.fixedColumnWidth
;
5985 case SCI_POINTYFROMPOSITION
:
5989 Point pt
= LocationFromPosition(static_cast<int>(lParam
));
5990 return static_cast<int>(pt
.y
);
5994 return FindText(wParam
, lParam
);
5996 case SCI_GETTEXTRANGE
: {
5999 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6000 int cpMax
= static_cast<int>(tr
->chrg
.cpMax
);
6002 cpMax
= pdoc
->Length();
6003 PLATFORM_ASSERT(cpMax
<= pdoc
->Length());
6004 int len
= static_cast<int>(cpMax
- tr
->chrg
.cpMin
); // No -1 as cpMin and cpMax are referring to inter character positions
6005 pdoc
->GetCharRange(tr
->lpstrText
, static_cast<int>(tr
->chrg
.cpMin
), len
);
6006 // Spec says copied text is terminated with a NUL
6007 tr
->lpstrText
[len
] = '\0';
6008 return len
; // Not including NUL
6011 case SCI_HIDESELECTION
:
6012 view
.hideSelection
= wParam
!= 0;
6016 case SCI_FORMATRANGE
:
6017 return FormatRange(wParam
!= 0, reinterpret_cast<Sci_RangeToFormat
*>(lParam
));
6019 case SCI_GETMARGINLEFT
:
6020 return vs
.leftMarginWidth
;
6022 case SCI_GETMARGINRIGHT
:
6023 return vs
.rightMarginWidth
;
6025 case SCI_SETMARGINLEFT
:
6026 lastXChosen
+= static_cast<int>(lParam
) - vs
.leftMarginWidth
;
6027 vs
.leftMarginWidth
= static_cast<int>(lParam
);
6028 InvalidateStyleRedraw();
6031 case SCI_SETMARGINRIGHT
:
6032 vs
.rightMarginWidth
= static_cast<int>(lParam
);
6033 InvalidateStyleRedraw();
6036 // Control specific mesages
6041 const int lengthInserted
= pdoc
->InsertString(
6042 CurrentPosition(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6043 SetEmptySelection(sel
.MainCaret() + lengthInserted
);
6047 case SCI_ADDSTYLEDTEXT
:
6049 AddStyledText(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6052 case SCI_INSERTTEXT
: {
6055 int insertPos
= static_cast<int>(wParam
);
6056 if (static_cast<int>(wParam
) == -1)
6057 insertPos
= CurrentPosition();
6058 int newCurrent
= CurrentPosition();
6059 char *sz
= CharPtrFromSPtr(lParam
);
6060 const int lengthInserted
= pdoc
->InsertString(insertPos
, sz
, istrlen(sz
));
6061 if (newCurrent
> insertPos
)
6062 newCurrent
+= lengthInserted
;
6063 SetEmptySelection(newCurrent
);
6067 case SCI_CHANGEINSERTION
:
6068 PLATFORM_ASSERT(lParam
);
6069 pdoc
->ChangeInsertion(CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6072 case SCI_APPENDTEXT
:
6073 pdoc
->InsertString(pdoc
->Length(), CharPtrFromSPtr(lParam
), static_cast<int>(wParam
));
6080 case SCI_DELETERANGE
:
6081 pdoc
->DeleteChars(static_cast<int>(wParam
), static_cast<int>(lParam
));
6084 case SCI_CLEARDOCUMENTSTYLE
:
6085 ClearDocumentStyle();
6088 case SCI_SETUNDOCOLLECTION
:
6089 pdoc
->SetUndoCollection(wParam
!= 0);
6092 case SCI_GETUNDOCOLLECTION
:
6093 return pdoc
->IsCollectingUndo();
6095 case SCI_BEGINUNDOACTION
:
6096 pdoc
->BeginUndoAction();
6099 case SCI_ENDUNDOACTION
:
6100 pdoc
->EndUndoAction();
6103 case SCI_GETCARETPERIOD
:
6104 return caret
.period
;
6106 case SCI_SETCARETPERIOD
:
6107 CaretSetPeriod(static_cast<int>(wParam
));
6110 case SCI_GETWORDCHARS
:
6111 return pdoc
->GetCharsOfClass(CharClassify::ccWord
, reinterpret_cast<unsigned char *>(lParam
));
6113 case SCI_SETWORDCHARS
: {
6114 pdoc
->SetDefaultCharClasses(false);
6117 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccWord
);
6121 case SCI_GETWHITESPACECHARS
:
6122 return pdoc
->GetCharsOfClass(CharClassify::ccSpace
, reinterpret_cast<unsigned char *>(lParam
));
6124 case SCI_SETWHITESPACECHARS
: {
6127 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccSpace
);
6131 case SCI_GETPUNCTUATIONCHARS
:
6132 return pdoc
->GetCharsOfClass(CharClassify::ccPunctuation
, reinterpret_cast<unsigned char *>(lParam
));
6134 case SCI_SETPUNCTUATIONCHARS
: {
6137 pdoc
->SetCharClasses(reinterpret_cast<unsigned char *>(lParam
), CharClassify::ccPunctuation
);
6141 case SCI_SETCHARSDEFAULT
:
6142 pdoc
->SetDefaultCharClasses(true);
6146 return pdoc
->Length();
6149 pdoc
->Allocate(static_cast<int>(wParam
));
6153 return pdoc
->CharAt(static_cast<int>(wParam
));
6155 case SCI_SETCURRENTPOS
:
6156 if (sel
.IsRectangular()) {
6157 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
6158 SetRectangularRange();
6161 SetSelection(static_cast<int>(wParam
), sel
.MainAnchor());
6165 case SCI_GETCURRENTPOS
:
6166 return sel
.IsRectangular() ? sel
.Rectangular().caret
.Position() : sel
.MainCaret();
6169 if (sel
.IsRectangular()) {
6170 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
6171 SetRectangularRange();
6174 SetSelection(sel
.MainCaret(), static_cast<int>(wParam
));
6179 return sel
.IsRectangular() ? sel
.Rectangular().anchor
.Position() : sel
.MainAnchor();
6181 case SCI_SETSELECTIONSTART
:
6182 SetSelection(Platform::Maximum(sel
.MainCaret(), static_cast<int>(wParam
)), static_cast<int>(wParam
));
6185 case SCI_GETSELECTIONSTART
:
6186 return sel
.LimitsForRectangularElseMain().start
.Position();
6188 case SCI_SETSELECTIONEND
:
6189 SetSelection(static_cast<int>(wParam
), Platform::Minimum(sel
.MainAnchor(), static_cast<int>(wParam
)));
6192 case SCI_GETSELECTIONEND
:
6193 return sel
.LimitsForRectangularElseMain().end
.Position();
6195 case SCI_SETEMPTYSELECTION
:
6196 SetEmptySelection(static_cast<int>(wParam
));
6199 case SCI_SETPRINTMAGNIFICATION
:
6200 view
.printParameters
.magnification
= static_cast<int>(wParam
);
6203 case SCI_GETPRINTMAGNIFICATION
:
6204 return view
.printParameters
.magnification
;
6206 case SCI_SETPRINTCOLOURMODE
:
6207 view
.printParameters
.colourMode
= static_cast<int>(wParam
);
6210 case SCI_GETPRINTCOLOURMODE
:
6211 return view
.printParameters
.colourMode
;
6213 case SCI_SETPRINTWRAPMODE
:
6214 view
.printParameters
.wrapState
= (wParam
== SC_WRAP_WORD
) ? eWrapWord
: eWrapNone
;
6217 case SCI_GETPRINTWRAPMODE
:
6218 return view
.printParameters
.wrapState
;
6220 case SCI_GETSTYLEAT
:
6221 if (static_cast<int>(wParam
) >= pdoc
->Length())
6224 return pdoc
->StyleAt(static_cast<int>(wParam
));
6234 case SCI_SETSAVEPOINT
:
6235 pdoc
->SetSavePoint();
6238 case SCI_GETSTYLEDTEXT
: {
6241 Sci_TextRange
*tr
= reinterpret_cast<Sci_TextRange
*>(lParam
);
6243 for (long iChar
= tr
->chrg
.cpMin
; iChar
< tr
->chrg
.cpMax
; iChar
++) {
6244 tr
->lpstrText
[iPlace
++] = pdoc
->CharAt(static_cast<int>(iChar
));
6245 tr
->lpstrText
[iPlace
++] = pdoc
->StyleAt(static_cast<int>(iChar
));
6247 tr
->lpstrText
[iPlace
] = '\0';
6248 tr
->lpstrText
[iPlace
+ 1] = '\0';
6253 return (pdoc
->CanRedo() && !pdoc
->IsReadOnly()) ? 1 : 0;
6255 case SCI_MARKERLINEFROMHANDLE
:
6256 return pdoc
->LineFromHandle(static_cast<int>(wParam
));
6258 case SCI_MARKERDELETEHANDLE
:
6259 pdoc
->DeleteMarkFromHandle(static_cast<int>(wParam
));
6263 return vs
.viewWhitespace
;
6266 vs
.viewWhitespace
= static_cast<WhiteSpaceVisibility
>(wParam
);
6270 case SCI_GETWHITESPACESIZE
:
6271 return vs
.whitespaceSize
;
6273 case SCI_SETWHITESPACESIZE
:
6274 vs
.whitespaceSize
= static_cast<int>(wParam
);
6278 case SCI_POSITIONFROMPOINT
:
6279 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6282 case SCI_POSITIONFROMPOINTCLOSE
:
6283 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6286 case SCI_CHARPOSITIONFROMPOINT
:
6287 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6290 case SCI_CHARPOSITIONFROMPOINTCLOSE
:
6291 return PositionFromLocation(Point::FromInts(static_cast<int>(wParam
) - vs
.ExternalMarginWidth(), static_cast<int>(lParam
)),
6295 GoToLine(static_cast<int>(wParam
));
6299 SetEmptySelection(static_cast<int>(wParam
));
6300 EnsureCaretVisible();
6303 case SCI_GETCURLINE
: {
6304 int lineCurrentPos
= pdoc
->LineFromPosition(sel
.MainCaret());
6305 int lineStart
= pdoc
->LineStart(lineCurrentPos
);
6306 unsigned int lineEnd
= pdoc
->LineStart(lineCurrentPos
+ 1);
6308 return 1 + lineEnd
- lineStart
;
6310 PLATFORM_ASSERT(wParam
> 0);
6311 char *ptr
= CharPtrFromSPtr(lParam
);
6312 unsigned int iPlace
= 0;
6313 for (unsigned int iChar
= lineStart
; iChar
< lineEnd
&& iPlace
< wParam
- 1; iChar
++) {
6314 ptr
[iPlace
++] = pdoc
->CharAt(iChar
);
6317 return sel
.MainCaret() - lineStart
;
6320 case SCI_GETENDSTYLED
:
6321 return pdoc
->GetEndStyled();
6323 case SCI_GETEOLMODE
:
6324 return pdoc
->eolMode
;
6326 case SCI_SETEOLMODE
:
6327 pdoc
->eolMode
= static_cast<int>(wParam
);
6330 case SCI_SETLINEENDTYPESALLOWED
:
6331 if (pdoc
->SetLineEndTypesAllowed(static_cast<int>(wParam
))) {
6333 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6334 SetAnnotationHeights(0, pdoc
->LinesTotal());
6335 InvalidateStyleRedraw();
6339 case SCI_GETLINEENDTYPESALLOWED
:
6340 return pdoc
->GetLineEndTypesAllowed();
6342 case SCI_GETLINEENDTYPESACTIVE
:
6343 return pdoc
->GetLineEndTypesActive();
6345 case SCI_STARTSTYLING
:
6346 pdoc
->StartStyling(static_cast<int>(wParam
), static_cast<char>(lParam
));
6349 case SCI_SETSTYLING
:
6350 if (static_cast<int>(wParam
) < 0)
6351 errorStatus
= SC_STATUS_FAILURE
;
6353 pdoc
->SetStyleFor(static_cast<int>(wParam
), static_cast<char>(lParam
));
6356 case SCI_SETSTYLINGEX
: // Specify a complete styling buffer
6359 pdoc
->SetStyles(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6362 case SCI_SETBUFFEREDDRAW
:
6363 view
.bufferedDraw
= wParam
!= 0;
6366 case SCI_GETBUFFEREDDRAW
:
6367 return view
.bufferedDraw
;
6369 case SCI_GETTWOPHASEDRAW
:
6370 return view
.phasesDraw
== EditView::phasesTwo
;
6372 case SCI_SETTWOPHASEDRAW
:
6373 if (view
.SetTwoPhaseDraw(wParam
!= 0))
6374 InvalidateStyleRedraw();
6377 case SCI_GETPHASESDRAW
:
6378 return view
.phasesDraw
;
6380 case SCI_SETPHASESDRAW
:
6381 if (view
.SetPhasesDraw(static_cast<int>(wParam
)))
6382 InvalidateStyleRedraw();
6385 case SCI_SETFONTQUALITY
:
6386 vs
.extraFontFlag
&= ~SC_EFF_QUALITY_MASK
;
6387 vs
.extraFontFlag
|= (wParam
& SC_EFF_QUALITY_MASK
);
6388 InvalidateStyleRedraw();
6391 case SCI_GETFONTQUALITY
:
6392 return (vs
.extraFontFlag
& SC_EFF_QUALITY_MASK
);
6394 case SCI_SETTABWIDTH
:
6396 pdoc
->tabInChars
= static_cast<int>(wParam
);
6397 if (pdoc
->indentInChars
== 0)
6398 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6400 InvalidateStyleRedraw();
6403 case SCI_GETTABWIDTH
:
6404 return pdoc
->tabInChars
;
6406 case SCI_CLEARTABSTOPS
:
6407 if (view
.ClearTabstops(static_cast<int>(wParam
))) {
6408 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6409 NotifyModified(pdoc
, mh
, NULL
);
6413 case SCI_ADDTABSTOP
:
6414 if (view
.AddTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
))) {
6415 DocModification
mh(SC_MOD_CHANGETABSTOPS
, 0, 0, 0, 0, static_cast<int>(wParam
));
6416 NotifyModified(pdoc
, mh
, NULL
);
6420 case SCI_GETNEXTTABSTOP
:
6421 return view
.GetNextTabstop(static_cast<int>(wParam
), static_cast<int>(lParam
));
6424 pdoc
->indentInChars
= static_cast<int>(wParam
);
6425 if (pdoc
->indentInChars
!= 0)
6426 pdoc
->actualIndentInChars
= pdoc
->indentInChars
;
6428 pdoc
->actualIndentInChars
= pdoc
->tabInChars
;
6429 InvalidateStyleRedraw();
6433 return pdoc
->indentInChars
;
6435 case SCI_SETUSETABS
:
6436 pdoc
->useTabs
= wParam
!= 0;
6437 InvalidateStyleRedraw();
6440 case SCI_GETUSETABS
:
6441 return pdoc
->useTabs
;
6443 case SCI_SETLINEINDENTATION
:
6444 pdoc
->SetLineIndentation(static_cast<int>(wParam
), static_cast<int>(lParam
));
6447 case SCI_GETLINEINDENTATION
:
6448 return pdoc
->GetLineIndentation(static_cast<int>(wParam
));
6450 case SCI_GETLINEINDENTPOSITION
:
6451 return pdoc
->GetLineIndentPosition(static_cast<int>(wParam
));
6453 case SCI_SETTABINDENTS
:
6454 pdoc
->tabIndents
= wParam
!= 0;
6457 case SCI_GETTABINDENTS
:
6458 return pdoc
->tabIndents
;
6460 case SCI_SETBACKSPACEUNINDENTS
:
6461 pdoc
->backspaceUnindents
= wParam
!= 0;
6464 case SCI_GETBACKSPACEUNINDENTS
:
6465 return pdoc
->backspaceUnindents
;
6467 case SCI_SETMOUSEDWELLTIME
:
6468 dwellDelay
= static_cast<int>(wParam
);
6469 ticksToDwell
= dwellDelay
;
6472 case SCI_GETMOUSEDWELLTIME
:
6475 case SCI_WORDSTARTPOSITION
:
6476 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), -1, lParam
!= 0);
6478 case SCI_WORDENDPOSITION
:
6479 return pdoc
->ExtendWordSelect(static_cast<int>(wParam
), 1, lParam
!= 0);
6481 case SCI_ISRANGEWORD
:
6482 return pdoc
->IsWordAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
6484 case SCI_SETIDLESTYLING
:
6485 idleStyling
= static_cast<int>(wParam
);
6488 case SCI_GETIDLESTYLING
:
6491 case SCI_SETWRAPMODE
:
6492 if (vs
.SetWrapState(static_cast<int>(wParam
))) {
6494 ContainerNeedsUpdate(SC_UPDATE_H_SCROLL
);
6495 InvalidateStyleRedraw();
6496 ReconfigureScrollBars();
6500 case SCI_GETWRAPMODE
:
6501 return vs
.wrapState
;
6503 case SCI_SETWRAPVISUALFLAGS
:
6504 if (vs
.SetWrapVisualFlags(static_cast<int>(wParam
))) {
6505 InvalidateStyleRedraw();
6506 ReconfigureScrollBars();
6510 case SCI_GETWRAPVISUALFLAGS
:
6511 return vs
.wrapVisualFlags
;
6513 case SCI_SETWRAPVISUALFLAGSLOCATION
:
6514 if (vs
.SetWrapVisualFlagsLocation(static_cast<int>(wParam
))) {
6515 InvalidateStyleRedraw();
6519 case SCI_GETWRAPVISUALFLAGSLOCATION
:
6520 return vs
.wrapVisualFlagsLocation
;
6522 case SCI_SETWRAPSTARTINDENT
:
6523 if (vs
.SetWrapVisualStartIndent(static_cast<int>(wParam
))) {
6524 InvalidateStyleRedraw();
6525 ReconfigureScrollBars();
6529 case SCI_GETWRAPSTARTINDENT
:
6530 return vs
.wrapVisualStartIndent
;
6532 case SCI_SETWRAPINDENTMODE
:
6533 if (vs
.SetWrapIndentMode(static_cast<int>(wParam
))) {
6534 InvalidateStyleRedraw();
6535 ReconfigureScrollBars();
6539 case SCI_GETWRAPINDENTMODE
:
6540 return vs
.wrapIndentMode
;
6542 case SCI_SETLAYOUTCACHE
:
6543 view
.llc
.SetLevel(static_cast<int>(wParam
));
6546 case SCI_GETLAYOUTCACHE
:
6547 return view
.llc
.GetLevel();
6549 case SCI_SETPOSITIONCACHE
:
6550 view
.posCache
.SetSize(wParam
);
6553 case SCI_GETPOSITIONCACHE
:
6554 return view
.posCache
.GetSize();
6556 case SCI_SETSCROLLWIDTH
:
6557 PLATFORM_ASSERT(wParam
> 0);
6558 if ((wParam
> 0) && (wParam
!= static_cast<unsigned int >(scrollWidth
))) {
6559 view
.lineWidthMaxSeen
= 0;
6560 scrollWidth
= static_cast<int>(wParam
);
6565 case SCI_GETSCROLLWIDTH
:
6568 case SCI_SETSCROLLWIDTHTRACKING
:
6569 trackLineWidth
= wParam
!= 0;
6572 case SCI_GETSCROLLWIDTHTRACKING
:
6573 return trackLineWidth
;
6579 case SCI_LINESSPLIT
:
6580 LinesSplit(static_cast<int>(wParam
));
6584 PLATFORM_ASSERT(wParam
< vs
.styles
.size());
6585 PLATFORM_ASSERT(lParam
);
6586 return TextWidth(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
6588 case SCI_TEXTHEIGHT
:
6590 return vs
.lineHeight
;
6592 case SCI_SETENDATLASTLINE
:
6593 PLATFORM_ASSERT((wParam
== 0) || (wParam
== 1));
6594 if (endAtLastLine
!= (wParam
!= 0)) {
6595 endAtLastLine
= wParam
!= 0;
6600 case SCI_GETENDATLASTLINE
:
6601 return endAtLastLine
;
6603 case SCI_SETCARETSTICKY
:
6604 PLATFORM_ASSERT(wParam
<= SC_CARETSTICKY_WHITESPACE
);
6605 if (wParam
<= SC_CARETSTICKY_WHITESPACE
) {
6606 caretSticky
= static_cast<int>(wParam
);
6610 case SCI_GETCARETSTICKY
:
6613 case SCI_TOGGLECARETSTICKY
:
6614 caretSticky
= !caretSticky
;
6618 return pdoc
->GetColumn(static_cast<int>(wParam
));
6620 case SCI_FINDCOLUMN
:
6621 return pdoc
->FindColumn(static_cast<int>(wParam
), static_cast<int>(lParam
));
6623 case SCI_SETHSCROLLBAR
:
6624 if (horizontalScrollBarVisible
!= (wParam
!= 0)) {
6625 horizontalScrollBarVisible
= wParam
!= 0;
6627 ReconfigureScrollBars();
6631 case SCI_GETHSCROLLBAR
:
6632 return horizontalScrollBarVisible
;
6634 case SCI_SETVSCROLLBAR
:
6635 if (verticalScrollBarVisible
!= (wParam
!= 0)) {
6636 verticalScrollBarVisible
= wParam
!= 0;
6638 ReconfigureScrollBars();
6639 if (verticalScrollBarVisible
)
6640 SetVerticalScrollPos();
6644 case SCI_GETVSCROLLBAR
:
6645 return verticalScrollBarVisible
;
6647 case SCI_SETINDENTATIONGUIDES
:
6648 vs
.viewIndentationGuides
= IndentView(wParam
);
6652 case SCI_GETINDENTATIONGUIDES
:
6653 return vs
.viewIndentationGuides
;
6655 case SCI_SETHIGHLIGHTGUIDE
:
6656 if ((highlightGuideColumn
!= static_cast<int>(wParam
)) || (wParam
> 0)) {
6657 highlightGuideColumn
= static_cast<int>(wParam
);
6662 case SCI_GETHIGHLIGHTGUIDE
:
6663 return highlightGuideColumn
;
6665 case SCI_GETLINEENDPOSITION
:
6666 return pdoc
->LineEnd(static_cast<int>(wParam
));
6668 case SCI_SETCODEPAGE
:
6669 if (ValidCodePage(static_cast<int>(wParam
))) {
6670 if (pdoc
->SetDBCSCodePage(static_cast<int>(wParam
))) {
6672 cs
.InsertLines(0, pdoc
->LinesTotal() - 1);
6673 SetAnnotationHeights(0, pdoc
->LinesTotal());
6674 InvalidateStyleRedraw();
6675 SetRepresentations();
6680 case SCI_GETCODEPAGE
:
6681 return pdoc
->dbcsCodePage
;
6683 case SCI_SETIMEINTERACTION
:
6684 imeInteraction
= static_cast<EditModel::IMEInteraction
>(wParam
);
6687 case SCI_GETIMEINTERACTION
:
6688 return imeInteraction
;
6690 #ifdef INCLUDE_DEPRECATED_FEATURES
6691 case SCI_SETUSEPALETTE
:
6692 InvalidateStyleRedraw();
6695 case SCI_GETUSEPALETTE
:
6699 // Marker definition and setting
6700 case SCI_MARKERDEFINE
:
6701 if (wParam
<= MARKER_MAX
) {
6702 vs
.markers
[wParam
].markType
= static_cast<int>(lParam
);
6703 vs
.CalcLargestMarkerHeight();
6705 InvalidateStyleData();
6709 case SCI_MARKERSYMBOLDEFINED
:
6710 if (wParam
<= MARKER_MAX
)
6711 return vs
.markers
[wParam
].markType
;
6715 case SCI_MARKERSETFORE
:
6716 if (wParam
<= MARKER_MAX
)
6717 vs
.markers
[wParam
].fore
= ColourDesired(static_cast<long>(lParam
));
6718 InvalidateStyleData();
6721 case SCI_MARKERSETBACKSELECTED
:
6722 if (wParam
<= MARKER_MAX
)
6723 vs
.markers
[wParam
].backSelected
= ColourDesired(static_cast<long>(lParam
));
6724 InvalidateStyleData();
6727 case SCI_MARKERENABLEHIGHLIGHT
:
6728 marginView
.highlightDelimiter
.isEnabled
= wParam
== 1;
6731 case SCI_MARKERSETBACK
:
6732 if (wParam
<= MARKER_MAX
)
6733 vs
.markers
[wParam
].back
= ColourDesired(static_cast<long>(lParam
));
6734 InvalidateStyleData();
6737 case SCI_MARKERSETALPHA
:
6738 if (wParam
<= MARKER_MAX
)
6739 vs
.markers
[wParam
].alpha
= static_cast<int>(lParam
);
6740 InvalidateStyleRedraw();
6742 case SCI_MARKERADD
: {
6743 int markerID
= pdoc
->AddMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6746 case SCI_MARKERADDSET
:
6748 pdoc
->AddMarkSet(static_cast<int>(wParam
), static_cast<int>(lParam
));
6751 case SCI_MARKERDELETE
:
6752 pdoc
->DeleteMark(static_cast<int>(wParam
), static_cast<int>(lParam
));
6755 case SCI_MARKERDELETEALL
:
6756 pdoc
->DeleteAllMarks(static_cast<int>(wParam
));
6760 return pdoc
->GetMark(static_cast<int>(wParam
));
6762 case SCI_MARKERNEXT
:
6763 return pdoc
->MarkerNext(static_cast<int>(wParam
), static_cast<int>(lParam
));
6765 case SCI_MARKERPREVIOUS
: {
6766 for (int iLine
= static_cast<int>(wParam
); iLine
>= 0; iLine
--) {
6767 if ((pdoc
->GetMark(iLine
) & lParam
) != 0)
6773 case SCI_MARKERDEFINEPIXMAP
:
6774 if (wParam
<= MARKER_MAX
) {
6775 vs
.markers
[wParam
].SetXPM(CharPtrFromSPtr(lParam
));
6776 vs
.CalcLargestMarkerHeight();
6778 InvalidateStyleData();
6782 case SCI_RGBAIMAGESETWIDTH
:
6783 sizeRGBAImage
.x
= static_cast<XYPOSITION
>(wParam
);
6786 case SCI_RGBAIMAGESETHEIGHT
:
6787 sizeRGBAImage
.y
= static_cast<XYPOSITION
>(wParam
);
6790 case SCI_RGBAIMAGESETSCALE
:
6791 scaleRGBAImage
= static_cast<float>(wParam
);
6794 case SCI_MARKERDEFINERGBAIMAGE
:
6795 if (wParam
<= MARKER_MAX
) {
6796 vs
.markers
[wParam
].SetRGBAImage(sizeRGBAImage
, scaleRGBAImage
/ 100.0f
, reinterpret_cast<unsigned char *>(lParam
));
6797 vs
.CalcLargestMarkerHeight();
6799 InvalidateStyleData();
6803 case SCI_SETMARGINTYPEN
:
6804 if (ValidMargin(wParam
)) {
6805 vs
.ms
[wParam
].style
= static_cast<int>(lParam
);
6806 InvalidateStyleRedraw();
6810 case SCI_GETMARGINTYPEN
:
6811 if (ValidMargin(wParam
))
6812 return vs
.ms
[wParam
].style
;
6816 case SCI_SETMARGINWIDTHN
:
6817 if (ValidMargin(wParam
)) {
6818 // Short-circuit if the width is unchanged, to avoid unnecessary redraw.
6819 if (vs
.ms
[wParam
].width
!= lParam
) {
6820 lastXChosen
+= static_cast<int>(lParam
) - vs
.ms
[wParam
].width
;
6821 vs
.ms
[wParam
].width
= static_cast<int>(lParam
);
6822 InvalidateStyleRedraw();
6827 case SCI_GETMARGINWIDTHN
:
6828 if (ValidMargin(wParam
))
6829 return vs
.ms
[wParam
].width
;
6833 case SCI_SETMARGINMASKN
:
6834 if (ValidMargin(wParam
)) {
6835 vs
.ms
[wParam
].mask
= static_cast<int>(lParam
);
6836 InvalidateStyleRedraw();
6840 case SCI_GETMARGINMASKN
:
6841 if (ValidMargin(wParam
))
6842 return vs
.ms
[wParam
].mask
;
6846 case SCI_SETMARGINSENSITIVEN
:
6847 if (ValidMargin(wParam
)) {
6848 vs
.ms
[wParam
].sensitive
= lParam
!= 0;
6849 InvalidateStyleRedraw();
6853 case SCI_GETMARGINSENSITIVEN
:
6854 if (ValidMargin(wParam
))
6855 return vs
.ms
[wParam
].sensitive
? 1 : 0;
6859 case SCI_SETMARGINCURSORN
:
6860 if (ValidMargin(wParam
))
6861 vs
.ms
[wParam
].cursor
= static_cast<int>(lParam
);
6864 case SCI_GETMARGINCURSORN
:
6865 if (ValidMargin(wParam
))
6866 return vs
.ms
[wParam
].cursor
;
6870 case SCI_STYLECLEARALL
:
6872 InvalidateStyleRedraw();
6875 case SCI_STYLESETFORE
:
6876 case SCI_STYLESETBACK
:
6877 case SCI_STYLESETBOLD
:
6878 case SCI_STYLESETWEIGHT
:
6879 case SCI_STYLESETITALIC
:
6880 case SCI_STYLESETEOLFILLED
:
6881 case SCI_STYLESETSIZE
:
6882 case SCI_STYLESETSIZEFRACTIONAL
:
6883 case SCI_STYLESETFONT
:
6884 case SCI_STYLESETUNDERLINE
:
6885 case SCI_STYLESETCASE
:
6886 case SCI_STYLESETCHARACTERSET
:
6887 case SCI_STYLESETVISIBLE
:
6888 case SCI_STYLESETCHANGEABLE
:
6889 case SCI_STYLESETHOTSPOT
:
6890 StyleSetMessage(iMessage
, wParam
, lParam
);
6893 case SCI_STYLEGETFORE
:
6894 case SCI_STYLEGETBACK
:
6895 case SCI_STYLEGETBOLD
:
6896 case SCI_STYLEGETWEIGHT
:
6897 case SCI_STYLEGETITALIC
:
6898 case SCI_STYLEGETEOLFILLED
:
6899 case SCI_STYLEGETSIZE
:
6900 case SCI_STYLEGETSIZEFRACTIONAL
:
6901 case SCI_STYLEGETFONT
:
6902 case SCI_STYLEGETUNDERLINE
:
6903 case SCI_STYLEGETCASE
:
6904 case SCI_STYLEGETCHARACTERSET
:
6905 case SCI_STYLEGETVISIBLE
:
6906 case SCI_STYLEGETCHANGEABLE
:
6907 case SCI_STYLEGETHOTSPOT
:
6908 return StyleGetMessage(iMessage
, wParam
, lParam
);
6910 case SCI_STYLERESETDEFAULT
:
6911 vs
.ResetDefaultStyle();
6912 InvalidateStyleRedraw();
6914 case SCI_SETSTYLEBITS
:
6915 vs
.EnsureStyle(0xff);
6918 case SCI_GETSTYLEBITS
:
6921 case SCI_SETLINESTATE
:
6922 return pdoc
->SetLineState(static_cast<int>(wParam
), static_cast<int>(lParam
));
6924 case SCI_GETLINESTATE
:
6925 return pdoc
->GetLineState(static_cast<int>(wParam
));
6927 case SCI_GETMAXLINESTATE
:
6928 return pdoc
->GetMaxLineState();
6930 case SCI_GETCARETLINEVISIBLE
:
6931 return vs
.showCaretLineBackground
;
6932 case SCI_SETCARETLINEVISIBLE
:
6933 vs
.showCaretLineBackground
= wParam
!= 0;
6934 InvalidateStyleRedraw();
6936 case SCI_GETCARETLINEVISIBLEALWAYS
:
6937 return vs
.alwaysShowCaretLineBackground
;
6938 case SCI_SETCARETLINEVISIBLEALWAYS
:
6939 vs
.alwaysShowCaretLineBackground
= wParam
!= 0;
6940 InvalidateStyleRedraw();
6943 case SCI_GETCARETLINEBACK
:
6944 return vs
.caretLineBackground
.AsLong();
6945 case SCI_SETCARETLINEBACK
:
6946 vs
.caretLineBackground
= static_cast<int>(wParam
);
6947 InvalidateStyleRedraw();
6949 case SCI_GETCARETLINEBACKALPHA
:
6950 return vs
.caretLineAlpha
;
6951 case SCI_SETCARETLINEBACKALPHA
:
6952 vs
.caretLineAlpha
= static_cast<int>(wParam
);
6953 InvalidateStyleRedraw();
6958 case SCI_VISIBLEFROMDOCLINE
:
6959 return cs
.DisplayFromDoc(static_cast<int>(wParam
));
6961 case SCI_DOCLINEFROMVISIBLE
:
6962 return cs
.DocFromDisplay(static_cast<int>(wParam
));
6965 return WrapCount(static_cast<int>(wParam
));
6967 case SCI_SETFOLDLEVEL
: {
6968 int prev
= pdoc
->SetLevel(static_cast<int>(wParam
), static_cast<int>(lParam
));
6969 if (prev
!= static_cast<int>(lParam
))
6974 case SCI_GETFOLDLEVEL
:
6975 return pdoc
->GetLevel(static_cast<int>(wParam
));
6977 case SCI_GETLASTCHILD
:
6978 return pdoc
->GetLastChild(static_cast<int>(wParam
), static_cast<int>(lParam
));
6980 case SCI_GETFOLDPARENT
:
6981 return pdoc
->GetFoldParent(static_cast<int>(wParam
));
6984 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), true);
6991 cs
.SetVisible(static_cast<int>(wParam
), static_cast<int>(lParam
), false);
6996 case SCI_GETLINEVISIBLE
:
6997 return cs
.GetVisible(static_cast<int>(wParam
));
6999 case SCI_GETALLLINESVISIBLE
:
7000 return cs
.HiddenLines() ? 0 : 1;
7002 case SCI_SETFOLDEXPANDED
:
7003 SetFoldExpanded(static_cast<int>(wParam
), lParam
!= 0);
7006 case SCI_GETFOLDEXPANDED
:
7007 return cs
.GetExpanded(static_cast<int>(wParam
));
7009 case SCI_SETAUTOMATICFOLD
:
7010 foldAutomatic
= static_cast<int>(wParam
);
7013 case SCI_GETAUTOMATICFOLD
:
7014 return foldAutomatic
;
7016 case SCI_SETFOLDFLAGS
:
7017 foldFlags
= static_cast<int>(wParam
);
7021 case SCI_TOGGLEFOLD
:
7022 FoldLine(static_cast<int>(wParam
), SC_FOLDACTION_TOGGLE
);
7026 FoldLine(static_cast<int>(wParam
), static_cast<int>(lParam
));
7029 case SCI_FOLDCHILDREN
:
7030 FoldExpand(static_cast<int>(wParam
), static_cast<int>(lParam
), pdoc
->GetLevel(static_cast<int>(wParam
)));
7034 FoldAll(static_cast<int>(wParam
));
7037 case SCI_EXPANDCHILDREN
:
7038 FoldExpand(static_cast<int>(wParam
), SC_FOLDACTION_EXPAND
, static_cast<int>(lParam
));
7041 case SCI_CONTRACTEDFOLDNEXT
:
7042 return ContractedFoldNext(static_cast<int>(wParam
));
7044 case SCI_ENSUREVISIBLE
:
7045 EnsureLineVisible(static_cast<int>(wParam
), false);
7048 case SCI_ENSUREVISIBLEENFORCEPOLICY
:
7049 EnsureLineVisible(static_cast<int>(wParam
), true);
7052 case SCI_SCROLLRANGE
:
7053 ScrollRange(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7056 case SCI_SEARCHANCHOR
:
7060 case SCI_SEARCHNEXT
:
7061 case SCI_SEARCHPREV
:
7062 return SearchText(iMessage
, wParam
, lParam
);
7064 case SCI_SETXCARETPOLICY
:
7065 caretXPolicy
= static_cast<int>(wParam
);
7066 caretXSlop
= static_cast<int>(lParam
);
7069 case SCI_SETYCARETPOLICY
:
7070 caretYPolicy
= static_cast<int>(wParam
);
7071 caretYSlop
= static_cast<int>(lParam
);
7074 case SCI_SETVISIBLEPOLICY
:
7075 visiblePolicy
= static_cast<int>(wParam
);
7076 visibleSlop
= static_cast<int>(lParam
);
7079 case SCI_LINESONSCREEN
:
7080 return LinesOnScreen();
7082 case SCI_SETSELFORE
:
7083 vs
.selColours
.fore
= ColourOptional(wParam
, lParam
);
7084 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(lParam
));
7085 InvalidateStyleRedraw();
7088 case SCI_SETSELBACK
:
7089 vs
.selColours
.back
= ColourOptional(wParam
, lParam
);
7090 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(lParam
));
7091 InvalidateStyleRedraw();
7094 case SCI_SETSELALPHA
:
7095 vs
.selAlpha
= static_cast<int>(wParam
);
7096 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
7097 InvalidateStyleRedraw();
7100 case SCI_GETSELALPHA
:
7103 case SCI_GETSELEOLFILLED
:
7104 return vs
.selEOLFilled
;
7106 case SCI_SETSELEOLFILLED
:
7107 vs
.selEOLFilled
= wParam
!= 0;
7108 InvalidateStyleRedraw();
7111 case SCI_SETWHITESPACEFORE
:
7112 vs
.whitespaceColours
.fore
= ColourOptional(wParam
, lParam
);
7113 InvalidateStyleRedraw();
7116 case SCI_SETWHITESPACEBACK
:
7117 vs
.whitespaceColours
.back
= ColourOptional(wParam
, lParam
);
7118 InvalidateStyleRedraw();
7121 case SCI_SETCARETFORE
:
7122 vs
.caretcolour
= ColourDesired(static_cast<long>(wParam
));
7123 InvalidateStyleRedraw();
7126 case SCI_GETCARETFORE
:
7127 return vs
.caretcolour
.AsLong();
7129 case SCI_SETCARETSTYLE
:
7130 if (wParam
<= CARETSTYLE_BLOCK
)
7131 vs
.caretStyle
= static_cast<int>(wParam
);
7133 /* Default to the line caret */
7134 vs
.caretStyle
= CARETSTYLE_LINE
;
7135 InvalidateStyleRedraw();
7138 case SCI_GETCARETSTYLE
:
7139 return vs
.caretStyle
;
7141 case SCI_SETCARETWIDTH
:
7142 if (static_cast<int>(wParam
) <= 0)
7144 else if (wParam
>= 3)
7147 vs
.caretWidth
= static_cast<int>(wParam
);
7148 InvalidateStyleRedraw();
7151 case SCI_GETCARETWIDTH
:
7152 return vs
.caretWidth
;
7154 case SCI_ASSIGNCMDKEY
:
7155 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7156 Platform::HighShortFromLong(static_cast<long>(wParam
)), static_cast<unsigned int>(lParam
));
7159 case SCI_CLEARCMDKEY
:
7160 kmap
.AssignCmdKey(Platform::LowShortFromLong(static_cast<long>(wParam
)),
7161 Platform::HighShortFromLong(static_cast<long>(wParam
)), SCI_NULL
);
7164 case SCI_CLEARALLCMDKEYS
:
7168 case SCI_INDICSETSTYLE
:
7169 if (wParam
<= INDIC_MAX
) {
7170 vs
.indicators
[wParam
].sacNormal
.style
= static_cast<int>(lParam
);
7171 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7172 InvalidateStyleRedraw();
7176 case SCI_INDICGETSTYLE
:
7177 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.style
: 0;
7179 case SCI_INDICSETFORE
:
7180 if (wParam
<= INDIC_MAX
) {
7181 vs
.indicators
[wParam
].sacNormal
.fore
= ColourDesired(static_cast<long>(lParam
));
7182 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7183 InvalidateStyleRedraw();
7187 case SCI_INDICGETFORE
:
7188 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacNormal
.fore
.AsLong() : 0;
7190 case SCI_INDICSETHOVERSTYLE
:
7191 if (wParam
<= INDIC_MAX
) {
7192 vs
.indicators
[wParam
].sacHover
.style
= static_cast<int>(lParam
);
7193 InvalidateStyleRedraw();
7197 case SCI_INDICGETHOVERSTYLE
:
7198 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.style
: 0;
7200 case SCI_INDICSETHOVERFORE
:
7201 if (wParam
<= INDIC_MAX
) {
7202 vs
.indicators
[wParam
].sacHover
.fore
= ColourDesired(static_cast<long>(lParam
));
7203 InvalidateStyleRedraw();
7207 case SCI_INDICGETHOVERFORE
:
7208 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].sacHover
.fore
.AsLong() : 0;
7210 case SCI_INDICSETFLAGS
:
7211 if (wParam
<= INDIC_MAX
) {
7212 vs
.indicators
[wParam
].SetFlags(static_cast<int>(lParam
));
7213 InvalidateStyleRedraw();
7217 case SCI_INDICGETFLAGS
:
7218 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].Flags() : 0;
7220 case SCI_INDICSETUNDER
:
7221 if (wParam
<= INDIC_MAX
) {
7222 vs
.indicators
[wParam
].under
= lParam
!= 0;
7223 InvalidateStyleRedraw();
7227 case SCI_INDICGETUNDER
:
7228 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].under
: 0;
7230 case SCI_INDICSETALPHA
:
7231 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7232 vs
.indicators
[wParam
].fillAlpha
= static_cast<int>(lParam
);
7233 InvalidateStyleRedraw();
7237 case SCI_INDICGETALPHA
:
7238 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].fillAlpha
: 0;
7240 case SCI_INDICSETOUTLINEALPHA
:
7241 if (wParam
<= INDIC_MAX
&& lParam
>=0 && lParam
<= 255) {
7242 vs
.indicators
[wParam
].outlineAlpha
= static_cast<int>(lParam
);
7243 InvalidateStyleRedraw();
7247 case SCI_INDICGETOUTLINEALPHA
:
7248 return (wParam
<= INDIC_MAX
) ? vs
.indicators
[wParam
].outlineAlpha
: 0;
7250 case SCI_SETINDICATORCURRENT
:
7251 pdoc
->decorations
.SetCurrentIndicator(static_cast<int>(wParam
));
7253 case SCI_GETINDICATORCURRENT
:
7254 return pdoc
->decorations
.GetCurrentIndicator();
7255 case SCI_SETINDICATORVALUE
:
7256 pdoc
->decorations
.SetCurrentValue(static_cast<int>(wParam
));
7258 case SCI_GETINDICATORVALUE
:
7259 return pdoc
->decorations
.GetCurrentValue();
7261 case SCI_INDICATORFILLRANGE
:
7262 pdoc
->DecorationFillRange(static_cast<int>(wParam
), pdoc
->decorations
.GetCurrentValue(), static_cast<int>(lParam
));
7265 case SCI_INDICATORCLEARRANGE
:
7266 pdoc
->DecorationFillRange(static_cast<int>(wParam
), 0, static_cast<int>(lParam
));
7269 case SCI_INDICATORALLONFOR
:
7270 return pdoc
->decorations
.AllOnFor(static_cast<int>(wParam
));
7272 case SCI_INDICATORVALUEAT
:
7273 return pdoc
->decorations
.ValueAt(static_cast<int>(wParam
), static_cast<int>(lParam
));
7275 case SCI_INDICATORSTART
:
7276 return pdoc
->decorations
.Start(static_cast<int>(wParam
), static_cast<int>(lParam
));
7278 case SCI_INDICATOREND
:
7279 return pdoc
->decorations
.End(static_cast<int>(wParam
), static_cast<int>(lParam
));
7282 case SCI_LINEDOWNEXTEND
:
7284 case SCI_PARADOWNEXTEND
:
7286 case SCI_LINEUPEXTEND
:
7288 case SCI_PARAUPEXTEND
:
7290 case SCI_CHARLEFTEXTEND
:
7292 case SCI_CHARRIGHTEXTEND
:
7294 case SCI_WORDLEFTEXTEND
:
7296 case SCI_WORDRIGHTEXTEND
:
7297 case SCI_WORDLEFTEND
:
7298 case SCI_WORDLEFTENDEXTEND
:
7299 case SCI_WORDRIGHTEND
:
7300 case SCI_WORDRIGHTENDEXTEND
:
7302 case SCI_HOMEEXTEND
:
7304 case SCI_LINEENDEXTEND
:
7306 case SCI_HOMEWRAPEXTEND
:
7307 case SCI_LINEENDWRAP
:
7308 case SCI_LINEENDWRAPEXTEND
:
7309 case SCI_DOCUMENTSTART
:
7310 case SCI_DOCUMENTSTARTEXTEND
:
7311 case SCI_DOCUMENTEND
:
7312 case SCI_DOCUMENTENDEXTEND
:
7313 case SCI_SCROLLTOSTART
:
7314 case SCI_SCROLLTOEND
:
7316 case SCI_STUTTEREDPAGEUP
:
7317 case SCI_STUTTEREDPAGEUPEXTEND
:
7318 case SCI_STUTTEREDPAGEDOWN
:
7319 case SCI_STUTTEREDPAGEDOWNEXTEND
:
7322 case SCI_PAGEUPEXTEND
:
7324 case SCI_PAGEDOWNEXTEND
:
7325 case SCI_EDITTOGGLEOVERTYPE
:
7327 case SCI_DELETEBACK
:
7333 case SCI_VCHOMEEXTEND
:
7334 case SCI_VCHOMEWRAP
:
7335 case SCI_VCHOMEWRAPEXTEND
:
7336 case SCI_VCHOMEDISPLAY
:
7337 case SCI_VCHOMEDISPLAYEXTEND
:
7340 case SCI_DELWORDLEFT
:
7341 case SCI_DELWORDRIGHT
:
7342 case SCI_DELWORDRIGHTEND
:
7343 case SCI_DELLINELEFT
:
7344 case SCI_DELLINERIGHT
:
7347 case SCI_LINEDELETE
:
7348 case SCI_LINETRANSPOSE
:
7349 case SCI_LINEDUPLICATE
:
7352 case SCI_LINESCROLLDOWN
:
7353 case SCI_LINESCROLLUP
:
7354 case SCI_WORDPARTLEFT
:
7355 case SCI_WORDPARTLEFTEXTEND
:
7356 case SCI_WORDPARTRIGHT
:
7357 case SCI_WORDPARTRIGHTEXTEND
:
7358 case SCI_DELETEBACKNOTLINE
:
7359 case SCI_HOMEDISPLAY
:
7360 case SCI_HOMEDISPLAYEXTEND
:
7361 case SCI_LINEENDDISPLAY
:
7362 case SCI_LINEENDDISPLAYEXTEND
:
7363 case SCI_LINEDOWNRECTEXTEND
:
7364 case SCI_LINEUPRECTEXTEND
:
7365 case SCI_CHARLEFTRECTEXTEND
:
7366 case SCI_CHARRIGHTRECTEXTEND
:
7367 case SCI_HOMERECTEXTEND
:
7368 case SCI_VCHOMERECTEXTEND
:
7369 case SCI_LINEENDRECTEXTEND
:
7370 case SCI_PAGEUPRECTEXTEND
:
7371 case SCI_PAGEDOWNRECTEXTEND
:
7372 case SCI_SELECTIONDUPLICATE
:
7373 return KeyCommand(iMessage
);
7375 case SCI_BRACEHIGHLIGHT
:
7376 SetBraceHighlight(static_cast<int>(wParam
), static_cast<int>(lParam
), STYLE_BRACELIGHT
);
7379 case SCI_BRACEHIGHLIGHTINDICATOR
:
7380 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7381 vs
.braceHighlightIndicatorSet
= wParam
!= 0;
7382 vs
.braceHighlightIndicator
= static_cast<int>(lParam
);
7386 case SCI_BRACEBADLIGHT
:
7387 SetBraceHighlight(static_cast<int>(wParam
), -1, STYLE_BRACEBAD
);
7390 case SCI_BRACEBADLIGHTINDICATOR
:
7391 if (lParam
>= 0 && lParam
<= INDIC_MAX
) {
7392 vs
.braceBadLightIndicatorSet
= wParam
!= 0;
7393 vs
.braceBadLightIndicator
= static_cast<int>(lParam
);
7397 case SCI_BRACEMATCH
:
7398 // wParam is position of char to find brace for,
7399 // lParam is maximum amount of text to restyle to find it
7400 return pdoc
->BraceMatch(static_cast<int>(wParam
), static_cast<int>(lParam
));
7402 case SCI_GETVIEWEOL
:
7405 case SCI_SETVIEWEOL
:
7406 vs
.viewEOL
= wParam
!= 0;
7407 InvalidateStyleRedraw();
7411 vs
.zoomLevel
= static_cast<int>(wParam
);
7412 InvalidateStyleRedraw();
7417 return vs
.zoomLevel
;
7419 case SCI_GETEDGECOLUMN
:
7422 case SCI_SETEDGECOLUMN
:
7423 vs
.theEdge
= static_cast<int>(wParam
);
7424 InvalidateStyleRedraw();
7427 case SCI_GETEDGEMODE
:
7428 return vs
.edgeState
;
7430 case SCI_SETEDGEMODE
:
7431 vs
.edgeState
= static_cast<int>(wParam
);
7432 InvalidateStyleRedraw();
7435 case SCI_GETEDGECOLOUR
:
7436 return vs
.edgecolour
.AsLong();
7438 case SCI_SETEDGECOLOUR
:
7439 vs
.edgecolour
= ColourDesired(static_cast<long>(wParam
));
7440 InvalidateStyleRedraw();
7443 case SCI_GETDOCPOINTER
:
7444 return reinterpret_cast<sptr_t
>(pdoc
);
7446 case SCI_SETDOCPOINTER
:
7448 SetDocPointer(reinterpret_cast<Document
*>(lParam
));
7451 case SCI_CREATEDOCUMENT
: {
7452 Document
*doc
= new Document();
7454 return reinterpret_cast<sptr_t
>(doc
);
7457 case SCI_ADDREFDOCUMENT
:
7458 (reinterpret_cast<Document
*>(lParam
))->AddRef();
7461 case SCI_RELEASEDOCUMENT
:
7462 (reinterpret_cast<Document
*>(lParam
))->Release();
7465 case SCI_CREATELOADER
: {
7466 Document
*doc
= new Document();
7468 doc
->Allocate(static_cast<int>(wParam
));
7469 doc
->SetUndoCollection(false);
7470 return reinterpret_cast<sptr_t
>(static_cast<ILoader
*>(doc
));
7473 case SCI_SETMODEVENTMASK
:
7474 modEventMask
= static_cast<int>(wParam
);
7477 case SCI_GETMODEVENTMASK
:
7478 return modEventMask
;
7480 case SCI_CONVERTEOLS
:
7481 pdoc
->ConvertLineEnds(static_cast<int>(wParam
));
7482 SetSelection(sel
.MainCaret(), sel
.MainAnchor()); // Ensure selection inside document
7485 case SCI_SETLENGTHFORENCODE
:
7486 lengthForEncode
= static_cast<int>(wParam
);
7489 case SCI_SELECTIONISRECTANGLE
:
7490 return sel
.selType
== Selection::selRectangle
? 1 : 0;
7492 case SCI_SETSELECTIONMODE
: {
7495 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7496 sel
.selType
= Selection::selStream
;
7498 case SC_SEL_RECTANGLE
:
7499 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selRectangle
));
7500 sel
.selType
= Selection::selRectangle
;
7503 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selLines
));
7504 sel
.selType
= Selection::selLines
;
7507 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selThin
));
7508 sel
.selType
= Selection::selThin
;
7511 sel
.SetMoveExtends(!sel
.MoveExtends() || (sel
.selType
!= Selection::selStream
));
7512 sel
.selType
= Selection::selStream
;
7514 InvalidateWholeSelection();
7517 case SCI_GETSELECTIONMODE
:
7518 switch (sel
.selType
) {
7519 case Selection::selStream
:
7520 return SC_SEL_STREAM
;
7521 case Selection::selRectangle
:
7522 return SC_SEL_RECTANGLE
;
7523 case Selection::selLines
:
7524 return SC_SEL_LINES
;
7525 case Selection::selThin
:
7528 return SC_SEL_STREAM
;
7530 case SCI_GETLINESELSTARTPOSITION
:
7531 case SCI_GETLINESELENDPOSITION
: {
7532 SelectionSegment
segmentLine(SelectionPosition(pdoc
->LineStart(static_cast<int>(wParam
))),
7533 SelectionPosition(pdoc
->LineEnd(static_cast<int>(wParam
))));
7534 for (size_t r
=0; r
<sel
.Count(); r
++) {
7535 SelectionSegment portion
= sel
.Range(r
).Intersect(segmentLine
);
7536 if (portion
.start
.IsValid()) {
7537 return (iMessage
== SCI_GETLINESELSTARTPOSITION
) ? portion
.start
.Position() : portion
.end
.Position();
7540 return INVALID_POSITION
;
7543 case SCI_SETOVERTYPE
:
7544 inOverstrike
= wParam
!= 0;
7547 case SCI_GETOVERTYPE
:
7548 return inOverstrike
? 1 : 0;
7551 SetFocusState(wParam
!= 0);
7558 errorStatus
= static_cast<int>(wParam
);
7564 case SCI_SETMOUSEDOWNCAPTURES
:
7565 mouseDownCaptures
= wParam
!= 0;
7568 case SCI_GETMOUSEDOWNCAPTURES
:
7569 return mouseDownCaptures
;
7572 cursorMode
= static_cast<int>(wParam
);
7573 DisplayCursor(Window::cursorText
);
7579 case SCI_SETCONTROLCHARSYMBOL
:
7580 vs
.controlCharSymbol
= static_cast<int>(wParam
);
7581 InvalidateStyleRedraw();
7584 case SCI_GETCONTROLCHARSYMBOL
:
7585 return vs
.controlCharSymbol
;
7587 case SCI_SETREPRESENTATION
:
7588 reprs
.SetRepresentation(reinterpret_cast<const char *>(wParam
), CharPtrFromSPtr(lParam
));
7591 case SCI_GETREPRESENTATION
: {
7592 const Representation
*repr
= reprs
.RepresentationFromCharacter(
7593 reinterpret_cast<const char *>(wParam
), UTF8MaxBytes
);
7595 return StringResult(lParam
, repr
->stringRep
.c_str());
7600 case SCI_CLEARREPRESENTATION
:
7601 reprs
.ClearRepresentation(reinterpret_cast<const char *>(wParam
));
7604 case SCI_STARTRECORD
:
7605 recordingMacro
= true;
7608 case SCI_STOPRECORD
:
7609 recordingMacro
= false;
7612 case SCI_MOVECARETINSIDEVIEW
:
7613 MoveCaretInsideView();
7616 case SCI_SETFOLDMARGINCOLOUR
:
7617 vs
.foldmarginColour
= ColourOptional(wParam
, lParam
);
7618 InvalidateStyleRedraw();
7621 case SCI_SETFOLDMARGINHICOLOUR
:
7622 vs
.foldmarginHighlightColour
= ColourOptional(wParam
, lParam
);
7623 InvalidateStyleRedraw();
7626 case SCI_SETHOTSPOTACTIVEFORE
:
7627 vs
.hotspotColours
.fore
= ColourOptional(wParam
, lParam
);
7628 InvalidateStyleRedraw();
7631 case SCI_GETHOTSPOTACTIVEFORE
:
7632 return vs
.hotspotColours
.fore
.AsLong();
7634 case SCI_SETHOTSPOTACTIVEBACK
:
7635 vs
.hotspotColours
.back
= ColourOptional(wParam
, lParam
);
7636 InvalidateStyleRedraw();
7639 case SCI_GETHOTSPOTACTIVEBACK
:
7640 return vs
.hotspotColours
.back
.AsLong();
7642 case SCI_SETHOTSPOTACTIVEUNDERLINE
:
7643 vs
.hotspotUnderline
= wParam
!= 0;
7644 InvalidateStyleRedraw();
7647 case SCI_GETHOTSPOTACTIVEUNDERLINE
:
7648 return vs
.hotspotUnderline
? 1 : 0;
7650 case SCI_SETHOTSPOTSINGLELINE
:
7651 vs
.hotspotSingleLine
= wParam
!= 0;
7652 InvalidateStyleRedraw();
7655 case SCI_GETHOTSPOTSINGLELINE
:
7656 return vs
.hotspotSingleLine
? 1 : 0;
7658 case SCI_SETPASTECONVERTENDINGS
:
7659 convertPastes
= wParam
!= 0;
7662 case SCI_GETPASTECONVERTENDINGS
:
7663 return convertPastes
? 1 : 0;
7665 case SCI_GETCHARACTERPOINTER
:
7666 return reinterpret_cast<sptr_t
>(pdoc
->BufferPointer());
7668 case SCI_GETRANGEPOINTER
:
7669 return reinterpret_cast<sptr_t
>(pdoc
->RangePointer(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7671 case SCI_GETGAPPOSITION
:
7672 return pdoc
->GapPosition();
7674 case SCI_SETEXTRAASCENT
:
7675 vs
.extraAscent
= static_cast<int>(wParam
);
7676 InvalidateStyleRedraw();
7679 case SCI_GETEXTRAASCENT
:
7680 return vs
.extraAscent
;
7682 case SCI_SETEXTRADESCENT
:
7683 vs
.extraDescent
= static_cast<int>(wParam
);
7684 InvalidateStyleRedraw();
7687 case SCI_GETEXTRADESCENT
:
7688 return vs
.extraDescent
;
7690 case SCI_MARGINSETSTYLEOFFSET
:
7691 vs
.marginStyleOffset
= static_cast<int>(wParam
);
7692 InvalidateStyleRedraw();
7695 case SCI_MARGINGETSTYLEOFFSET
:
7696 return vs
.marginStyleOffset
;
7698 case SCI_SETMARGINOPTIONS
:
7699 marginOptions
= static_cast<int>(wParam
);
7702 case SCI_GETMARGINOPTIONS
:
7703 return marginOptions
;
7705 case SCI_MARGINSETTEXT
:
7706 pdoc
->MarginSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7709 case SCI_MARGINGETTEXT
: {
7710 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7711 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7714 case SCI_MARGINSETSTYLE
:
7715 pdoc
->MarginSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7718 case SCI_MARGINGETSTYLE
: {
7719 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7723 case SCI_MARGINSETSTYLES
:
7724 pdoc
->MarginSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7727 case SCI_MARGINGETSTYLES
: {
7728 const StyledText st
= pdoc
->MarginStyledText(static_cast<int>(wParam
));
7729 return BytesResult(lParam
, st
.styles
, st
.length
);
7732 case SCI_MARGINTEXTCLEARALL
:
7733 pdoc
->MarginClearAll();
7736 case SCI_ANNOTATIONSETTEXT
:
7737 pdoc
->AnnotationSetText(static_cast<int>(wParam
), CharPtrFromSPtr(lParam
));
7740 case SCI_ANNOTATIONGETTEXT
: {
7741 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7742 return BytesResult(lParam
, reinterpret_cast<const unsigned char *>(st
.text
), st
.length
);
7745 case SCI_ANNOTATIONGETSTYLE
: {
7746 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7750 case SCI_ANNOTATIONSETSTYLE
:
7751 pdoc
->AnnotationSetStyle(static_cast<int>(wParam
), static_cast<int>(lParam
));
7754 case SCI_ANNOTATIONSETSTYLES
:
7755 pdoc
->AnnotationSetStyles(static_cast<int>(wParam
), reinterpret_cast<const unsigned char *>(lParam
));
7758 case SCI_ANNOTATIONGETSTYLES
: {
7759 const StyledText st
= pdoc
->AnnotationStyledText(static_cast<int>(wParam
));
7760 return BytesResult(lParam
, st
.styles
, st
.length
);
7763 case SCI_ANNOTATIONGETLINES
:
7764 return pdoc
->AnnotationLines(static_cast<int>(wParam
));
7766 case SCI_ANNOTATIONCLEARALL
:
7767 pdoc
->AnnotationClearAll();
7770 case SCI_ANNOTATIONSETVISIBLE
:
7771 SetAnnotationVisible(static_cast<int>(wParam
));
7774 case SCI_ANNOTATIONGETVISIBLE
:
7775 return vs
.annotationVisible
;
7777 case SCI_ANNOTATIONSETSTYLEOFFSET
:
7778 vs
.annotationStyleOffset
= static_cast<int>(wParam
);
7779 InvalidateStyleRedraw();
7782 case SCI_ANNOTATIONGETSTYLEOFFSET
:
7783 return vs
.annotationStyleOffset
;
7785 case SCI_RELEASEALLEXTENDEDSTYLES
:
7786 vs
.ReleaseAllExtendedStyles();
7789 case SCI_ALLOCATEEXTENDEDSTYLES
:
7790 return vs
.AllocateExtendedStyles(static_cast<int>(wParam
));
7792 case SCI_ADDUNDOACTION
:
7793 pdoc
->AddUndoAction(static_cast<int>(wParam
), lParam
& UNDO_MAY_COALESCE
);
7796 case SCI_SETMOUSESELECTIONRECTANGULARSWITCH
:
7797 mouseSelectionRectangularSwitch
= wParam
!= 0;
7800 case SCI_GETMOUSESELECTIONRECTANGULARSWITCH
:
7801 return mouseSelectionRectangularSwitch
;
7803 case SCI_SETMULTIPLESELECTION
:
7804 multipleSelection
= wParam
!= 0;
7808 case SCI_GETMULTIPLESELECTION
:
7809 return multipleSelection
;
7811 case SCI_SETADDITIONALSELECTIONTYPING
:
7812 additionalSelectionTyping
= wParam
!= 0;
7816 case SCI_GETADDITIONALSELECTIONTYPING
:
7817 return additionalSelectionTyping
;
7819 case SCI_SETMULTIPASTE
:
7820 multiPasteMode
= static_cast<int>(wParam
);
7823 case SCI_GETMULTIPASTE
:
7824 return multiPasteMode
;
7826 case SCI_SETADDITIONALCARETSBLINK
:
7827 view
.additionalCaretsBlink
= wParam
!= 0;
7831 case SCI_GETADDITIONALCARETSBLINK
:
7832 return view
.additionalCaretsBlink
;
7834 case SCI_SETADDITIONALCARETSVISIBLE
:
7835 view
.additionalCaretsVisible
= wParam
!= 0;
7839 case SCI_GETADDITIONALCARETSVISIBLE
:
7840 return view
.additionalCaretsVisible
;
7842 case SCI_GETSELECTIONS
:
7845 case SCI_GETSELECTIONEMPTY
:
7848 case SCI_CLEARSELECTIONS
:
7850 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7854 case SCI_SETSELECTION
:
7855 sel
.SetSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7859 case SCI_ADDSELECTION
:
7860 sel
.AddSelection(SelectionRange(static_cast<int>(wParam
), static_cast<int>(lParam
)));
7861 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7865 case SCI_DROPSELECTIONN
:
7866 sel
.DropSelection(static_cast<int>(wParam
));
7867 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7871 case SCI_SETMAINSELECTION
:
7872 sel
.SetMain(static_cast<int>(wParam
));
7873 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7877 case SCI_GETMAINSELECTION
:
7880 case SCI_SETSELECTIONNCARET
:
7881 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7882 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7886 case SCI_GETSELECTIONNCARET
:
7887 return sel
.Range(wParam
).caret
.Position();
7889 case SCI_SETSELECTIONNANCHOR
:
7890 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7891 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7894 case SCI_GETSELECTIONNANCHOR
:
7895 return sel
.Range(wParam
).anchor
.Position();
7897 case SCI_SETSELECTIONNCARETVIRTUALSPACE
:
7898 sel
.Range(wParam
).caret
.SetVirtualSpace(static_cast<int>(lParam
));
7899 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7903 case SCI_GETSELECTIONNCARETVIRTUALSPACE
:
7904 return sel
.Range(wParam
).caret
.VirtualSpace();
7906 case SCI_SETSELECTIONNANCHORVIRTUALSPACE
:
7907 sel
.Range(wParam
).anchor
.SetVirtualSpace(static_cast<int>(lParam
));
7908 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7912 case SCI_GETSELECTIONNANCHORVIRTUALSPACE
:
7913 return sel
.Range(wParam
).anchor
.VirtualSpace();
7915 case SCI_SETSELECTIONNSTART
:
7916 sel
.Range(wParam
).anchor
.SetPosition(static_cast<int>(lParam
));
7917 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7921 case SCI_GETSELECTIONNSTART
:
7922 return sel
.Range(wParam
).Start().Position();
7924 case SCI_SETSELECTIONNEND
:
7925 sel
.Range(wParam
).caret
.SetPosition(static_cast<int>(lParam
));
7926 ContainerNeedsUpdate(SC_UPDATE_SELECTION
);
7930 case SCI_GETSELECTIONNEND
:
7931 return sel
.Range(wParam
).End().Position();
7933 case SCI_SETRECTANGULARSELECTIONCARET
:
7934 if (!sel
.IsRectangular())
7936 sel
.selType
= Selection::selRectangle
;
7937 sel
.Rectangular().caret
.SetPosition(static_cast<int>(wParam
));
7938 SetRectangularRange();
7942 case SCI_GETRECTANGULARSELECTIONCARET
:
7943 return sel
.Rectangular().caret
.Position();
7945 case SCI_SETRECTANGULARSELECTIONANCHOR
:
7946 if (!sel
.IsRectangular())
7948 sel
.selType
= Selection::selRectangle
;
7949 sel
.Rectangular().anchor
.SetPosition(static_cast<int>(wParam
));
7950 SetRectangularRange();
7954 case SCI_GETRECTANGULARSELECTIONANCHOR
:
7955 return sel
.Rectangular().anchor
.Position();
7957 case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7958 if (!sel
.IsRectangular())
7960 sel
.selType
= Selection::selRectangle
;
7961 sel
.Rectangular().caret
.SetVirtualSpace(static_cast<int>(wParam
));
7962 SetRectangularRange();
7966 case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE
:
7967 return sel
.Rectangular().caret
.VirtualSpace();
7969 case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7970 if (!sel
.IsRectangular())
7972 sel
.selType
= Selection::selRectangle
;
7973 sel
.Rectangular().anchor
.SetVirtualSpace(static_cast<int>(wParam
));
7974 SetRectangularRange();
7978 case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE
:
7979 return sel
.Rectangular().anchor
.VirtualSpace();
7981 case SCI_SETVIRTUALSPACEOPTIONS
:
7982 virtualSpaceOptions
= static_cast<int>(wParam
);
7985 case SCI_GETVIRTUALSPACEOPTIONS
:
7986 return virtualSpaceOptions
;
7988 case SCI_SETADDITIONALSELFORE
:
7989 vs
.selAdditionalForeground
= ColourDesired(static_cast<long>(wParam
));
7990 InvalidateStyleRedraw();
7993 case SCI_SETADDITIONALSELBACK
:
7994 vs
.selAdditionalBackground
= ColourDesired(static_cast<long>(wParam
));
7995 InvalidateStyleRedraw();
7998 case SCI_SETADDITIONALSELALPHA
:
7999 vs
.selAdditionalAlpha
= static_cast<int>(wParam
);
8000 InvalidateStyleRedraw();
8003 case SCI_GETADDITIONALSELALPHA
:
8004 return vs
.selAdditionalAlpha
;
8006 case SCI_SETADDITIONALCARETFORE
:
8007 vs
.additionalCaretColour
= ColourDesired(static_cast<long>(wParam
));
8008 InvalidateStyleRedraw();
8011 case SCI_GETADDITIONALCARETFORE
:
8012 return vs
.additionalCaretColour
.AsLong();
8014 case SCI_ROTATESELECTION
:
8016 InvalidateWholeSelection();
8019 case SCI_SWAPMAINANCHORCARET
:
8020 InvalidateSelection(sel
.RangeMain());
8021 sel
.RangeMain().Swap();
8024 case SCI_MULTIPLESELECTADDNEXT
:
8025 MultipleSelectAdd(addOne
);
8028 case SCI_MULTIPLESELECTADDEACH
:
8029 MultipleSelectAdd(addEach
);
8032 case SCI_CHANGELEXERSTATE
:
8033 pdoc
->ChangeLexerState(static_cast<int>(wParam
), static_cast<int>(lParam
));
8036 case SCI_SETIDENTIFIER
:
8037 SetCtrlID(static_cast<int>(wParam
));
8040 case SCI_GETIDENTIFIER
:
8043 case SCI_SETTECHNOLOGY
:
8044 // No action by default
8047 case SCI_GETTECHNOLOGY
:
8050 case SCI_COUNTCHARACTERS
:
8051 return pdoc
->CountCharacters(static_cast<int>(wParam
), static_cast<int>(lParam
));
8054 return DefWndProc(iMessage
, wParam
, lParam
);
8056 //Platform::DebugPrintf("end wnd proc\n");