diff options
| -rw-r--r-- | gtk/ScintillaGTK.cxx | 20 | ||||
| -rw-r--r-- | gtk/makefile | 2 | ||||
| -rw-r--r-- | gtk/scintilla.mak | 19 | ||||
| -rw-r--r-- | include/Scintilla.h | 36 | ||||
| -rw-r--r-- | include/Scintilla.iface | 71 | ||||
| -rw-r--r-- | src/Document.cxx | 4 | ||||
| -rw-r--r-- | src/Document.h | 1 | ||||
| -rw-r--r-- | src/Editor.cxx | 1767 | ||||
| -rw-r--r-- | src/Editor.h | 46 | ||||
| -rw-r--r-- | src/PositionCache.cxx | 22 | ||||
| -rw-r--r-- | src/PositionCache.h | 6 | ||||
| -rw-r--r-- | src/ScintillaBase.cxx | 41 | ||||
| -rw-r--r-- | src/Selection.cxx | 345 | ||||
| -rw-r--r-- | src/Selection.h | 142 | ||||
| -rw-r--r-- | vcbuild/SciLexer.dsp | 4 | ||||
| -rw-r--r-- | win32/ScintillaWin.cxx | 31 | ||||
| -rw-r--r-- | win32/makefile | 4 | ||||
| -rw-r--r-- | win32/scintilla.mak | 18 | 
18 files changed, 1763 insertions, 816 deletions
| diff --git a/gtk/ScintillaGTK.cxx b/gtk/ScintillaGTK.cxx index e506dd1b4..9d7cc02ee 100644 --- a/gtk/ScintillaGTK.cxx +++ b/gtk/ScintillaGTK.cxx @@ -44,6 +44,7 @@  #include "Decoration.h"  #include "CharClassify.h"  #include "Document.h" +#include "Selection.h"  #include "PositionCache.h"  #include "Editor.h"  #include "SString.h" @@ -1345,7 +1346,7 @@ void ScintillaGTK::CopyToClipboard(const SelectionText &selectedText) {  }  void ScintillaGTK::Copy() { -	if (currentPos != anchor) { +	if (!sel.Empty()) {  #ifndef USE_GTK_CLIPBOARD  		CopySelectionRange(©Text);  		gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)), @@ -1357,7 +1358,7 @@ void ScintillaGTK::Copy() {  		StoreOnClipboard(clipText);  #endif  #if PLAT_GTK_WIN32 -		if (selType == selRectangle) { +		if (sel.IsRectangular()) {  			::OpenClipboard(NULL);  			::SetClipboardData(cfColumnSelect, 0);  			::CloseClipboard(); @@ -1433,7 +1434,7 @@ bool ScintillaGTK::OwnPrimarySelection() {  void ScintillaGTK::ClaimSelection() {  	// X Windows has a 'primary selection' as well as the clipboard.  	// Whenever the user selects some text, we become the primary selection -	if (currentPos != anchor && GTK_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain)))) { +	if (!sel.Empty() && GTK_WIDGET_REALIZED(GTK_WIDGET(PWidget(wMain)))) {  		primarySelection = true;  		gtk_selection_owner_set(GTK_WIDGET(PWidget(wMain)),  		                        GDK_SELECTION_PRIMARY, GDK_CURRENT_TIME); @@ -1520,10 +1521,11 @@ void ScintillaGTK::ReceivedSelection(GtkSelectionData *selection_data) {  				int selStart = SelectionStart();  				if (selText.rectangular) { -					PasteRectangular(selStart, selText.s, selText.len); +					PasteRectangular(SelectionPosition(selStart), selText.s, selText.len);  				} else { -					pdoc->InsertString(currentPos, selText.s, selText.len); -					SetEmptySelection(currentPos + selText.len); +					int caretMain = sel.MainCaret(); +					pdoc->InsertString(caretMain, selText.s, selText.len); +					SetEmptySelection(caretMain + selText.len);  				}  				pdoc->EndUndoAction();  				EnsureCaretVisible(); @@ -2222,7 +2224,7 @@ void ScintillaGTK::PreeditChangedThis() {  			gint x, y;  			gdk_window_get_origin((PWidget(wText))->window, &x, &y); -			Point pt = LocationFromPosition(currentPos); +			Point pt = LocationFromPosition(sel.MainCaret());  			if (pt.x < 0)  				pt.x = 0;  			if (pt.y < 0) @@ -2309,7 +2311,7 @@ void ScintillaGTK::Draw(GtkWidget *widget, GdkRectangle *area) {  		}  #ifdef INTERNATIONAL_INPUT -		Point pt = sciThis->LocationFromPosition(sciThis->currentPos); +		Point pt = sciThis->LocationFromPosition(sciThis->sel.MainCaret());  		pt.y += sciThis->vs.lineHeight - 2;  		if (pt.x < 0) pt.x = 0;  		if (pt.y < 0) pt.y = 0; @@ -2569,7 +2571,7 @@ void ScintillaGTK::DragDataGet(GtkWidget *widget, GdkDragContext *context,  	ScintillaGTK *sciThis = ScintillaFromWidget(widget);  	try {  		sciThis->dragWasDropped = true; -		if (sciThis->currentPos != sciThis->anchor) { +		if (!sciThis->sel.Empty()) {  			sciThis->GetSelection(selection_data, info, &sciThis->drag);  		}  		if (context->action == GDK_ACTION_MOVE) { diff --git a/gtk/makefile b/gtk/makefile index 87c43aa43..8d01390d8 100644 --- a/gtk/makefile +++ b/gtk/makefile @@ -88,7 +88,7 @@ $(COMPLIB): DocumentAccessor.o WindowAccessor.o KeyWords.o StyleContext.o \  	CharClassify.o Decoration.o Document.o PerLine.o CallTip.o \  	ScintillaBase.o ContractionState.o Editor.o ExternalLexer.o PropSet.o PlatGTK.o \  	KeyMap.o LineMarker.o PositionCache.o ScintillaGTK.o CellBuffer.o ViewStyle.o \ -	RESearch.o RunStyles.o Style.o Indicator.o AutoComplete.o UniConversion.o XPM.o \ +	RESearch.o RunStyles.o Selection.o Style.o Indicator.o AutoComplete.o UniConversion.o XPM.o \  	$(MARSHALLER) $(LEXOBJS)  	$(AR) rc $@ $^  	$(RANLIB) $@ diff --git a/gtk/scintilla.mak b/gtk/scintilla.mak index b993c6069..78634aaae 100644 --- a/gtk/scintilla.mak +++ b/gtk/scintilla.mak @@ -135,6 +135,7 @@ SOBJS=\  	$(DIR_O)\PropSet.obj \  	$(DIR_O)\ScintillaBase.obj \  	$(DIR_O)\ScintillaGTK.obj \ +	$(DIR_O)\Selection.obj \  	$(DIR_O)\Style.obj \  	$(DIR_O)\UniConversion.obj \  	$(DIR_O)\ViewStyle.obj \ @@ -245,6 +246,7 @@ LOBJS=\  	$(DIR_O)\PropSet.obj \  	$(DIR_O)\ScintillaBaseL.obj \  	$(DIR_O)\ScintillaGTKL.obj \ +	$(DIR_O)\Selection.obj \  	$(DIR_O)\Style.obj \  	$(DIR_O)\StyleContext.obj \  	$(DIR_O)\UniConversion.obj \ @@ -341,7 +343,7 @@ $(DIR_O)\Editor.obj: ../src/Editor.cxx ../include/Platform.h ../include/Scintill    ../src/Partitioning.h ../src/CellBuffer.h ../src/KeyMap.h \    ../src/RunStyles.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \    ../src/Style.h ../src/ViewStyle.h ../src/CharClassify.h \ -  ../src/Document.h ../src/Editor.h ../src/PositionCache.h +  ../src/Document.h ../src/Editor.h ../src/Selection.h ../src/PositionCache.h  $(DIR_O)\ExternalLexer.obj: ../src/ExternalLexer.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/SciLexer.h ../include/PropSet.h \ @@ -530,7 +532,7 @@ $(DIR_O)\PositionCache.obj: ../src/Editor.cxx ../include/Platform.h ../include/S    ../src/Partitioning.h ../src/CellBuffer.h ../src/KeyMap.h \    ../src/RunStyles.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \    ../src/Style.h ../src/ViewStyle.h ../src/CharClassify.h \ -  ../src/Decoration.h ../src/Document.h ../src/Editor.h ../src/PositionCache.h +  ../src/Decoration.h ../src/Document.h ../src/Editor.h ../src/Selection.h ../src/PositionCache.h  $(DIR_O)\PropSet.obj: ../src/PropSet.cxx ../include/Platform.h ../include/PropSet.h \    ../include/SString.h @@ -548,7 +550,7 @@ $(DIR_O)\ScintillaBase.obj: ../src/ScintillaBase.cxx ../include/Platform.h \    ../src/CallTip.h ../src/KeyMap.h ../src/Indicator.h ../src/XPM.h \    ../src/LineMarker.h ../src/Style.h ../src/ViewStyle.h \    ../src/AutoComplete.h ../src/CharClassify.h ../src/Document.h \ -  ../src/Editor.h ../src/ScintillaBase.h +  ../src/Editor.h ../src/Selection.h ../src/ScintillaBase.h  $(DIR_O)\ScintillaBaseL.obj: ../src/ScintillaBase.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/PropSet.h ../include/SString.h \ @@ -557,7 +559,7 @@ $(DIR_O)\ScintillaBaseL.obj: ../src/ScintillaBase.cxx ../include/Platform.h \    ../src/CallTip.h ../src/KeyMap.h ../src/Indicator.h ../src/XPM.h \    ../src/LineMarker.h ../src/Style.h ../src/ViewStyle.h \    ../src/AutoComplete.h ../src/CharClassify.h ../src/Document.h \ -  ../src/Editor.h ../src/ScintillaBase.h +  ../src/Editor.h ../src/Selection.h ../src/ScintillaBase.h  $(DIR_O)\ScintillaGTK.obj: ScintillaGTK.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/SString.h ../src/ContractionState.h \ @@ -566,7 +568,7 @@ $(DIR_O)\ScintillaGTK.obj: ScintillaGTK.cxx ../include/Platform.h \    ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \    ../src/AutoComplete.h ../src/ViewStyle.h ../src/CharClassify.h \    ../src/Document.h ../src/Editor.h ../src/ScintillaBase.h \ -  ../src/UniConversion.h +  ../src/Selection.h ../src/UniConversion.h  $(DIR_O)\ScintillaGTKL.obj: ScintillaGTK.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/SString.h ../src/ContractionState.h \ @@ -575,7 +577,7 @@ $(DIR_O)\ScintillaGTKL.obj: ScintillaGTK.cxx ../include/Platform.h \    ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \    ../src/AutoComplete.h ../src/ViewStyle.h ../src/CharClassify.h \    ../src/Document.h ../src/Editor.h ../src/ScintillaBase.h \ -  ../src/UniConversion.h +  ../src/Selection.h ../src/UniConversion.h  $(DIR_O)\ScintillaGTKS.obj: ScintillaGTK.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/SString.h ../src/ContractionState.h \ @@ -584,7 +586,10 @@ $(DIR_O)\ScintillaGTKS.obj: ScintillaGTK.cxx ../include/Platform.h \    ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \    ../src/AutoComplete.h ../src/ViewStyle.h ../src/CharClassify.h \    ../src/Document.h ../src/Editor.h ../src/ScintillaBase.h \ -  ../src/UniConversion.h +  ../src/Selection.h ../src/UniConversion.h + +$(DIR_O)\Selection.obj: ../src/Selection.cxx ../include/Platform.h ../include/Scintilla.h \ +  ../src/Selection.h  $(DIR_O)\Style.obj: ../src/Style.cxx ../include/Platform.h ../include/Scintilla.h \    ../src/Style.h diff --git a/include/Scintilla.h b/include/Scintilla.h index 476fa0506..d4980577d 100644 --- a/include/Scintilla.h +++ b/include/Scintilla.h @@ -617,6 +617,7 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,  #define SC_SEL_STREAM 0  #define SC_SEL_RECTANGLE 1  #define SC_SEL_LINES 2 +#define SC_SEL_THIN 3  #define SCI_SETSELECTIONMODE 2422  #define SCI_GETSELECTIONMODE 2423  #define SCI_GETLINESELSTARTPOSITION 2424 @@ -713,6 +714,41 @@ typedef sptr_t (*SciFnDirect)(sptr_t ptr, unsigned int iMessage, uptr_t wParam,  #define SCI_ADDUNDOACTION 2560  #define SCI_CHARPOSITIONFROMPOINT 2561  #define SCI_CHARPOSITIONFROMPOINTCLOSE 2562 +#define SCI_SETMULTILINECARET 2563 +#define SCI_GETMULTILINECARET 2564 +#define SCI_SETMULTILINECARETBLINKS 2565 +#define SCI_GETMULTILINECARETBLINKS 2566 +#define SCI_GETSELECTIONS 2570 +#define SCI_CLEARSELECTIONS 2571 +#define SCI_SETSELECTION 2572 +#define SCI_ADDSELECTION 2573 +#define SCI_SETMAINSELECTION 2574 +#define SCI_GETMAINSELECTION 2575 +#define SCI_SETSELECTIONNCARET 2576 +#define SCI_GETSELECTIONNCARET 2577 +#define SCI_SETSELECTIONNANCHOR 2578 +#define SCI_GETSELECTIONNANCHOR 2579 +#define SCI_SETSELECTIONNCARETVIRTUALSPACE 2580 +#define SCI_GETSELECTIONNCARETVIRTUALSPACE 2581 +#define SCI_SETSELECTIONNANCHORVIRTUALSPACE 2582 +#define SCI_GETSELECTIONNANCHORVIRTUALSPACE 2583 +#define SCI_SETSELECTIONNSTART 2584 +#define SCI_GETSELECTIONNSTART 2585 +#define SCI_SETSELECTIONNEND 2586 +#define SCI_GETSELECTIONNEND 2587 +#define SCI_SETRECTANGULARSELECTIONCARET 2588 +#define SCI_GETRECTANGULARSELECTIONCARET 2589 +#define SCI_SETRECTANGULARSELECTIONANCHOR 2590 +#define SCI_GETRECTANGULARSELECTIONANCHOR 2591 +#define SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE 2592 +#define SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE 2593 +#define SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE 2594 +#define SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE 2595 +#define SCVS_NONE 0 +#define SCVS_RECTANGULARSELECTION 1 +#define SCVS_USERACCESSIBLE 2 +#define SCI_SETVIRTUALSPACEOPTIONS 2596 +#define SCI_GETVIRTUALSPACEOPTIONS 2597  #define SCI_STARTRECORD 3001  #define SCI_STOPRECORD 3002  #define SCI_SETLEXER 4001 diff --git a/include/Scintilla.iface b/include/Scintilla.iface index 91d19ef85..8abafb69a 100644 --- a/include/Scintilla.iface +++ b/include/Scintilla.iface @@ -1637,8 +1637,9 @@ enu SelectionMode=SC_SEL_  val SC_SEL_STREAM=0  val SC_SEL_RECTANGLE=1  val SC_SEL_LINES=2 +val SC_SEL_THIN=3 -# Set the selection mode to stream (SC_SEL_STREAM) or rectangular (SC_SEL_RECTANGLE) or +# Set the selection mode to stream (SC_SEL_STREAM) or rectangular (SC_SEL_RECTANGLE/SC_SEL_THIN) or  # by lines (SC_SEL_LINES).  set void SetSelectionMode=2422(int mode,) @@ -1926,6 +1927,74 @@ fun position CharPositionFromPoint=2561(int x, int y)  # Return INVALID_POSITION if not close to text.  fun position CharPositionFromPointClose=2562(int x, int y) +# Set whether the caret will show on multiple lines for a rectangular selection +set void SetMultiLineCaret=2563(bool multiLine,) + +# Whether the caret will show on multiple lines for a rectangular selection +get bool GetMultiLineCaret=2564(,) + +# Set whether the multiline caret will blink +set void SetMultiLineCaretBlinks=2565(bool multiLineBlinks,) + +# Whether the multiline caret will blink +get bool GetMultiLineCaretBlinks=2566(,) + +# How many selections are there? +get int GetSelections=2570(,) + +# Add a selection +fun void ClearSelections=2571(,) + +# Set a simple selection +fun int SetSelection=2572(int currentPos,int anchor) + +# Add a selection +fun int AddSelection=2573(int currentPos,int anchor) + +# Set the main selection +set void SetMainSelection=2574(int selection,) + +# Which selection is the main selection +get int GetMainSelection=2575(,) + +set void SetSelectionNCaret=2576(int selection, position pos) +get position GetSelectionNCaret=2577(int selection,) +set void SetSelectionNAnchor=2578(int selection, position posAnchor) +get position GetSelectionNAnchor=2579(int selection,) +set void SetSelectionNCaretVirtualSpace=2580(int selection, int space) +get int GetSelectionNCaretVirtualSpace=2581(int selection,) +set void SetSelectionNAnchorVirtualSpace=2582(int selection, int space) +get int GetSelectionNAnchorVirtualSpace=2583(int selection,) + +# Sets the position that starts the selection - this becomes the anchor. +set void SetSelectionNStart=2584(int selection, position pos) + +# Returns the position at the start of the selection. +get position GetSelectionNStart=2585(,) + +# Sets the position that ends the selection - this becomes the currentPosition. +set void SetSelectionNEnd=2586(position pos,) + +# Returns the position at the end of the selection. +get position GetSelectionNEnd=2587(,) + +set void SetRectangularSelectionCaret=2588(position pos,) +get position GetRectangularSelectionCaret=2589(,) +set void SetRectangularSelectionAnchor=2590(position posAnchor,) +get position GetRectangularSelectionAnchor=2591(,) +set void SetRectangularSelectionCaretVirtualSpace=2592(int space,) +get int GetRectangularSelectionCaretVirtualSpace=2593(,) +set void SetRectangularSelectionAnchorVirtualSpace=2594(int space,) +get int GetRectangularSelectionAnchorVirtualSpace=2595(,) + +enu VirtualSpace=SCVS_ +val SCVS_NONE=0 +val SCVS_RECTANGULARSELECTION=1 +val SCVS_USERACCESSIBLE=2 + +set void SetVirtualSpaceOptions=2596(int virtualSpace,) +get int GetVirtualSpaceOptions=2597(,) +  # Start notifying the container of all key presses and commands.  fun void StartRecord=3001(,) diff --git a/src/Document.cxx b/src/Document.cxx index 211d19315..eca4511de 100644 --- a/src/Document.cxx +++ b/src/Document.cxx @@ -217,6 +217,10 @@ int Document::LineEndPosition(int position) const {  	return LineEnd(LineFromPosition(position));  } +bool Document::IsLineEndPosition(int position) const { +	return LineEnd(LineFromPosition(position)) == position; +} +  int Document::VCHomePosition(int position) const {  	int line = LineFromPosition(position);  	int startPosition = LineStart(line); diff --git a/src/Document.h b/src/Document.h index 58615bb19..4751cd2c8 100644 --- a/src/Document.h +++ b/src/Document.h @@ -239,6 +239,7 @@ public:  	int LineStart(int line) const;  	int LineEnd(int line) const;  	int LineEndPosition(int position) const; +	bool IsLineEndPosition(int position) const;  	int VCHomePosition(int position) const;  	int SetLevel(int line, int level); diff --git a/src/Editor.cxx b/src/Editor.cxx index 6f7e6eb4b..7af0e7325 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -28,6 +28,7 @@  #include "CharClassify.h"  #include "Decoration.h"  #include "Document.h" +#include "Selection.h"  #include "PositionCache.h"  #include "Editor.h" @@ -116,10 +117,6 @@ Editor::Editor() {  	lineAnchor = 0;  	originalAnchorPos = 0; -	selType = selStream; -	moveExtendsSelection = false; -	xStartSelect = 0; -	xEndSelect = 0;  	primarySelection = true;  	caretXPolicy = CARET_SLOP | CARET_EVEN; @@ -139,6 +136,10 @@ Editor::Editor() {  	verticalScrollBarVisible = true;  	endAtLastLine = true;  	caretSticky = false; +	multiLineCaret = false; +	multiLineCaretBlinks = true; +	virtualSpaceOptions = SCVS_NONE; +	virtualSpaceOptions = SCVS_USERACCESSIBLE;  	pixmapLine = Surface::Allocate();  	pixmapSelMargin = Surface::Allocate(); @@ -146,9 +147,6 @@ Editor::Editor() {  	pixmapIndentGuide = Surface::Allocate();  	pixmapIndentGuideHighlight = Surface::Allocate(); -	currentPos = 0; -	anchor = 0; -  	targetStart = 0;  	targetEnd = 0;  	searchFlags = 0; @@ -227,10 +225,7 @@ void Editor::InvalidateStyleData() {  	palette.Release();  	llc.Invalidate(LineLayout::llInvalid);  	posCache.Clear(); -	if (selType == selRectangle) { -		xStartSelect = XFromPosition(anchor); -		xEndSelect = XFromPosition(currentPos); -	} +	SetRectangularRange();  }  void Editor::InvalidateStyleRedraw() { @@ -347,91 +342,18 @@ public:  	}  }; -#ifdef SCI_NAMESPACE -namespace Scintilla { -#endif - -/** - * Allows to iterate through the lines of a selection. - * Althought it can be called for a stream selection, in most cases - * it is inefficient and it should be used only for - * a rectangular or a line selection. - */ -class SelectionLineIterator { -private: -	Editor *ed; -	int line;	///< Current line within the iteration. -	bool forward;	///< True if iterating by increasing line number, false otherwise. -	int selStart, selEnd;	///< Positions of the start and end of the selection relative to the start of the document. -	int minX, maxX;	///< Left and right of selection rectangle. - -public: -	int lineStart, lineEnd;	///< Line numbers, first and last lines of the selection. -	int startPos, endPos;	///< Positions of the beginning and end of the selection on the current line. - -	void Reset() { -		if (forward) { -			line = lineStart; -		} else { -			line = lineEnd; -		} -	} - -	SelectionLineIterator(Editor *ed_, bool forward_ = true) : line(0), startPos(0), endPos(0) { -		ed = ed_; -		forward = forward_; -		selStart = ed->SelectionStart(); -		selEnd = ed->SelectionEnd(); -		lineStart = ed->pdoc->LineFromPosition(selStart); -		lineEnd = ed->pdoc->LineFromPosition(selEnd); -		// Left of rectangle -		minX = Platform::Minimum(ed->xStartSelect, ed->xEndSelect); -		// Right of rectangle -		maxX = Platform::Maximum(ed->xStartSelect, ed->xEndSelect); -		Reset(); -	} -	~SelectionLineIterator() {} - -	void SetAt(int line) { -		if (line < lineStart || line > lineEnd) { -			startPos = endPos = INVALID_POSITION; -		} else { -			if (ed->selType == ed->selRectangle) { -				// Measure line and return character closest to minX -				startPos = ed->PositionFromLineX(line, minX); -				// Measure line and return character closest to maxX -				endPos = ed->PositionFromLineX(line, maxX); -			} else if (ed->selType == ed->selLines) { -				startPos = ed->pdoc->LineStart(line); -				endPos = ed->pdoc->LineStart(line + 1); -			} else {	// Stream selection, here only for completion -				if (line == lineStart) { -					startPos = selStart; -				} else { -					startPos = ed->pdoc->LineStart(line); -				} -				if (line == lineEnd) { -					endPos = selEnd; -				} else { -					endPos = ed->pdoc->LineStart(line + 1); -				} -			} -		} -	} -	bool Iterate() { -		SetAt(line); -		if (forward) { -			line++; -		} else { -			line--; -		} -		return startPos != INVALID_POSITION; +SelectionPosition Editor::ClampPositionIntoDocument(SelectionPosition sp) const { +	if (sp.Position() < 0) { +		return SelectionPosition(0); +	} else if (sp.Position() > pdoc->Length()) { +		return SelectionPosition(pdoc->Length()); +	} else { +		// If not at end of line then set offset to 0 +		if (!pdoc->IsLineEndPosition(sp.Position()))  +			sp.SetVirtualSpace(0); +		return sp;  	} -}; - -#ifdef SCI_NAMESPACE  } -#endif  Point Editor::LocationFromPosition(int pos) {  	Point pt; @@ -478,6 +400,11 @@ int Editor::XFromPosition(int pos) {  	return pt.x - vs.fixedColumnWidth + xOffset;  } +int Editor::XFromPosition(SelectionPosition sp) { +	Point pt = LocationFromPosition(sp.Position()); +	return pt.x + sp.VirtualSpace() * vs.spaceWidth - vs.fixedColumnWidth + xOffset; +} +  int Editor::LineFromLocation(Point pt) {  	return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine);  } @@ -487,16 +414,16 @@ void Editor::SetTopLine(int topLineNew) {  	posTopLine = pdoc->LineStart(cs.DocFromDisplay(topLine));  } -int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) { +SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition, bool virtualSpace) {  	RefreshStyleData();  	if (canReturnInvalid) {  		PRectangle rcClient = GetTextRectangle();  		if (!rcClient.Contains(pt)) -			return INVALID_POSITION; +			return SelectionPosition(INVALID_POSITION);  		if (pt.x < vs.fixedColumnWidth) -			return INVALID_POSITION; +			return SelectionPosition(INVALID_POSITION);  		if (pt.y < 0) -			return INVALID_POSITION; +			return SelectionPosition(INVALID_POSITION);  	}  	pt.x = pt.x - vs.fixedColumnWidth + xOffset;  	int visibleLine = pt.y / vs.lineHeight + topLine; @@ -507,11 +434,11 @@ int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosit  		visibleLine = 0;  	int lineDoc = cs.DocFromDisplay(visibleLine);  	if (canReturnInvalid && (lineDoc < 0)) -		return INVALID_POSITION; +		return SelectionPosition(INVALID_POSITION);  	if (lineDoc >= pdoc->LinesTotal()) -		return canReturnInvalid ? INVALID_POSITION : pdoc->Length(); +		return SelectionPosition(canReturnInvalid ? INVALID_POSITION : pdoc->Length());  	unsigned int posLineStart = pdoc->LineStart(lineDoc); -	int retVal = canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart); +	SelectionPosition retVal(canReturnInvalid ? INVALID_POSITION : static_cast<int>(posLineStart));  	AutoSurface surface(this);  	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc));  	if (surface && ll) { @@ -531,29 +458,38 @@ int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosit  			while (i < lineEnd) {  				if (charPosition) {  					if ((pt.x + subLineStart) < (ll->positions[i + 1])) { -						return pdoc->MovePositionOutsideChar(i + posLineStart, 1); +						return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));  					}  				} else {  					if ((pt.x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { -						return pdoc->MovePositionOutsideChar(i + posLineStart, 1); +						return SelectionPosition(pdoc->MovePositionOutsideChar(i + posLineStart, 1));  					}  				}  				i++;  			} -			if (canReturnInvalid) { +			if (virtualSpace) { +				const int spaceWidth = static_cast<int>(vs.spaceWidth); +				int spaceOffset = (pt.x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) /  +					spaceWidth; +				return SelectionPosition(lineEnd + posLineStart, spaceOffset); +			} else if (canReturnInvalid) {  				if (pt.x < (ll->positions[lineEnd] - subLineStart)) { -					return pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1); +					return SelectionPosition(pdoc->MovePositionOutsideChar(lineEnd + posLineStart, 1));  				}  			} else { -				return lineEnd + posLineStart; +				return SelectionPosition(lineEnd + posLineStart);  			}  		}  		if (!canReturnInvalid) -			return ll->numCharsInLine + posLineStart; +			return SelectionPosition(ll->numCharsInLine + posLineStart);  	}  	return retVal;  } +int Editor::PositionFromLocation(Point pt, bool canReturnInvalid, bool charPosition) { +	return SPositionFromLocation(pt, canReturnInvalid, charPosition, false).Position(); +} +  /**   * Find the document position corresponding to an x coordinate on a particular document line.   * Ensure is between whole characters when document is in multi-byte or UTF-8 mode. @@ -592,6 +528,45 @@ int Editor::PositionFromLineX(int lineDoc, int x) {  }  /** + * Find the document position corresponding to an x coordinate on a particular document line. + * Ensure is between whole characters when document is in multi-byte or UTF-8 mode. + */ +SelectionPosition Editor::SPositionFromLineX(int lineDoc, int x) { +	RefreshStyleData(); +	if (lineDoc >= pdoc->LinesTotal()) +		return SelectionPosition(pdoc->Length()); +	//Platform::DebugPrintf("Position of (%d,%d) line = %d top=%d\n", pt.x, pt.y, line, topLine); +	AutoSurface surface(this); +	AutoLineLayout ll(llc, RetrieveLineLayout(lineDoc)); +	int retVal = 0; +	if (surface && ll) { +		unsigned int posLineStart = pdoc->LineStart(lineDoc); +		LayoutLine(lineDoc, surface, vs, ll, wrapWidth); +		int subLine = 0; +		int lineStart = ll->LineStart(subLine); +		int lineEnd = ll->LineLastVisible(subLine); +		int subLineStart = ll->positions[lineStart]; + +		if (ll->wrapIndent != 0) { +			if (lineStart != 0)	// Wrapped +				x -= ll->wrapIndent; +		} +		int i = ll->FindBefore(x + subLineStart, lineStart, lineEnd); +		while (i < lineEnd) { +			if ((x + subLineStart) < ((ll->positions[i] + ll->positions[i + 1]) / 2)) { +				retVal = pdoc->MovePositionOutsideChar(i + posLineStart, 1); +				return SelectionPosition(retVal); +			} +			i++; +		} +		const int spaceWidth = static_cast<int>(vs.spaceWidth); +		int spaceOffset = (x + subLineStart - ll->positions[lineEnd] + spaceWidth / 2) / spaceWidth; +		return SelectionPosition(lineEnd + posLineStart, spaceOffset); +	} +	return SelectionPosition(retVal); +} + +/**   * If painting then abandon the painting because a wider redraw is needed.   * @return true if calling code should stop drawing.   */ @@ -676,80 +651,124 @@ void Editor::InvalidateRange(int start, int end) {  }  int Editor::CurrentPosition() { -	return currentPos; +	return sel.MainCaret();  }  bool Editor::SelectionEmpty() { -	return anchor == currentPos; +	return sel.Empty();  }  int Editor::SelectionStart() { -	return Platform::Minimum(currentPos, anchor); +	return sel.RangeMain().Start().Position();  }  int Editor::SelectionEnd() { -	return Platform::Maximum(currentPos, anchor); +	return sel.RangeMain().End().Position();  }  void Editor::SetRectangularRange() { -	if (selType == selRectangle) { -		xStartSelect = XFromPosition(anchor); -		xEndSelect = XFromPosition(currentPos); +	if (sel.IsRectangular()) { +		int xAnchor = XFromPosition(sel.Rectangular().anchor); +		int xCaret = XFromPosition(sel.Rectangular().caret); +		bool anchorTop = sel.Rectangular().anchor < sel.Rectangular().caret; +		bool anchorLeft = xAnchor < xCaret; +		if (sel.selType == Selection::selThin) { +			xCaret = xAnchor; +		} +		SelectionPosition selStart = sel.Rectangular().Start(); +		SelectionPosition selEnd = sel.Rectangular().End(); +		int lineStart = pdoc->LineFromPosition(selStart.Position()); +		int lineEnd = pdoc->LineFromPosition(selEnd.Position()); +		// Left of rectangle +		int minX = Platform::Minimum(xAnchor, xCaret); +		// Right of rectangle +		int maxX = Platform::Maximum(xAnchor, xCaret); +		sel.EmptyRanges(); +		if (anchorTop) { +			for (int line=lineStart; line<=lineEnd; line++) { +				SelectionPosition spMin(SPositionFromLineX(line, minX)); +				SelectionPosition spMax(SPositionFromLineX(line, maxX)); +				sel.AddSelection(spMin, spMax, anchorLeft); +			} +		} else { +			for (int line=lineEnd; line>=lineStart; line--) { +				SelectionPosition spMin(SPositionFromLineX(line, minX)); +				SelectionPosition spMax(SPositionFromLineX(line, maxX)); +				sel.AddSelection(spMin, spMax, anchorLeft); +			} +		}  	}  } -void Editor::InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection) { -	if (anchor != anchor_ || selType == selRectangle) { +void Editor::InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection) { +	if (sel.Count() > 1 || !(sel.RangeMain().anchor == newMain.anchor) || sel.IsRectangular()) {  		invalidateWholeSelection = true;  	} -	int firstAffected = currentPos; +	int firstAffected = newMain.Start().Position(); +	// +1 for lastAffected ensures caret repainted +	int lastAffected = Platform::Maximum(newMain.caret.Position()+1, newMain.anchor.Position());  	if (invalidateWholeSelection) { -		if (firstAffected > anchor) -			firstAffected = anchor; -		if (firstAffected > anchor_) -			firstAffected = anchor_; -	} -	if (firstAffected > currentPos_) -		firstAffected = currentPos_; -	int lastAffected = currentPos; -	if (invalidateWholeSelection) { -		if (lastAffected < anchor) -			lastAffected = anchor; -		if (lastAffected < anchor_) -			lastAffected = anchor_; +		for (size_t r=0; r<sel.Count(); r++) { +			firstAffected = Platform::Minimum(firstAffected, sel.Range(r).caret.Position()); +			firstAffected = Platform::Minimum(firstAffected, sel.Range(r).anchor.Position()); +			lastAffected = Platform::Maximum(lastAffected, sel.Range(r).caret.Position()+1); +			lastAffected = Platform::Maximum(lastAffected, sel.Range(r).anchor.Position()); +		}  	} -	if (lastAffected < (currentPos_ + 1))	// +1 ensures caret repainted -		lastAffected = (currentPos_ + 1);  	needUpdateUI = true;  	InvalidateRange(firstAffected, lastAffected);  } -void Editor::SetSelection(int currentPos_, int anchor_) { -	currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); -	anchor_ = pdoc->ClampPositionIntoDocument(anchor_); -	if ((currentPos != currentPos_) || (anchor != anchor_)) { -		InvalidateSelection(currentPos_, anchor_, true); -		currentPos = currentPos_; -		anchor = anchor_; +void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_) { +	SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_),  +		ClampPositionIntoDocument(anchor_)); +	if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { +		InvalidateSelection(rangeNew);  	} +	sel.RangeMain() = rangeNew;  	SetRectangularRange();  	ClaimSelection();  } +void Editor::SetSelection(int currentPos_, int anchor_) { +	SetSelection(SelectionPosition(currentPos_), SelectionPosition(anchor_)); +} + +// Just move the caret on the main selection +void Editor::SetSelection(SelectionPosition currentPos_) { +	currentPos_ = ClampPositionIntoDocument(currentPos_); +	if (sel.Count() > 1 || !(sel.RangeMain().caret == currentPos_)) { +		InvalidateSelection(SelectionRange(currentPos_)); +	} +	if (sel.IsRectangular()) { +		sel.Rectangular() = +			SelectionRange(SelectionPosition(currentPos_), sel.Rectangular().anchor); +		SetRectangularRange(); +	} else { +		sel.RangeMain() = +			SelectionRange(SelectionPosition(currentPos_), sel.RangeMain().anchor); +	} +	ClaimSelection(); +} +  void Editor::SetSelection(int currentPos_) { -	currentPos_ = pdoc->ClampPositionIntoDocument(currentPos_); -	if (currentPos != currentPos_) { -		InvalidateSelection(currentPos_, anchor, false); -		currentPos = currentPos_; +	SetSelection(SelectionPosition(currentPos_)); +} + +void Editor::SetEmptySelection(SelectionPosition currentPos_) { +	SelectionRange rangeNew(ClampPositionIntoDocument(currentPos_)); +	if (sel.Count() > 1 || !(sel.RangeMain() == rangeNew)) { +		InvalidateSelection(rangeNew);  	} +	sel.Clear(); +	sel.RangeMain() = rangeNew;  	SetRectangularRange();  	ClaimSelection(); +  }  void Editor::SetEmptySelection(int currentPos_) { -	selType = selStream; -	moveExtendsSelection = false; -	SetSelection(currentPos_, currentPos_); +	SetEmptySelection(SelectionPosition(currentPos_));  }  bool Editor::RangeContainsProtected(int start, int end) const { @@ -769,20 +788,13 @@ bool Editor::RangeContainsProtected(int start, int end) const {  }  bool Editor::SelectionContainsProtected() { -	// DONE, but untested...: make support rectangular selection -	bool scp = false; -	if (selType == selStream) { -		scp = RangeContainsProtected(anchor, currentPos); -	} else { -		SelectionLineIterator lineIterator(this); -		while (lineIterator.Iterate()) { -			if (RangeContainsProtected(lineIterator.startPos, lineIterator.endPos)) { -				scp = true; -				break; -			} +	for (size_t r=0; r<sel.Count(); r++) { +		if (RangeContainsProtected(sel.Range(r).Start().Position(),  +			sel.Range(r).End().Position())) { +			return true;  		}  	} -	return scp; +	return false;  }  /** @@ -809,14 +821,43 @@ int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) con  	return pos;  } -int Editor::MovePositionTo(int newPos, selTypes sel, bool ensureVisible) { -	int delta = newPos - currentPos; -	newPos = pdoc->ClampPositionIntoDocument(newPos); -	newPos = MovePositionOutsideChar(newPos, delta); -	if (sel != noSel) { -		selType = sel; +SelectionPosition Editor::MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd) const { +	int posMoved = pdoc->MovePositionOutsideChar(pos.Position(), moveDir, checkLineEnd); +	if (posMoved != pos.Position()) +		pos.SetPosition(posMoved); +	if (vs.ProtectionActive()) { +		int mask = pdoc->stylingBitsMask; +		if (moveDir > 0) { +			if ((pos.Position() > 0) && vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected()) { +				while ((pos.Position() < pdoc->Length()) && +				        (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected())) +					pos.Add(1); +			} +		} else if (moveDir < 0) { +			if (vs.styles[pdoc->StyleAt(pos.Position()) & mask].IsProtected()) { +				while ((pos.Position() > 0) && +				        (vs.styles[pdoc->StyleAt(pos.Position() - 1) & mask].IsProtected())) +					pos.Add(-1); +			} +		} +	} +	return pos; +} + +int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, bool ensureVisible) { +	//int delta = newPos.Position() - sel.MainCaret(); +	newPos = ClampPositionIntoDocument(newPos); +	//newPos = MovePositionOutsideChar(newPos, delta); +	if (!sel.IsRectangular() && (selt == Selection::selRectangle)) { +		// Switching to rectangular +		SelectionRange rangeMain = sel.RangeMain(); +		sel.Clear(); +		sel.Rectangular() = rangeMain; +	} +	if (selt != Selection::noSel) { +		sel.selType = selt;  	} -	if (sel != noSel || moveExtendsSelection) { +	if (selt != Selection::noSel || sel.MoveExtends()) {  		SetSelection(newPos);  	} else {  		SetEmptySelection(newPos); @@ -828,10 +869,14 @@ int Editor::MovePositionTo(int newPos, selTypes sel, bool ensureVisible) {  	return 0;  } -int Editor::MovePositionSoVisible(int pos, int moveDir) { -	pos = pdoc->ClampPositionIntoDocument(pos); -	pos = MovePositionOutsideChar(pos, moveDir); -	int lineDoc = pdoc->LineFromPosition(pos); +int Editor::MovePositionTo(int newPos, Selection::selTypes selt, bool ensureVisible) { +	return MovePositionTo(SelectionPosition(newPos), selt, ensureVisible); +} + +SelectionPosition Editor::MovePositionSoVisible(SelectionPosition pos, int moveDir) { +	pos = ClampPositionIntoDocument(pos); +	//pos = MovePositionOutsideChar(pos, moveDir); +	int lineDoc = pdoc->LineFromPosition(pos.Position());  	if (cs.GetVisible(lineDoc)) {  		return pos;  	} else { @@ -839,20 +884,24 @@ int Editor::MovePositionSoVisible(int pos, int moveDir) {  		if (moveDir > 0) {  			// lineDisplay is already line before fold as lines in fold use display line of line after fold  			lineDisplay = Platform::Clamp(lineDisplay, 0, cs.LinesDisplayed()); -			return pdoc->LineStart(cs.DocFromDisplay(lineDisplay)); +			return SelectionPosition(pdoc->LineStart(cs.DocFromDisplay(lineDisplay)));  		} else {  			lineDisplay = Platform::Clamp(lineDisplay - 1, 0, cs.LinesDisplayed()); -			return pdoc->LineEnd(cs.DocFromDisplay(lineDisplay)); +			return SelectionPosition(pdoc->LineEnd(cs.DocFromDisplay(lineDisplay)));  		}  	}  } +SelectionPosition Editor::MovePositionSoVisible(int pos, int moveDir) { +	return MovePositionSoVisible(SelectionPosition(pos), moveDir); +} +  /**   * Choose the x position that the caret will try to stick to   * as it moves up and down.   */  void Editor::SetLastXChosen() { -	Point pt = LocationFromPosition(currentPos); +	Point pt = LocationFromPosition(sel.MainCaret());  	lastXChosen = pt.x;  } @@ -897,16 +946,16 @@ void Editor::HorizontalScrollTo(int xPos) {  void Editor::MoveCaretInsideView(bool ensureVisible) {  	PRectangle rcClient = GetTextRectangle(); -	Point pt = LocationFromPosition(currentPos); +	Point pt = LocationFromPosition(sel.MainCaret());  	if (pt.y < rcClient.top) { -		MovePositionTo(PositionFromLocation( +		MovePositionTo(SPositionFromLocation(  		            Point(lastXChosen, rcClient.top)), -		        noSel, ensureVisible); +					Selection::noSel, ensureVisible);  	} else if ((pt.y + vs.lineHeight - 1) > rcClient.bottom) {  		int yOfLastLineFullyDisplayed = rcClient.top + (LinesOnScreen() - 1) * vs.lineHeight; -		MovePositionTo(PositionFromLocation( +		MovePositionTo(SPositionFromLocation(  		            Point(lastXChosen, rcClient.top + yOfLastLineFullyDisplayed)), -		        noSel, ensureVisible); +		        Selection::noSel, ensureVisible);  	}  } @@ -978,7 +1027,7 @@ void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {  	//Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " ");  	PRectangle rcClient = GetTextRectangle();  	//int rcClientFullWidth = rcClient.Width(); -	int posCaret = currentPos; +	int posCaret = sel.MainCaret();  	if (posDrag >= 0) {  		posCaret = posDrag;  	} @@ -1222,10 +1271,13 @@ void Editor::DropCaret() {  }  void Editor::InvalidateCaret() { -	if (posDrag >= 0) +	if (posDrag >= 0) {  		InvalidateRange(posDrag, posDrag + 1); -	else -		InvalidateRange(currentPos, currentPos + 1); +	} else { +		for (size_t r=0; r<sel.Count(); r++) { +			InvalidateRange(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1); +		} +	}  	UpdateSystemCaret();  } @@ -1757,7 +1809,7 @@ LineLayout *Editor::RetrieveLineLayout(int lineNumber) {  	int posLineStart = pdoc->LineStart(lineNumber);  	int posLineEnd = pdoc->LineStart(lineNumber + 1);  	PLATFORM_ASSERT(posLineEnd >= posLineStart); -	int lineCaret = pdoc->LineFromPosition(currentPos); +	int lineCaret = pdoc->LineFromPosition(sel.MainCaret());  	return llc.Retrieve(lineNumber, lineCaret,  	        posLineEnd - posLineStart, pdoc->GetStyleClock(),  	        LinesOnScreen() + 1, pdoc->LinesTotal()); @@ -1884,6 +1936,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou  		ll->widthLine = LineLayout::wrapWidthInfinite;  		ll->lines = 1;  		int numCharsInLine = 0; +		int numCharsBeforeEOL = 0;  		if (vstyle.edgeState == EDGE_BACKGROUND) {  			ll->edgeColumn = pdoc->FindColumn(line, theEdge);  			if (ll->edgeColumn >= posLineStart) { @@ -1910,6 +1963,8 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou  				else if (vstyle.styles[ll->styles[numCharsInLine]].caseForce == Style::caseLower)  					ll->chars[numCharsInLine] = static_cast<char>(tolower(chDoc));  				numCharsInLine++; +				if (!IsEOLChar(chDoc)) +					numCharsBeforeEOL++;  			}  		}  		ll->xHighlightGuide = 0; @@ -1992,6 +2047,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou  			ll->positions[startseg] += 2;  		}  		ll->numCharsInLine = numCharsInLine; +		ll->numCharsBeforeEOL = numCharsBeforeEOL;  		ll->validity = LineLayout::llPositions;  	}  	// Hard to cope when too narrow, so just assume there is space @@ -2186,15 +2242,49 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin  	int styleMask = pdoc->stylingBitsMask;  	PRectangle rcSegment = rcLine; +	int virtualSpace = 0; +	if (subLine == (ll->lines - 1))  +		virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * vsDraw.spaceWidth; +  	// Fill in a PRectangle representing the end of line characters  	int xEol = ll->positions[lineEnd] - subLineStart; -	rcSegment.left = xEol + xStart; -	rcSegment.right = xEol + vsDraw.aveCharWidth + xStart; -	int posLineEnd = pdoc->LineStart(line + 1); -	bool eolInSelection = (subLine == (ll->lines - 1)) && -	        (posLineEnd > ll->selStart) && (posLineEnd <= ll->selEnd) && (ll->selStart != ll->selEnd); -	if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { +	if (virtualSpace) { +		rcSegment.left = xEol + xStart; +		rcSegment.right = xEol + xStart + virtualSpace; +		// TODO: draw selection where needed +		surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated); +	} + +	int posAfterLineEnd = pdoc->LineStart(line + 1); +	bool eolInSelection = (subLine == (ll->lines - 1)) && sel.InSelectionForEOL(posAfterLineEnd); + +	for (int eolPos=ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) { +		rcSegment.left = xStart + ll->positions[eolPos] + virtualSpace; +		rcSegment.right = xStart + ll->positions[eolPos+1] + virtualSpace; +		const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]); +		bool inSelection = false; +		bool inHotspot = false; +		int styleMain = ll->styles[eolPos]; +		ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, eolPos, ll); +		ColourAllocated textFore = vsDraw.styles[styleMain].fore.allocated; +		if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1)) { +			if (vsDraw.selAlpha == SC_ALPHA_NOALPHA) { +				surface->FillRectangle(rcSegment, SelectionBackground(vsDraw)); +			} else { +				surface->FillRectangle(rcSegment, textBack); +				SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha); +			} +		} else { +			surface->FillRectangle(rcSegment, textBack); +		} +		DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); +	} + +	rcSegment.left = ll->positions[ll->numCharsInLine] + xStart + virtualSpace; +	rcSegment.right = ll->positions[ll->numCharsInLine] + vsDraw.aveCharWidth + xStart + virtualSpace; + +	if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {  		surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));  	} else {  		if (overrideBackground) { @@ -2202,15 +2292,15 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin  		} else {  			surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated);  		} -		if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) { +		if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) {  			SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha);  		}  	} -	rcSegment.left = xEol + vsDraw.aveCharWidth + xStart; +	rcSegment.left = ll->positions[ll->numCharsInLine] + vsDraw.aveCharWidth + xStart + virtualSpace;  	rcSegment.right = rcLine.right; -	if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { +	if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) {  		surface->FillRectangle(rcSegment, SelectionBackground(vsDraw));  	} else {  		if (overrideBackground) { @@ -2229,7 +2319,7 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin  		PRectangle rcPlace = rcSegment;  		if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { -			rcPlace.left = xEol + xStart; +			rcPlace.left = ll->positions[ll->numCharsInLine] + xStart + virtualSpace;  			rcPlace.right = rcPlace.left + vsDraw.aveCharWidth;  		} else {  			// draw left of the right text margin, to avoid clipping by the current clip rect @@ -2427,6 +2517,9 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis  	if (subLine < ll->lines) {  		lineStart = ll->LineStart(subLine);  		lineEnd = ll->LineStart(subLine + 1); +		if (subLine == ll->lines - 1) { +			lineEnd = ll->numCharsBeforeEOL; +		}  	}  	ColourAllocated wrapColour = vsDraw.styles[STYLE_DEFAULT].fore.allocated; @@ -2481,6 +2574,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis  	// Does not take margin into account but not significant  	int xStartVisible = subLineStart - xStart; +	ll->psel = &sel;  	BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible);  	int next = bfBack.First(); @@ -2502,7 +2596,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis  			rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right);  			int styleMain = ll->styles[i]; -			bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd); +			const bool inSelection = !hideSelection && sel.CharacterInSelection(iDoc);  			bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd);  			ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll);  			if (ll->chars[i] == '\t') { @@ -2595,7 +2689,7 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis  				if (vsDraw.hotspotForegroundSet)  					textFore = vsDraw.hotspotForeground.allocated;  			} -			bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd); +			const bool inSelection = !hideSelection && sel.CharacterInSelection(iDoc);  			if (inSelection && (vsDraw.selforeset)) {  				textFore = vsDraw.selforeground.allocated;  			} @@ -2767,15 +2861,21 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis  		        xStart, subLine, subLineStart, overrideBackground, background,  		        drawWrapMarkEnd, wrapColour);  	} -	if ((vsDraw.selAlpha != SC_ALPHA_NOALPHA) && (ll->selStart >= 0) && (ll->selEnd >= 0)) { -		int startPosSel = (ll->selStart < posLineStart) ? posLineStart : ll->selStart; -		int endPosSel = (ll->selEnd < (lineEnd + posLineStart)) ? ll->selEnd : (lineEnd + posLineStart); -		if (startPosSel < endPosSel) { -			rcSegment.left = xStart + ll->positions[startPosSel - posLineStart] - subLineStart; -			rcSegment.right = xStart + ll->positions[endPosSel - posLineStart] - subLineStart; -			rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left); -			rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right); -			SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha); +	if (!hideSelection && vsDraw.selAlpha != SC_ALPHA_NOALPHA) { +		// For each selection draw +		for (size_t r=0; r<sel.Count(); r++) { +			SelectionPosition spStart; +			SelectionPosition spEnd; +			if (sel.Range(r).Intersect(posLineStart, posLineStart + lineEnd, spStart, spEnd)) { +				if (!(spStart == spEnd)) { +					rcSegment.left = xStart + ll->positions[spStart.Position() - posLineStart] - subLineStart + spStart.VirtualSpace() * vsDraw.spaceWidth; +					rcSegment.right = xStart + ll->positions[spEnd.Position() - posLineStart] - subLineStart + spEnd.VirtualSpace() * vsDraw.spaceWidth; +					rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left); +					rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right); +					SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw),  +						(r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAlpha / 2); +				} +			}  		}  	} @@ -2937,6 +3037,84 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) {  	}  } +void Editor::DrawCarets(Surface *surface, ViewStyle &vsDraw, int lineDoc, int xStart, +        PRectangle rcLine, LineLayout *ll, int subLine) { +	// When drag is active it is the only caret drawn +	bool drawDrag = posDrag != INVALID_POSITION; +	if (hideSelection && !drawDrag) +		return; +	Range rangeLine(pdoc->LineStart(lineDoc), pdoc->LineStart(lineDoc + 1)); +	// For each selection draw +	for (size_t r=0; (r<sel.Count()) || drawDrag; r++) { +		const bool mainCaret = r == sel.Main(); +		const int posCaret = (drawDrag ? posDrag : sel.Range(r).caret.Position()); +		const int offset = posCaret - rangeLine.start; +		const int virtualOffset = drawDrag ? 0 : sel.Range(r).caret.VirtualSpace() * vsDraw.spaceWidth; +		if (ll->InLine(offset, subLine) && offset <= ll->numCharsInLine) { +			int xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)] + xStart; +			if (ll->wrapIndent != 0) { +				int lineStart = ll->LineStart(subLine); +				if (lineStart != 0)	// Wrapped +					xposCaret += ll->wrapIndent; +			} +			if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) && +			        ((posDrag >= 0) || ((caret.active && caret.on) || (!multiLineCaretBlinks && !mainCaret)))) { +				bool caretAtEOF = false; +				bool caretAtEOL = false; +				bool drawBlockCaret = false; +				int widthOverstrikeCaret; +				int caretWidthOffset = 0; +				PRectangle rcCaret = rcLine; + +				if (posCaret == pdoc->Length())	{   // At end of document +					caretAtEOF = true; +					widthOverstrikeCaret = vsDraw.aveCharWidth; +				} else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) {	// At end of line +					caretAtEOL = true; +					widthOverstrikeCaret = vsDraw.aveCharWidth; +				} else { +					widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset]; +				} +				if (widthOverstrikeCaret < 3)	// Make sure its visible +					widthOverstrikeCaret = 3; + +				if (offset > ll->LineStart(subLine)) +					caretWidthOffset = 1;	// Move back so overlaps both character cells. +				if (posDrag >= 0) { +					/* Dragging text, use a line caret */ +					rcCaret.left = xposCaret - caretWidthOffset; +					rcCaret.right = rcCaret.left + vsDraw.caretWidth; +				} else if (inOverstrike) { +					/* Overstrike (insert mode), use a modified bar caret */ +					rcCaret.top = rcCaret.bottom - 2; +					rcCaret.left = xposCaret + 1; +					rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; +				} else if (vsDraw.caretStyle == CARETSTYLE_BLOCK) { +					/* Block caret */ +					rcCaret.left = xposCaret; +					if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) { +						drawBlockCaret = true; +						rcCaret.right = xposCaret + widthOverstrikeCaret; +					} else { +						rcCaret.right = xposCaret + vsDraw.aveCharWidth; +					} +				} else { +					/* Line caret */ +					rcCaret.left = xposCaret - caretWidthOffset; +					rcCaret.right = rcCaret.left + vsDraw.caretWidth; +				} +				if (drawBlockCaret) { +					DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret, rcCaret); +				} else { +					surface->FillRectangle(rcCaret, mainCaret ? vsDraw.caretcolour.allocated : vsDraw.selbackground2.allocated); +				} +			} +		} +		if (drawDrag)  +			break; +	} +} +  void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {  	//Platform::DebugPrintf("Paint:%1d (%3d,%3d) ... (%3d,%3d)\n",  	//	paintingAllText, rcArea.left, rcArea.top, rcArea.right, rcArea.bottom); @@ -3036,7 +3214,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {  		int visibleLine = topLine + screenLinePaintFirst; -		int posCaret = currentPos; +		int posCaret = sel.MainCaret();  		if (posDrag >= 0)  			posCaret = posDrag;  		int lineCaret = pdoc->LineFromPosition(posCaret); @@ -3055,7 +3233,6 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {  		//ElapsedTime etWhole;  		int lineDocPrevious = -1;	// Used to avoid laying out one document line multiple times  		AutoLineLayout ll(llc, 0); -		SelectionLineIterator lineIterator(this);  		while (visibleLine < cs.LinesDisplayed() && yposScreen < rcArea.bottom) {  			int lineDoc = cs.DocFromDisplay(visibleLine); @@ -3069,8 +3246,6 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {  			//ElapsedTime et;  			if (lineDoc != lineDocPrevious) {  				ll.Set(0); -				// For rectangular selection this accesses the layout cache so should be after layout returned. -				lineIterator.SetAt(lineDoc);  				ll.Set(RetrieveLineLayout(lineDoc));  				LayoutLine(lineDoc, surface, vs, ll, wrapWidth);  				lineDocPrevious = lineDoc; @@ -3078,17 +3253,8 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {  			//durLayout += et.Duration(true);  			if (ll) { -				if (selType == selStream) { -					ll->selStart = SelectionStart(); -					ll->selEnd = SelectionEnd(); -				} else { -					ll->selStart = lineIterator.startPos; -					ll->selEnd = lineIterator.endPos; -				}  				ll->containsCaret = lineDoc == lineCaret;  				if (hideSelection) { -					ll->selStart = -1; -					ll->selEnd = -1;  					ll->containsCaret = false;  				} @@ -3132,71 +3298,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {  					}  				} -				// Draw the Caret -				if (lineDoc == lineCaret) { -					int offset = Platform::Minimum(posCaret - rangeLine.start, ll->maxLineLength); -					if (ll->InLine(offset, subLine)) { -						int xposCaret = ll->positions[offset] - ll->positions[ll->LineStart(subLine)] + xStart; - -						if (ll->wrapIndent != 0) { -							int lineStart = ll->LineStart(subLine); -							if (lineStart != 0)	// Wrapped -								xposCaret += ll->wrapIndent; -						} -						if ((xposCaret >= 0) && (vs.caretWidth > 0) && (vs.caretStyle != CARETSTYLE_INVISIBLE) && -						        ((posDrag >= 0) || (caret.active && caret.on))) { -							bool caretAtEOF = false; -							bool caretAtEOL = false; -							bool drawBlockCaret = false; -							int widthOverstrikeCaret; -							int caretWidthOffset = 0; -							PRectangle rcCaret = rcLine; - -							if (posCaret == pdoc->Length())	{   // At end of document -								caretAtEOF = true; -								widthOverstrikeCaret = vs.aveCharWidth; -							} else if ((posCaret - rangeLine.start) >= ll->numCharsInLine) {	// At end of line -								caretAtEOL = true; -								widthOverstrikeCaret = vs.aveCharWidth; -							} else { -								widthOverstrikeCaret = ll->positions[offset + 1] - ll->positions[offset]; -							} -							if (widthOverstrikeCaret < 3)	// Make sure its visible -								widthOverstrikeCaret = 3; - -							if (offset > ll->LineStart(subLine)) -								caretWidthOffset = 1;	// Move back so overlaps both character cells. -							if (posDrag >= 0) { -								/* Dragging text, use a line caret */ -								rcCaret.left = xposCaret - caretWidthOffset; -								rcCaret.right = rcCaret.left + vs.caretWidth; -							} else if (inOverstrike) { -								/* Overstrike (insert mode), use a modified bar caret */ -								rcCaret.top = rcCaret.bottom - 2; -								rcCaret.left = xposCaret + 1; -								rcCaret.right = rcCaret.left + widthOverstrikeCaret - 1; -							} else if (vs.caretStyle == CARETSTYLE_BLOCK) { -								/* Block caret */ -								rcCaret.left = xposCaret; -								if (!caretAtEOL && !caretAtEOF && (ll->chars[offset] != '\t') && !(IsControlCharacter(ll->chars[offset]))) { -									drawBlockCaret = true; -									rcCaret.right = xposCaret + widthOverstrikeCaret; -								} else { -									rcCaret.right = xposCaret + vs.aveCharWidth; -								} -							} else { -								/* Line caret */ -								rcCaret.left = xposCaret - caretWidthOffset; -								rcCaret.right = rcCaret.left + vs.caretWidth; -							} -							if (drawBlockCaret) { -								DrawBlockCaret(surface, vs, ll, subLine, xStart, offset, posCaret, rcCaret); -							} else { -								surface->FillRectangle(rcCaret, vs.caretcolour.allocated); -							} -						} -					} -				} +				DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);  				if (bufferedDraw) {  					Point from(vs.fixedColumnWidth, 0); @@ -3375,8 +3477,6 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) {  		LineLayout ll(8000);  		LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint); -		ll.selStart = -1; -		ll.selEnd = -1;  		ll.containsCaret = false;  		PRectangle rcLine; @@ -3508,32 +3608,61 @@ void Editor::AddChar(char ch) {  // AddCharUTF inserts an array of bytes which may or may not be in UTF-8.  void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { -	bool wasSelection = currentPos != anchor; -	ClearSelection(); -	bool charReplaceAction = false; -	if (inOverstrike && !wasSelection && !RangeContainsProtected(currentPos, currentPos + 1)) { -		if (currentPos < (pdoc->Length())) { -			if (!IsEOLChar(pdoc->CharAt(currentPos))) { -				charReplaceAction = true; -				pdoc->BeginUndoAction(); -				pdoc->DelChar(currentPos); +	const bool undoBracketNeeded = (sel.Count() > 1) || !sel.Empty() || inOverstrike; +	if (undoBracketNeeded)  +		pdoc->BeginUndoAction(); +	for (size_t r=0; r<sel.Count(); r++) { +		if (!RangeContainsProtected(sel.Range(r).Start().Position(),  +			sel.Range(r).End().Position())) { +			int positionInsert = sel.Range(r).Start().Position(); +			if (!sel.Range(r).Empty()) { +				if (sel.Range(r).Length()) { +					pdoc->DeleteChars(positionInsert, sel.Range(r).Length()); +					sel.ClearVirtualSpace(r); +				} else { +					// Range is all virtual so collapse to start of virtual space +					sel.Range(r).MinimizeVirtualSpace(); +				} +			} else if (inOverstrike) { +				if (positionInsert < pdoc->Length()) { +					if (!IsEOLChar(pdoc->CharAt(positionInsert))) { +						pdoc->DelChar(positionInsert); +						sel.ClearVirtualSpace(r); +					} +				} +			} +			const unsigned int spaces = sel.Range(r).caret.VirtualSpace(); +			if (spaces > 0) { +				char *spaceText = new char[spaces]; +				memset(spaceText, ' ', spaces); +				pdoc->InsertString(positionInsert, spaceText, spaces); +				positionInsert += spaces; +				delete []spaceText; +			} +			if (pdoc->InsertString(positionInsert, s, len)) { +				sel.Range(r).caret.SetPosition(positionInsert + len); +				sel.Range(r).anchor.SetPosition(positionInsert + len); +			} +			sel.ClearVirtualSpace(r); +			// If in wrap mode rewrap current line so EnsureCaretVisible has accurate information +			if (wrapState != eWrapNone) { +				AutoSurface surface(this); +				if (surface) { +					WrapOneLine(surface, pdoc->LineFromPosition(positionInsert)); +				}  			}  		}  	} -	if (pdoc->InsertString(currentPos, s, len)) { -		SetEmptySelection(currentPos + len); -	} -	if (charReplaceAction) { +	if (undoBracketNeeded)   		pdoc->EndUndoAction(); -	} -	// If in wrap mode rewrap current line so EnsureCaretVisible has accurate information  	if (wrapState != eWrapNone) { -		AutoSurface surface(this); -		if (surface) { -			WrapOneLine(surface, pdoc->LineFromPosition(currentPos)); -		}  		SetScrollBars();  	} +	if (sel.IsRectangular()) { +		sel.selType = Selection::selThin; +		sel.Rectangular() = SelectionRange(sel.Rectangular().caret, sel.Range(0).anchor); +	} +	// If in wrap mode rewrap current line so EnsureCaretVisible has accurate information  	EnsureCaretVisible();  	// Avoid blinking during rapid typing:  	ShowCaretAtCurrentPosition(); @@ -3580,30 +3709,19 @@ void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) {  }  void Editor::ClearSelection() { -	if (!SelectionContainsProtected()) { -		int startPos = SelectionStart(); -		if (selType == selStream) { -			unsigned int chars = SelectionEnd() - startPos; -			if (0 != chars) { -				pdoc->BeginUndoAction(); -				pdoc->DeleteChars(startPos, chars); -				pdoc->EndUndoAction(); -			} -		} else { -			pdoc->BeginUndoAction(); -			SelectionLineIterator lineIterator(this, false); -			while (lineIterator.Iterate()) { -				startPos = lineIterator.startPos; -				unsigned int chars = lineIterator.endPos - startPos; -				if (0 != chars) { -					pdoc->DeleteChars(startPos, chars); -				} +	pdoc->BeginUndoAction(); +	for (size_t r=0; r<sel.Count(); r++) { +		if (!sel.Range(r).Empty()) { +			if (!RangeContainsProtected(sel.Range(r).Start().Position(),  +				sel.Range(r).End().Position())) { +				pdoc->DeleteChars(sel.Range(r).Start().Position(),  +					sel.Range(r).Length()); +				sel.ClearVirtualSpace(r);  			} -			pdoc->EndUndoAction(); -			selType = selStream;  		} -		SetEmptySelection(startPos);  	} +	pdoc->EndUndoAction(); +  }  void Editor::ClearAll() { @@ -3617,8 +3735,7 @@ void Editor::ClearAll() {  		pdoc->MarginClearAll();  	}  	pdoc->EndUndoAction(); -	anchor = 0; -	currentPos = 0; +	sel.Clear();  	SetTopLine(0);  	SetVerticalScrollPos();  	InvalidateStyleRedraw(); @@ -3655,13 +3772,14 @@ void Editor::Cut() {  	}  } -void Editor::PasteRectangular(int pos, const char *ptr, int len) { +void Editor::PasteRectangular(SelectionPosition pos, const char *ptr, int len) {  	if (pdoc->IsReadOnly() || SelectionContainsProtected()) {  		return;  	} -	currentPos = pos; -	int xInsert = XFromPosition(currentPos); -	int line = pdoc->LineFromPosition(currentPos); +	sel.Clear(); +	sel.RangeMain() = SelectionRange(pos, pos); +	int xInsert = XFromPosition(sel.RangeMain().caret); +	int line = pdoc->LineFromPosition(sel.MainCaret());  	bool prevCr = false;  	pdoc->BeginUndoAction();  	for (int i = 0; i < len; i++) { @@ -3675,17 +3793,17 @@ void Editor::PasteRectangular(int pos, const char *ptr, int len) {  					pdoc->InsertChar(pdoc->Length(), '\n');  			}  			// Pad the end of lines with spaces if required -			currentPos = PositionFromLineX(line, xInsert); -			if ((XFromPosition(currentPos) < xInsert) && (i + 1 < len)) { -				while (XFromPosition(currentPos) < xInsert) { -					pdoc->InsertChar(currentPos, ' '); -					currentPos++; +			sel.RangeMain().caret.SetPosition(PositionFromLineX(line, xInsert)); +			if ((XFromPosition(sel.MainCaret()) < xInsert) && (i + 1 < len)) { +				while (XFromPosition(sel.MainCaret()) < xInsert) { +					pdoc->InsertChar(sel.MainCaret(), ' '); +					sel.RangeMain().caret.Add(1);  				}  			}  			prevCr = ptr[i] == '\r';  		} else { -			pdoc->InsertString(currentPos, ptr + i, 1); -			currentPos++; +			pdoc->InsertString(sel.MainCaret(), ptr + i, 1); +			sel.RangeMain().caret.Add(1);  			prevCr = false;  		}  	} @@ -3698,14 +3816,28 @@ bool Editor::CanPaste() {  }  void Editor::Clear() { -	if (currentPos == anchor) { -		if (!RangeContainsProtected(currentPos, currentPos + 1)) { -			DelChar(); +	const bool undoBracketNeeded = (sel.Count() > 1) || !sel.Empty(); +	// If multiple selections, don't delete EOLS +	if (undoBracketNeeded)  +		pdoc->BeginUndoAction(); +	if (sel.Empty()) { +		pdoc->BeginUndoAction(); +		for (size_t r=0; r<sel.Count(); r++) { +			if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) { +				if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) { +					pdoc->DelChar(sel.Range(r).caret.Position()); +					sel.ClearVirtualSpace(r); +				}  // else multiple selection so don't eat line ends +			} else { +				sel.ClearVirtualSpace(r); +			}  		} +		pdoc->EndUndoAction();  	} else {  		ClearSelection();  	} -	SetEmptySelection(currentPos); +	if (undoBracketNeeded)  +		pdoc->EndUndoAction();  }  void Editor::SelectAll() { @@ -3733,20 +3865,57 @@ void Editor::Redo() {  }  void Editor::DelChar() { -	if (!RangeContainsProtected(currentPos, currentPos + 1)) { -		pdoc->DelChar(currentPos); +	if (!RangeContainsProtected(sel.MainCaret(), sel.MainCaret() + 1)) { +		pdoc->DelChar(sel.MainCaret());  	}  	// Avoid blinking during rapid typing:  	ShowCaretAtCurrentPosition();  }  void Editor::DelCharBack(bool allowLineStartDeletion) { -	if (currentPos == anchor) { -		if (!RangeContainsProtected(currentPos - 1, currentPos)) { -			int lineCurrentPos = pdoc->LineFromPosition(currentPos); -			if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != currentPos)) { -				if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) && -				        pdoc->GetColumn(currentPos) > 0 && pdoc->backspaceUnindents) { +	const bool undoBracketNeeded = (sel.Count() > 1) || !sel.Empty(); +	if (undoBracketNeeded)  +		pdoc->BeginUndoAction(); +	if (sel.Empty()) { +		for (size_t r=0; r<sel.Count(); r++) { +			if (!RangeContainsProtected(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1)) { +				if (sel.Range(r).caret.VirtualSpace()) { +					sel.Range(r).caret.SetVirtualSpace(sel.Range(r).caret.VirtualSpace() - 1); +					sel.Range(r).anchor.SetVirtualSpace(sel.Range(r).caret.VirtualSpace()); +				} else { +					int lineCurrentPos = pdoc->LineFromPosition(sel.Range(r).caret.Position()); +					if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.Range(r).caret.Position())) { +						if (pdoc->GetColumn(sel.Range(r).caret.Position()) <= pdoc->GetLineIndentation(lineCurrentPos) && +						        pdoc->GetColumn(sel.Range(r).caret.Position()) > 0 && pdoc->backspaceUnindents) { +							if (!undoBracketNeeded) +								pdoc->BeginUndoAction(); +							int indentation = pdoc->GetLineIndentation(lineCurrentPos); +							int indentationStep = pdoc->IndentSize(); +							if (indentation % indentationStep == 0) { +								pdoc->SetLineIndentation(lineCurrentPos, indentation - indentationStep); +							} else { +								pdoc->SetLineIndentation(lineCurrentPos, indentation - (indentation % indentationStep)); +							} +							// SetEmptySelection +							sel.Range(r) = SelectionRange(pdoc->GetLineIndentPosition(lineCurrentPos),  +								pdoc->GetLineIndentPosition(lineCurrentPos)); +							if (!undoBracketNeeded) +								pdoc->EndUndoAction(); +						} else { +							pdoc->DelCharBack(sel.Range(r).caret.Position()); +						} +					} +				} +			} else { +				sel.ClearVirtualSpace(r); +			} +		} +		/* +		if (!RangeContainsProtected(sel.MainCaret() - 1, sel.MainCaret())) { +			int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret()); +			if (allowLineStartDeletion || (pdoc->LineStart(lineCurrentPos) != sel.MainCaret())) { +				if (pdoc->GetColumn(sel.MainCaret()) <= pdoc->GetLineIndentation(lineCurrentPos) && +				        pdoc->GetColumn(sel.MainCaret()) > 0 && pdoc->backspaceUnindents) {  					pdoc->BeginUndoAction();  					int indentation = pdoc->GetLineIndentation(lineCurrentPos);  					int indentationStep = pdoc->IndentSize(); @@ -3758,14 +3927,17 @@ void Editor::DelCharBack(bool allowLineStartDeletion) {  					SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));  					pdoc->EndUndoAction();  				} else { -					pdoc->DelCharBack(currentPos); +					pdoc->DelCharBack(sel.MainCaret());  				}  			}  		} +		*/  	} else {  		ClearSelection(); -		SetEmptySelection(currentPos); +		SetEmptySelection(sel.MainCaret());  	} +	if (undoBracketNeeded)  +		pdoc->EndUndoAction();  	// Avoid blinking during rapid typing:  	ShowCaretAtCurrentPosition();  } @@ -3990,13 +4162,11 @@ void Editor::NotifyModified(Document*, DocModification mh, void *) {  	} else {  		// Move selection and brace highlights  		if (mh.modificationType & SC_MOD_INSERTTEXT) { -			currentPos = MovePositionForInsertion(currentPos, mh.position, mh.length); -			anchor = MovePositionForInsertion(anchor, mh.position, mh.length); +			sel.MovePositions(true, mh.position, mh.length);  			braces[0] = MovePositionForInsertion(braces[0], mh.position, mh.length);  			braces[1] = MovePositionForInsertion(braces[1], mh.position, mh.length);  		} else if (mh.modificationType & SC_MOD_DELETETEXT) { -			currentPos = MovePositionForDeletion(currentPos, mh.position, mh.length); -			anchor = MovePositionForDeletion(anchor, mh.position, mh.length); +			sel.MovePositions(false, mh.position, mh.length);  			braces[0] = MovePositionForDeletion(braces[0], mh.position, mh.length);  			braces[1] = MovePositionForDeletion(braces[1], mh.position, mh.length);  		} @@ -4228,11 +4398,11 @@ void Editor::NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lPar   * If stuttered = true and not already at first/last row, move to first/last row of window.   * If stuttered = true and already at first/last row, scroll as normal.   */ -void Editor::PageMove(int direction, selTypes sel, bool stuttered) { +void Editor::PageMove(int direction, Selection::selTypes selt, bool stuttered) {  	int topLineNew, newPos;  	// I consider only the caretYSlop, and ignore the caretYPolicy-- is that a problem? -	int currentLine = pdoc->LineFromPosition(currentPos); +	int currentLine = pdoc->LineFromPosition(sel.MainCaret());  	int topStutterLine = topLine + caretYSlop;  	int bottomStutterLine =  	    pdoc->LineFromPosition(PositionFromLocation( @@ -4248,7 +4418,7 @@ void Editor::PageMove(int direction, selTypes sel, bool stuttered) {  		newPos = PositionFromLocation(Point(lastXChosen, vs.lineHeight * (LinesToScroll() - caretYSlop)));  	} else { -		Point pt = LocationFromPosition(currentPos); +		Point pt = LocationFromPosition(sel.MainCaret());  		topLineNew = Platform::Clamp(  		            topLine + direction * LinesToScroll(), 0, MaxScrollPos()); @@ -4258,37 +4428,28 @@ void Editor::PageMove(int direction, selTypes sel, bool stuttered) {  	if (topLineNew != topLine) {  		SetTopLine(topLineNew); -		MovePositionTo(newPos, sel); +		MovePositionTo(SelectionPosition(newPos), selt);  		Redraw();  		SetVerticalScrollPos();  	} else { -		MovePositionTo(newPos, sel); +		MovePositionTo(SelectionPosition(newPos), selt);  	}  }  void Editor::ChangeCaseOfSelection(bool makeUpperCase) {  	pdoc->BeginUndoAction(); -	int startCurrent = currentPos; -	int startAnchor = anchor; -	if (selType == selStream) { -		pdoc->ChangeCase(Range(SelectionStart(), SelectionEnd()), -		        makeUpperCase); -		SetSelection(startCurrent, startAnchor); -	} else { -		SelectionLineIterator lineIterator(this, false); -		while (lineIterator.Iterate()) { -			pdoc->ChangeCase( -			    Range(lineIterator.startPos, lineIterator.endPos), -			    makeUpperCase); -		} -		// Would be nicer to keep the rectangular selection but this is complex -		SetEmptySelection(startCurrent); +	for (size_t r=0; r<sel.Count(); r++) { +		SelectionRange current = sel.Range(r); +		pdoc->ChangeCase(Range(current.Start().Position(), current.End().Position()), +	        makeUpperCase); +		// Automatic movement cuts off last character so reset to exactly the same as it was. +		sel.Range(r) = current;  	}  	pdoc->EndUndoAction();  }  void Editor::LineTranspose() { -	int line = pdoc->LineFromPosition(currentPos); +	int line = pdoc->LineFromPosition(sel.MainCaret());  	if (line > 0) {  		pdoc->BeginUndoAction();  		int startPrev = pdoc->LineStart(line - 1); @@ -4303,7 +4464,7 @@ void Editor::LineTranspose() {  		pdoc->DeleteChars(startPrev, len1);  		pdoc->InsertString(startPrev, line2, len2);  		pdoc->InsertString(start - len1 + len2, line1, len1); -		MovePositionTo(start - len1 + len2); +		MovePositionTo(SelectionPosition(start - len1 + len2));  		delete []line1;  		delete []line2;  		pdoc->EndUndoAction(); @@ -4311,13 +4472,14 @@ void Editor::LineTranspose() {  }  void Editor::Duplicate(bool forLine) { +	// TODO: multiple selection by duplicating each selection  	int start = SelectionStart();  	int end = SelectionEnd(); -	if (start == end) { +	if (sel.Empty()) {  		forLine = true;  	}  	if (forLine) { -		int line = pdoc->LineFromPosition(currentPos); +		int line = pdoc->LineFromPosition(sel.MainCaret());  		start = pdoc->LineStart(line);  		end = pdoc->LineEnd(line);  	} @@ -4333,7 +4495,7 @@ void Editor::Duplicate(bool forLine) {  }  void Editor::CancelModes() { -	moveExtendsSelection = false; +	sel.SetMoveExtends(false);  }  void Editor::NewLine() { @@ -4344,8 +4506,8 @@ void Editor::NewLine() {  	} else if (pdoc->eolMode == SC_EOL_CR) {  		eol = "\r";  	} // else SC_EOL_LF -> "\n" already set -	if (pdoc->InsertCString(currentPos, eol)) { -		SetEmptySelection(currentPos + istrlen(eol)); +	if (pdoc->InsertCString(sel.MainCaret(), eol)) { +		SetEmptySelection(sel.MainCaret() + istrlen(eol));  		while (*eol) {  			NotifyChar(*eol);  			eol++; @@ -4358,16 +4520,16 @@ void Editor::NewLine() {  	ShowCaretAtCurrentPosition();  } -void Editor::CursorUpOrDown(int direction, selTypes sel) { -	Point pt = LocationFromPosition(currentPos); -	int lineDoc = pdoc->LineFromPosition(currentPos); +void Editor::CursorUpOrDown(int direction, Selection::selTypes selt) { +	Point pt = LocationFromPosition(sel.MainCaret()); +	int lineDoc = pdoc->LineFromPosition(sel.MainCaret());  	Point ptStartLine = LocationFromPosition(pdoc->LineStart(lineDoc));  	int subLine = (pt.y - ptStartLine.y) / vs.lineHeight;  	int commentLines = vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0; -	int posNew = PositionFromLocation( +	SelectionPosition posNew = SPositionFromLocation(  	            Point(lastXChosen, pt.y + direction * vs.lineHeight));  	if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) { -		posNew = PositionFromLocation( +		posNew = SPositionFromLocation(  	            Point(lastXChosen, pt.y + (commentLines + 1) * vs.lineHeight));  	}  	if (direction < 0) { @@ -4375,24 +4537,25 @@ void Editor::CursorUpOrDown(int direction, selTypes sel) {  		// seek back if that is the case.  		// There is an equivalent case when moving down which skips  		// over a line but as that does not trap the user it is fine. -		Point ptNew = LocationFromPosition(posNew); -		while ((posNew > 0) && (pt.y == ptNew.y)) { -			posNew--; -			ptNew = LocationFromPosition(posNew); +		Point ptNew = LocationFromPosition(posNew.Position()); +		while ((posNew.Position() > 0) && (pt.y == ptNew.y)) { +			posNew.Add(- 1); +			posNew.SetVirtualSpace(0); +			ptNew = LocationFromPosition(posNew.Position());  		}  	} -	MovePositionTo(posNew, sel); +	MovePositionTo(posNew, selt);  } -void Editor::ParaUpOrDown(int direction, selTypes sel) { -	int lineDoc, savedPos = currentPos; +void Editor::ParaUpOrDown(int direction, Selection::selTypes selt) { +	int lineDoc, savedPos = sel.MainCaret();  	do { -		MovePositionTo(direction > 0 ? pdoc->ParaDown(currentPos) : pdoc->ParaUp(currentPos), sel); -		lineDoc = pdoc->LineFromPosition(currentPos); +		MovePositionTo(SelectionPosition(direction > 0 ? pdoc->ParaDown(sel.MainCaret()) : pdoc->ParaUp(sel.MainCaret())), selt); +		lineDoc = pdoc->LineFromPosition(sel.MainCaret());  		if (direction > 0) { -			if (currentPos >= pdoc->Length() && !cs.GetVisible(lineDoc)) { -				if (sel == noSel) { -					MovePositionTo(pdoc->LineEndPosition(savedPos)); +			if (sel.MainCaret() >= pdoc->Length() && !cs.GetVisible(lineDoc)) { +				if (selt == Selection::noSel) { +					MovePositionTo(SelectionPosition(pdoc->LineEndPosition(savedPos)));  				}  				break;  			} @@ -4438,16 +4601,16 @@ int Editor::KeyCommand(unsigned int iMessage) {  		CursorUpOrDown(1);  		break;  	case SCI_LINEDOWNEXTEND: -		CursorUpOrDown(1, selStream); +		CursorUpOrDown(1, Selection::selStream);  		break;  	case SCI_LINEDOWNRECTEXTEND: -		CursorUpOrDown(1, selRectangle); +		CursorUpOrDown(1, Selection::selRectangle);  		break;  	case SCI_PARADOWN:  		ParaUpOrDown(1);  		break;  	case SCI_PARADOWNEXTEND: -		ParaUpOrDown(1, selStream); +		ParaUpOrDown(1, Selection::selStream);  		break;  	case SCI_LINESCROLLDOWN:  		ScrollTo(topLine + 1); @@ -4457,144 +4620,180 @@ int Editor::KeyCommand(unsigned int iMessage) {  		CursorUpOrDown(-1);  		break;  	case SCI_LINEUPEXTEND: -		CursorUpOrDown(-1, selStream); +		CursorUpOrDown(-1, Selection::selStream);  		break;  	case SCI_LINEUPRECTEXTEND: -		CursorUpOrDown(-1, selRectangle); +		CursorUpOrDown(-1, Selection::selRectangle);  		break;  	case SCI_PARAUP:  		ParaUpOrDown(-1);  		break;  	case SCI_PARAUPEXTEND: -		ParaUpOrDown(-1, selStream); +		ParaUpOrDown(-1, Selection::selStream);  		break;  	case SCI_LINESCROLLUP:  		ScrollTo(topLine - 1);  		MoveCaretInsideView(false);  		break;  	case SCI_CHARLEFT: -		if (SelectionEmpty() || moveExtendsSelection) { -			MovePositionTo(MovePositionSoVisible(currentPos - 1, -1)); +		if (SelectionEmpty() || sel.MoveExtends()) { +			if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { +				SelectionPosition spCaret = sel.RangeMain().caret; +				spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); +				MovePositionTo(spCaret); +			} else { +				MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1)); +			}  		} else { -			MovePositionTo(SelectionStart()); +			MovePositionTo(sel.RangeMain().Start());  		}  		SetLastXChosen();  		break;  	case SCI_CHARLEFTEXTEND: -		MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selStream); +		if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { +			SelectionPosition spCaret = sel.RangeMain().caret; +			spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); +			MovePositionTo(spCaret, Selection::selStream); +		} else { +			MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selStream); +		}  		SetLastXChosen();  		break;  	case SCI_CHARLEFTRECTEXTEND: -		MovePositionTo(MovePositionSoVisible(currentPos - 1, -1), selRectangle); +		if (pdoc->IsLineEndPosition(sel.MainCaret()) && sel.RangeMain().caret.VirtualSpace()) { +			SelectionPosition spCaret = sel.RangeMain().caret; +			spCaret.SetVirtualSpace(spCaret.VirtualSpace() - 1); +			MovePositionTo(spCaret, Selection::selRectangle); +		} else { +			MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() - 1), -1), Selection::selRectangle); +		}  		SetLastXChosen();  		break;  	case SCI_CHARRIGHT: -		if (SelectionEmpty() || moveExtendsSelection) { -			MovePositionTo(MovePositionSoVisible(currentPos + 1, 1)); +		if (SelectionEmpty() || sel.MoveExtends()) { +			if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) { +				SelectionPosition spCaret = sel.RangeMain().caret; +				spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); +				MovePositionTo(spCaret); +			} else { +				MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1)); +			}  		} else { -			MovePositionTo(SelectionEnd()); +			MovePositionTo(sel.RangeMain().End());  		}  		SetLastXChosen();  		break;  	case SCI_CHARRIGHTEXTEND: -		MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selStream); +		if ((virtualSpaceOptions & SCVS_USERACCESSIBLE) && pdoc->IsLineEndPosition(sel.MainCaret())) { +			SelectionPosition spCaret = sel.RangeMain().caret; +			spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); +			MovePositionTo(spCaret, Selection::selStream); +		} else { +			MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selStream); +		}  		SetLastXChosen();  		break;  	case SCI_CHARRIGHTRECTEXTEND: -		MovePositionTo(MovePositionSoVisible(currentPos + 1, 1), selRectangle); +		if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) && pdoc->IsLineEndPosition(sel.MainCaret())) { +			SelectionPosition spCaret = sel.RangeMain().caret; +			spCaret.SetVirtualSpace(spCaret.VirtualSpace() + 1); +			MovePositionTo(spCaret, Selection::selRectangle); +		} else { +			MovePositionTo(MovePositionSoVisible(SelectionPosition(sel.MainCaret() + 1), 1), Selection::selRectangle); +		}  		SetLastXChosen();  		break;  	case SCI_WORDLEFT: -		MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1)); +		MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1));  		SetLastXChosen();  		break;  	case SCI_WORDLEFTEXTEND: -		MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, -1), -1), selStream); +		MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), -1), -1), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_WORDRIGHT: -		MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1)); +		MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1));  		SetLastXChosen();  		break;  	case SCI_WORDRIGHTEXTEND: -		MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(currentPos, 1), 1), selStream); +		MovePositionTo(MovePositionSoVisible(pdoc->NextWordStart(sel.MainCaret(), 1), 1), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_WORDLEFTEND: -		MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1)); +		MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1));  		SetLastXChosen();  		break;  	case SCI_WORDLEFTENDEXTEND: -		MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, -1), -1), selStream); +		MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), -1), -1), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_WORDRIGHTEND: -		MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1)); +		MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1));  		SetLastXChosen();  		break;  	case SCI_WORDRIGHTENDEXTEND: -		MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(currentPos, 1), 1), selStream); +		MovePositionTo(MovePositionSoVisible(pdoc->NextWordEnd(sel.MainCaret(), 1), 1), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_HOME: -		MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos))); +		MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));  		SetLastXChosen();  		break;  	case SCI_HOMEEXTEND: -		MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selStream); +		MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_HOMERECTEXTEND: -		MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(currentPos)), selRectangle); +		MovePositionTo(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())), Selection::selRectangle);  		SetLastXChosen();  		break;  	case SCI_LINEEND: -		MovePositionTo(pdoc->LineEndPosition(currentPos)); +		MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()));  		SetLastXChosen();  		break;  	case SCI_LINEENDEXTEND: -		MovePositionTo(pdoc->LineEndPosition(currentPos), selStream); +		MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_LINEENDRECTEXTEND: -		MovePositionTo(pdoc->LineEndPosition(currentPos), selRectangle); +		MovePositionTo(pdoc->LineEndPosition(sel.MainCaret()), Selection::selRectangle);  		SetLastXChosen();  		break;  	case SCI_HOMEWRAP: { -			int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1); -			if (currentPos <= homePos) -				homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos)); +			SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); +			if (sel.RangeMain().caret <= homePos) +				homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret())));  			MovePositionTo(homePos);  			SetLastXChosen();  		}  		break;  	case SCI_HOMEWRAPEXTEND: { -			int homePos = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1); -			if (currentPos <= homePos) -				homePos = pdoc->LineStart(pdoc->LineFromPosition(currentPos)); -			MovePositionTo(homePos, selStream); +			SelectionPosition homePos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); +			if (sel.RangeMain().caret <= homePos) +				homePos = SelectionPosition(pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()))); +			MovePositionTo(homePos, Selection::selStream);  			SetLastXChosen();  		}  		break;  	case SCI_LINEENDWRAP: { -			int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1); -			int realEndPos = pdoc->LineEndPosition(currentPos); +			SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1); +			SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));  			if (endPos > realEndPos      // if moved past visible EOLs -			        || currentPos >= endPos) // if at end of display line already +			        || sel.RangeMain().caret >= endPos) // if at end of display line already  				endPos = realEndPos;  			MovePositionTo(endPos);  			SetLastXChosen();  		}  		break;  	case SCI_LINEENDWRAPEXTEND: { -			int endPos = MovePositionSoVisible(StartEndDisplayLine(currentPos, false), 1); -			int realEndPos = pdoc->LineEndPosition(currentPos); +			SelectionPosition endPos = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), false), 1); +			SelectionPosition realEndPos = SelectionPosition(pdoc->LineEndPosition(sel.MainCaret()));  			if (endPos > realEndPos      // if moved past visible EOLs -			        || currentPos >= endPos) // if at end of display line already +			        || sel.RangeMain().caret >= endPos) // if at end of display line already  				endPos = realEndPos; -			MovePositionTo(endPos, selStream); +			MovePositionTo(endPos, Selection::selStream);  			SetLastXChosen();  		}  		break; @@ -4603,7 +4802,7 @@ int Editor::KeyCommand(unsigned int iMessage) {  		SetLastXChosen();  		break;  	case SCI_DOCUMENTSTARTEXTEND: -		MovePositionTo(0, selStream); +		MovePositionTo(0, Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_DOCUMENTEND: @@ -4611,38 +4810,38 @@ int Editor::KeyCommand(unsigned int iMessage) {  		SetLastXChosen();  		break;  	case SCI_DOCUMENTENDEXTEND: -		MovePositionTo(pdoc->Length(), selStream); +		MovePositionTo(pdoc->Length(), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_STUTTEREDPAGEUP: -		PageMove(-1, noSel, true); +		PageMove(-1, Selection::noSel, true);  		break;  	case SCI_STUTTEREDPAGEUPEXTEND: -		PageMove(-1, selStream, true); +		PageMove(-1, Selection::selStream, true);  		break;  	case SCI_STUTTEREDPAGEDOWN: -		PageMove(1, noSel, true); +		PageMove(1, Selection::noSel, true);  		break;  	case SCI_STUTTEREDPAGEDOWNEXTEND: -		PageMove(1, selStream, true); +		PageMove(1, Selection::selStream, true);  		break;  	case SCI_PAGEUP:  		PageMove(-1);  		break;  	case SCI_PAGEUPEXTEND: -		PageMove(-1, selStream); +		PageMove(-1, Selection::selStream);  		break;  	case SCI_PAGEUPRECTEXTEND: -		PageMove(-1, selRectangle); +		PageMove(-1, Selection::selRectangle);  		break;  	case SCI_PAGEDOWN:  		PageMove(1);  		break;  	case SCI_PAGEDOWNEXTEND: -		PageMove(1, selStream); +		PageMove(1, Selection::selStream);  		break;  	case SCI_PAGEDOWNRECTEXTEND: -		PageMove(1, selRectangle); +		PageMove(1, Selection::selRectangle);  		break;  	case SCI_EDITTOGGLEOVERTYPE:  		inOverstrike = !inOverstrike; @@ -4691,21 +4890,21 @@ int Editor::KeyCommand(unsigned int iMessage) {  		AddChar('\f');  		break;  	case SCI_VCHOME: -		MovePositionTo(pdoc->VCHomePosition(currentPos)); +		MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()));  		SetLastXChosen();  		break;  	case SCI_VCHOMEEXTEND: -		MovePositionTo(pdoc->VCHomePosition(currentPos), selStream); +		MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_VCHOMERECTEXTEND: -		MovePositionTo(pdoc->VCHomePosition(currentPos), selRectangle); +		MovePositionTo(pdoc->VCHomePosition(sel.MainCaret()), Selection::selRectangle);  		SetLastXChosen();  		break;  	case SCI_VCHOMEWRAP: { -			int homePos = pdoc->VCHomePosition(currentPos); -			int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1); -			if ((viewLineStart < currentPos) && (viewLineStart > homePos)) +			SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); +			SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); +			if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))  				homePos = viewLineStart;  			MovePositionTo(homePos); @@ -4713,12 +4912,12 @@ int Editor::KeyCommand(unsigned int iMessage) {  		}  		break;  	case SCI_VCHOMEWRAPEXTEND: { -			int homePos = pdoc->VCHomePosition(currentPos); -			int viewLineStart = MovePositionSoVisible(StartEndDisplayLine(currentPos, true), -1); -			if ((viewLineStart < currentPos) && (viewLineStart > homePos)) +			SelectionPosition homePos = SelectionPosition(pdoc->VCHomePosition(sel.MainCaret())); +			SelectionPosition viewLineStart = MovePositionSoVisible(StartEndDisplayLine(sel.MainCaret(), true), -1); +			if ((viewLineStart < sel.RangeMain().caret) && (viewLineStart > homePos))  				homePos = viewLineStart; -			MovePositionTo(homePos, selStream); +			MovePositionTo(homePos, Selection::selStream);  			SetLastXChosen();  		}  		break; @@ -4737,32 +4936,32 @@ int Editor::KeyCommand(unsigned int iMessage) {  		}  		break;  	case SCI_DELWORDLEFT: { -			int startWord = pdoc->NextWordStart(currentPos, -1); -			pdoc->DeleteChars(startWord, currentPos - startWord); +			int startWord = pdoc->NextWordStart(sel.MainCaret(), -1); +			pdoc->DeleteChars(startWord, sel.MainCaret() - startWord);  			SetLastXChosen();  		}  		break;  	case SCI_DELWORDRIGHT: { -			int endWord = pdoc->NextWordStart(currentPos, 1); -			pdoc->DeleteChars(currentPos, endWord - currentPos); +			int endWord = pdoc->NextWordStart(sel.MainCaret(), 1); +			pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());  		}  		break;  	case SCI_DELWORDRIGHTEND: { -			int endWord = pdoc->NextWordEnd(currentPos, 1); -			pdoc->DeleteChars(currentPos, endWord - currentPos); +			int endWord = pdoc->NextWordEnd(sel.MainCaret(), 1); +			pdoc->DeleteChars(sel.MainCaret(), endWord - sel.MainCaret());  		}  		break;  	case SCI_DELLINELEFT: { -			int line = pdoc->LineFromPosition(currentPos); +			int line = pdoc->LineFromPosition(sel.MainCaret());  			int start = pdoc->LineStart(line); -			pdoc->DeleteChars(start, currentPos - start); +			pdoc->DeleteChars(start, sel.MainCaret() - start);  			SetLastXChosen();  		}  		break;  	case SCI_DELLINERIGHT: { -			int line = pdoc->LineFromPosition(currentPos); +			int line = pdoc->LineFromPosition(sel.MainCaret());  			int end = pdoc->LineEnd(line); -			pdoc->DeleteChars(currentPos, end - currentPos); +			pdoc->DeleteChars(sel.MainCaret(), end - sel.MainCaret());  		}  		break;  	case SCI_LINECOPY: { @@ -4783,7 +4982,7 @@ int Editor::KeyCommand(unsigned int iMessage) {  		}  		break;  	case SCI_LINEDELETE: { -			int line = pdoc->LineFromPosition(currentPos); +			int line = pdoc->LineFromPosition(sel.MainCaret());  			int start = pdoc->LineStart(line);  			int end = pdoc->LineStart(line + 1);  			pdoc->DeleteChars(start, end - start); @@ -4805,39 +5004,39 @@ int Editor::KeyCommand(unsigned int iMessage) {  		ChangeCaseOfSelection(true);  		break;  	case SCI_WORDPARTLEFT: -		MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1)); +		MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1));  		SetLastXChosen();  		break;  	case SCI_WORDPARTLEFTEXTEND: -		MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(currentPos), -1), selStream); +		MovePositionTo(MovePositionSoVisible(pdoc->WordPartLeft(sel.MainCaret()), -1), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_WORDPARTRIGHT: -		MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1)); +		MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1));  		SetLastXChosen();  		break;  	case SCI_WORDPARTRIGHTEXTEND: -		MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(currentPos), 1), selStream); +		MovePositionTo(MovePositionSoVisible(pdoc->WordPartRight(sel.MainCaret()), 1), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_HOMEDISPLAY:  		MovePositionTo(MovePositionSoVisible( -		            StartEndDisplayLine(currentPos, true), -1)); +		            StartEndDisplayLine(sel.MainCaret(), true), -1));  		SetLastXChosen();  		break;  	case SCI_HOMEDISPLAYEXTEND:  		MovePositionTo(MovePositionSoVisible( -		            StartEndDisplayLine(currentPos, true), -1), selStream); +		            StartEndDisplayLine(sel.MainCaret(), true), -1), Selection::selStream);  		SetLastXChosen();  		break;  	case SCI_LINEENDDISPLAY:  		MovePositionTo(MovePositionSoVisible( -		            StartEndDisplayLine(currentPos, false), 1)); +		            StartEndDisplayLine(sel.MainCaret(), false), 1));  		SetLastXChosen();  		break;  	case SCI_LINEENDDISPLAYEXTEND:  		MovePositionTo(MovePositionSoVisible( -		            StartEndDisplayLine(currentPos, false), 1), selStream); +		            StartEndDisplayLine(sel.MainCaret(), false), 1), Selection::selStream);  		SetLastXChosen();  		break;  	} @@ -4874,13 +5073,13 @@ int Editor::GetWhitespaceVisible() {  void Editor::Indent(bool forwards) {  	//Platform::DebugPrintf("INdent %d\n", forwards); -	int lineOfAnchor = pdoc->LineFromPosition(anchor); -	int lineCurrentPos = pdoc->LineFromPosition(currentPos); +	int lineOfAnchor = pdoc->LineFromPosition(sel.MainAnchor()); +	int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret());  	if (lineOfAnchor == lineCurrentPos) {  		if (forwards) {  			pdoc->BeginUndoAction();  			ClearSelection(); -			if (pdoc->GetColumn(currentPos) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) && +			if (pdoc->GetColumn(sel.MainCaret()) <= pdoc->GetColumn(pdoc->GetLineIndentPosition(lineCurrentPos)) &&  			        pdoc->tabIndents) {  				int indentation = pdoc->GetLineIndentation(lineCurrentPos);  				int indentationStep = pdoc->IndentSize(); @@ -4888,22 +5087,22 @@ void Editor::Indent(bool forwards) {  				SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));  			} else {  				if (pdoc->useTabs) { -					pdoc->InsertChar(currentPos, '\t'); -					SetEmptySelection(currentPos + 1); +					pdoc->InsertChar(sel.MainCaret(), '\t'); +					SetEmptySelection(sel.MainCaret() + 1);  				} else {  					int numSpaces = (pdoc->tabInChars) - -					        (pdoc->GetColumn(currentPos) % (pdoc->tabInChars)); +					        (pdoc->GetColumn(sel.MainCaret()) % (pdoc->tabInChars));  					if (numSpaces < 1)  						numSpaces = pdoc->tabInChars;  					for (int i = 0; i < numSpaces; i++) { -						pdoc->InsertChar(currentPos + i, ' '); +						pdoc->InsertChar(sel.MainCaret() + i, ' ');  					} -					SetEmptySelection(currentPos + numSpaces); +					SetEmptySelection(sel.MainCaret() + numSpaces);  				}  			}  			pdoc->EndUndoAction();  		} else { -			if (pdoc->GetColumn(currentPos) <= pdoc->GetLineIndentation(lineCurrentPos) && +			if (pdoc->GetColumn(sel.MainCaret()) <= pdoc->GetLineIndentation(lineCurrentPos) &&  			        pdoc->tabIndents) {  				pdoc->BeginUndoAction();  				int indentation = pdoc->GetLineIndentation(lineCurrentPos); @@ -4912,23 +5111,23 @@ void Editor::Indent(bool forwards) {  				SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos));  				pdoc->EndUndoAction();  			} else { -				int newColumn = ((pdoc->GetColumn(currentPos) - 1) / pdoc->tabInChars) * +				int newColumn = ((pdoc->GetColumn(sel.MainCaret()) - 1) / pdoc->tabInChars) *  				        pdoc->tabInChars;  				if (newColumn < 0)  					newColumn = 0; -				int newPos = currentPos; +				int newPos = sel.MainCaret();  				while (pdoc->GetColumn(newPos) > newColumn)  					newPos--;  				SetEmptySelection(newPos);  			}  		}  	} else { -		int anchorPosOnLine = anchor - pdoc->LineStart(lineOfAnchor); -		int currentPosPosOnLine = currentPos - pdoc->LineStart(lineCurrentPos); +		int anchorPosOnLine = sel.MainAnchor() - pdoc->LineStart(lineOfAnchor); +		int currentPosPosOnLine = sel.MainCaret() - pdoc->LineStart(lineCurrentPos);  		// Multiple lines selected so indent / dedent  		int lineTopSel = Platform::Minimum(lineOfAnchor, lineCurrentPos);  		int lineBottomSel = Platform::Maximum(lineOfAnchor, lineCurrentPos); -		if (pdoc->LineStart(lineBottomSel) == anchor || pdoc->LineStart(lineBottomSel) == currentPos) +		if (pdoc->LineStart(lineBottomSel) == sel.MainAnchor() || pdoc->LineStart(lineBottomSel) == sel.MainCaret())  			lineBottomSel--;  	// If not selecting any characters on a line, do not indent  		pdoc->BeginUndoAction();  		pdoc->Indent(forwards, lineBottomSel, lineTopSel); @@ -5079,75 +5278,60 @@ char *Editor::CopyRange(int start, int end) {  	return text;  } -void Editor::CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end) { -	bool isLine = allowLineCopy && (start == end); -	if (isLine) { -		int currentLine = pdoc->LineFromPosition(currentPos); -		start = pdoc->LineStart(currentLine); -		end = pdoc->LineEnd(currentLine); - -		char *text = CopyRange(start, end); -		int textLen = text ? strlen(text) : 0; -		// include room for \r\n\0 -		textLen += 3; -		char *textWithEndl = new char[textLen]; -		textWithEndl[0] = '\0'; -		if (text) -			strncat(textWithEndl, text, textLen); -		if (pdoc->eolMode != SC_EOL_LF) -			strncat(textWithEndl, "\r", textLen); -		if (pdoc->eolMode != SC_EOL_CR) -			strncat(textWithEndl, "\n", textLen); -		ss->Set(textWithEndl, strlen(textWithEndl), -			pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true); -		delete []text; -	} else { -		ss->Set(CopyRange(start, end), end - start + 1, -			pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, false); -	} -} -  void Editor::CopySelectionRange(SelectionText *ss, bool allowLineCopy) { -	if (selType == selStream) { -		CopySelectionFromRange(ss, allowLineCopy, SelectionStart(), SelectionEnd()); +	if (sel.Empty()) { +		if (allowLineCopy) { +			int currentLine = pdoc->LineFromPosition(sel.MainCaret()); +			int start = pdoc->LineStart(currentLine); +			int end = pdoc->LineEnd(currentLine); + +			char *text = CopyRange(start, end); +			int textLen = text ? strlen(text) : 0; +			// include room for \r\n\0 +			textLen += 3; +			char *textWithEndl = new char[textLen]; +			textWithEndl[0] = '\0'; +			if (text) +				strncat(textWithEndl, text, textLen); +			if (pdoc->eolMode != SC_EOL_LF) +				strncat(textWithEndl, "\r", textLen); +			if (pdoc->eolMode != SC_EOL_CR) +				strncat(textWithEndl, "\n", textLen); +			ss->Set(textWithEndl, strlen(textWithEndl), +				pdoc->dbcsCodePage, vs.styles[STYLE_DEFAULT].characterSet, false, true); +			delete []text; +		}  	} else { -		char *text = 0; -		int size = 0; -		SelectionLineIterator lineIterator(this); -		while (lineIterator.Iterate()) { -			size += lineIterator.endPos - lineIterator.startPos; -			if (selType != selLines) { -				size++; -				if (pdoc->eolMode == SC_EOL_CRLF) { -					size++; -				} +		int delimiterLength = 0; +		if (sel.selType == Selection::selRectangle) { +			if (pdoc->eolMode == SC_EOL_CRLF) { +				delimiterLength = 2; +			} else { +				delimiterLength = 1;  			}  		} -		if (size > 0) { -			text = new char[size + 1]; -			if (text) { -				int j = 0; -				lineIterator.Reset(); -				while (lineIterator.Iterate()) { -					for (int i = lineIterator.startPos; -					        i < lineIterator.endPos; -					        i++) { -						text[j++] = pdoc->CharAt(i); -					} -					if (selType != selLines) { -						if (pdoc->eolMode != SC_EOL_LF) { -							text[j++] = '\r'; -						} -						if (pdoc->eolMode != SC_EOL_CR) { -							text[j++] = '\n'; -						} -					} +		int size = sel.Length() + delimiterLength * sel.Count(); +		char *text = new char[size + 1]; +		int j = 0; +		for (size_t r=0; r<sel.Count(); r++) { +			SelectionRange current = sel.Range(r); +			for (int i = current.Start().Position(); +			        i < current.End().Position(); +			        i++) { +				text[j++] = pdoc->CharAt(i); +			} +			if (sel.selType == Selection::selRectangle) { +				if (pdoc->eolMode != SC_EOL_LF) { +					text[j++] = '\r'; +				} +				if (pdoc->eolMode != SC_EOL_CR) { +					text[j++] = '\n';  				} -				text[size] = '\0';  			}  		} +		text[size] = '\0';  		ss->Set(text, size + 1, pdoc->dbcsCodePage, -			vs.styles[STYLE_DEFAULT].characterSet, selType == selRectangle, selType == selLines); +			vs.styles[STYLE_DEFAULT].characterSet, sel.IsRectangular(), sel.selType == Selection::selLines);  	}  } @@ -5206,12 +5390,12 @@ void Editor::DropAt(int position, const char *value, bool moving, bool rectangul  	if (inDragDrop == ddDragging)  		dropWentOutside = false; -	int positionWasInSelection = PositionInSelection(position); +	bool positionWasInSelection = PositionInSelection(position);  	bool positionOnEdgeOfSelection =  	    (position == SelectionStart()) || (position == SelectionEnd()); -	if ((inDragDrop != ddDragging) || !(0 == positionWasInSelection) || +	if ((inDragDrop != ddDragging) || !(positionWasInSelection) ||  	        (positionOnEdgeOfSelection && !moving)) {  		int selStart = SelectionStart(); @@ -5222,14 +5406,13 @@ void Editor::DropAt(int position, const char *value, bool moving, bool rectangul  		int positionAfterDeletion = position;  		if ((inDragDrop == ddDragging) && moving) {  			// Remove dragged out text -			if (rectangular || selType == selLines) { -				SelectionLineIterator lineIterator(this); -				while (lineIterator.Iterate()) { -					if (position >= lineIterator.startPos) { -						if (position > lineIterator.endPos) { -							positionAfterDeletion -= lineIterator.endPos - lineIterator.startPos; +			if (rectangular || sel.selType == Selection::selLines) { +				for (size_t r=0; r<sel.Count(); r++) { +					if (position >= sel.Range(r).Start().Position()) { +						if (position > sel.Range(r).End().Position()) { +							positionAfterDeletion -= sel.Range(r).End().Position() - sel.Range(r).Start().Position();  						} else { -							positionAfterDeletion -= position - lineIterator.startPos; +							positionAfterDeletion -= position - sel.Range(r).Start().Position();  						}  					}  				} @@ -5243,12 +5426,12 @@ void Editor::DropAt(int position, const char *value, bool moving, bool rectangul  		position = positionAfterDeletion;  		if (rectangular) { -			PasteRectangular(position, value, istrlen(value)); +			PasteRectangular(SelectionPosition(position), value, istrlen(value));  			pdoc->EndUndoAction();  			// Should try to select new rectangle but it may not be a rectangle now so just select the drop position  			SetEmptySelection(position);  		} else { -			position = MovePositionOutsideChar(position, currentPos - position); +			position = MovePositionOutsideChar(position, sel.MainCaret() - position);  			if (pdoc->InsertCString(position, value)) {  				SetSelection(position + istrlen(value), position);  			} @@ -5260,62 +5443,39 @@ void Editor::DropAt(int position, const char *value, bool moving, bool rectangul  }  /** - * @return -1 if given position is before the selection, - *          1 if position is after the selection, - *          0 if position is inside the selection, + * @return true if given position is inside the selection,   */ -int Editor::PositionInSelection(int pos) { -	pos = MovePositionOutsideChar(pos, currentPos - pos); -	if (pos < SelectionStart()) { -		return -1; -	} -	if (pos > SelectionEnd()) { -		return 1; -	} -	if (selType == selStream) { -		return 0; -	} else { -		SelectionLineIterator lineIterator(this); -		lineIterator.SetAt(pdoc->LineFromPosition(pos)); -		if (pos < lineIterator.startPos) { -			return -1; -		} else if (pos > lineIterator.endPos) { -			return 1; -		} else { -			return 0; -		} +bool Editor::PositionInSelection(int pos) { +	pos = MovePositionOutsideChar(pos, sel.MainCaret() - pos); +	for (size_t r=0; r<sel.Count(); r++) { +		if (sel.Range(r).Contains(pos))  +			return true;  	} +	return false;  }  bool Editor::PointInSelection(Point pt) { -	int pos = PositionFromLocation(pt); -	if (0 == PositionInSelection(pos)) { -		// Probably inside, but we must make a finer test -		int selStart, selEnd; -		if (selType == selStream) { -			selStart = SelectionStart(); -			selEnd = SelectionEnd(); -		} else { -			SelectionLineIterator lineIterator(this); -			lineIterator.SetAt(pdoc->LineFromPosition(pos)); -			selStart = lineIterator.startPos; -			selEnd = lineIterator.endPos; -		} -		if (pos == selStart) { -			// see if just before selection -			Point locStart = LocationFromPosition(pos); -			if (pt.x < locStart.x) { -				return false; +	SelectionPosition pos = SPositionFromLocation(pt); +	int xPos = XFromPosition(pos); +	for (size_t r=0; r<sel.Count(); r++) { +		SelectionRange range = sel.Range(r); +		if (range.Contains(pos)) { +			bool hit = true; +			if (pos == range.Start()) { +				// see if just before selection +				if (pt.x < xPos) { +					hit = false; +				}  			} -		} -		if (pos == selEnd) { -			// see if just after selection -			Point locEnd = LocationFromPosition(pos); -			if (pt.x > locEnd.x) { -				return false; +			if (pos == range.End()) { +				// see if just after selection +				if (pt.x > xPos) { +					hit = false; +				}  			} +			if (hit) +				return true;  		} -		return true;  	}  	return false;  } @@ -5358,25 +5518,25 @@ void Editor::DwellEnd(bool mouseMoved) {  void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) {  	//Platform::DebugPrintf("ButtonDown %d %d = %d alt=%d %d\n", curTime, lastClickTime, curTime - lastClickTime, alt, inDragDrop);  	ptMouseLast = pt; -	int newPos = PositionFromLocation(pt); -	newPos = MovePositionOutsideChar(newPos, currentPos - newPos); +	SelectionPosition newPos = SPositionFromLocation(pt); +	newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());  	inDragDrop = ddNone; -	moveExtendsSelection = false; +	sel.SetMoveExtends(false);  	bool processed = NotifyMarginClick(pt, shift, ctrl, alt);  	if (processed)  		return; -	NotifyIndicatorClick(true, newPos, shift, ctrl, alt); +	NotifyIndicatorClick(true, newPos.Position(), shift, ctrl, alt);  	bool inSelMargin = PointInSelMargin(pt);  	if (shift & !inSelMargin) { -		SetSelection(newPos); +		SetSelection(newPos.Position());  	}  	if (((curTime - lastClickTime) < Platform::DoubleClickTime()) && Close(pt, lastClick)) {  		//Platform::DebugPrintf("Double click %d %d = %d\n", curTime, lastClickTime, curTime - lastClickTime);  		SetMouseCapture(true); -		SetEmptySelection(newPos); +		SetEmptySelection(newPos.Position());  		bool doubleClick = false;  		// Stop mouse button bounce changing selection type  		if (!Platform::MouseButtonBounce() || curTime != lastClickTime) { @@ -5387,16 +5547,16 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b  				selectionType = selLine;  			} else {  				selectionType = selChar; -				originalAnchorPos = currentPos; +				originalAnchorPos = sel.MainCaret();  			}  		}  		if (selectionType == selWord) { -			if (currentPos >= originalAnchorPos) {	// Moved forward -				SetSelection(pdoc->ExtendWordSelect(currentPos, 1), +			if (sel.MainCaret() >= originalAnchorPos) {	// Moved forward +				SetSelection(pdoc->ExtendWordSelect(sel.MainCaret(), 1),  				        pdoc->ExtendWordSelect(originalAnchorPos, -1));  			} else {	// Moved backward -				SetSelection(pdoc->ExtendWordSelect(currentPos, -1), +				SetSelection(pdoc->ExtendWordSelect(sel.MainCaret(), -1),  				        pdoc->ExtendWordSelect(originalAnchorPos, 1));  			}  		} else if (selectionType == selLine) { @@ -5404,17 +5564,17 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b  			SetSelection(pdoc->LineStart(lineAnchor + 1), pdoc->LineStart(lineAnchor));  			//Platform::DebugPrintf("Triple click: %d - %d\n", anchor, currentPos);  		} else { -			SetEmptySelection(currentPos); +			SetEmptySelection(sel.MainCaret());  		}  		//Platform::DebugPrintf("Double click: %d - %d\n", anchor, currentPos);  		if (doubleClick) {  			NotifyDoubleClick(pt, shift, ctrl, alt); -			if (PositionIsHotspot(newPos)) -				NotifyHotSpotDoubleClicked(newPos, shift, ctrl, alt); +			if (PositionIsHotspot(newPos.Position())) +				NotifyHotSpotDoubleClicked(newPos.Position(), shift, ctrl, alt);  		}  	} else {	// Single click  		if (inSelMargin) { -			selType = selStream; +			sel.selType = Selection::selStream;  			if (ctrl) {  				SelectAll();  				lastClickTime = curTime; @@ -5428,10 +5588,10 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b  				        pdoc->LineStart(lineAnchor));  			} else {  				// Single shift+click in margin: select from line anchor to clicked line -				if (anchor > currentPos) -					lineAnchor = pdoc->LineFromPosition(anchor - 1); +				if (sel.MainAnchor() > sel.MainCaret()) +					lineAnchor = pdoc->LineFromPosition(sel.MainAnchor() - 1);  				else -					lineAnchor = pdoc->LineFromPosition(anchor); +					lineAnchor = pdoc->LineFromPosition(sel.MainAnchor());  				int lineStart = LineFromLocation(pt);  				LineSelection(lineStart, lineAnchor);  				//lineAnchor = lineStart; // Keep the same anchor for ButtonMove @@ -5442,7 +5602,7 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b  			selectionType = selLine;  		} else {  			if (PointIsHotspot(pt)) { -				NotifyHotSpotClicked(newPos, shift, ctrl, alt); +				NotifyHotSpotClicked(newPos.Position(), shift, ctrl, alt);  			}  			if (!shift) {  				if (PointInSelection(pt) && !SelectionEmpty()) @@ -5453,12 +5613,21 @@ void Editor::ButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, b  			SetMouseCapture(true);  			if (inDragDrop != ddInitial) {  				SetDragPosition(invalidPosition); -				if (!shift) { -					SetEmptySelection(newPos); +				if (ctrl) { +					InvalidateSelection(SelectionRange(newPos), true); +					sel.AddSelection(newPos); +				} else if (!shift) { +					InvalidateSelection(SelectionRange(newPos), true); +					if (sel.Count() > 1)  +						Redraw(); +					sel.Clear(); +					sel.selType = alt ? Selection::selRectangle : Selection::selStream; +					SetSelection(newPos, newPos);  				} -				selType = alt ? selRectangle : selStream; +				sel.selType = alt ? Selection::selRectangle : Selection::selStream;  				selectionType = selChar; -				originalAnchorPos = currentPos; +				originalAnchorPos = sel.MainCaret(); +				sel.Rectangular() = SelectionRange(newPos, newPos);  				SetRectangularRange();  			}  		} @@ -5522,13 +5691,13 @@ void Editor::ButtonMove(Point pt) {  		DwellEnd(true);  	} -	int movePos = PositionFromLocation(pt); -	movePos = MovePositionOutsideChar(movePos, currentPos - movePos); +	SelectionPosition movePos = SPositionFromLocation(pt); +	movePos = MovePositionOutsideChar(movePos, sel.MainCaret() - movePos.Position());  	if (inDragDrop == ddInitial) {  		if (DragThreshold(ptMouseLast, pt)) {  			SetMouseCapture(false); -			SetDragPosition(movePos); +			SetDragPosition(movePos.Position());  			CopySelectionRange(&drag);  			StartDrag();  		} @@ -5547,13 +5716,22 @@ void Editor::ButtonMove(Point pt) {  		// Adjust selection  		if (posDrag >= 0) { -			SetDragPosition(movePos); +			SetDragPosition(movePos.Position());  		} else {  			if (selectionType == selChar) { -				SetSelection(movePos); +				if (sel.IsRectangular()) { +					sel.Rectangular() = SelectionRange(movePos, sel.Rectangular().anchor); +					SetSelection(movePos, sel.RangeMain().anchor); +				} else if (sel.Count() > 1) { +					sel.TrimSelection(sel.RangeMain().anchor, movePos); +					sel.RangeMain() = SelectionRange(movePos, sel.RangeMain().anchor); +					InvalidateSelection(SelectionRange(movePos, sel.RangeMain().anchor), true); +				} else { +					SetSelection(movePos, sel.RangeMain().anchor); +				}  			} else if (selectionType == selWord) {  				// Continue selecting by word -				if (movePos == originalAnchorPos) {	// Didn't move +				if (movePos.Position() == originalAnchorPos) {	// Didn't move  					// No need to do anything. Previously this case was lumped  					// in with "Moved forward", but that can be harmful in this  					// case: a handler for the NotifyDoubleClick re-adjusts @@ -5563,11 +5741,11 @@ void Editor::ButtonMove(Point pt) {  					// the ButtonMove() called via Tick() for auto-scrolling  					// could result in the fancier word selection adjustment  					// being unmade. -				} else if (movePos > originalAnchorPos) {	// Moved forward -					SetSelection(pdoc->ExtendWordSelect(movePos, 1), +				} else if (movePos.Position() > originalAnchorPos) {	// Moved forward +					SetSelection(pdoc->ExtendWordSelect(movePos.Position(), 1),  					        pdoc->ExtendWordSelect(originalAnchorPos, -1));  				} else {	// Moved backward -					SetSelection(pdoc->ExtendWordSelect(movePos, -1), +					SetSelection(pdoc->ExtendWordSelect(movePos.Position(), -1),  					        pdoc->ExtendWordSelect(originalAnchorPos, 1));  				}  			} else { @@ -5576,10 +5754,6 @@ void Editor::ButtonMove(Point pt) {  				LineSelection(lineMove, lineAnchor);  			}  		} -		// While dragging to make rectangular selection, we don't want the current -		// position to jump to the end of smaller or empty lines. -		//xEndSelect = pt.x - vs.fixedColumnWidth + xOffset; -		xEndSelect = XFromPosition(movePos);  		// Autoscroll  		PRectangle rcClient = GetClientRectangle(); @@ -5597,7 +5771,7 @@ void Editor::ButtonMove(Point pt) {  		}  		EnsureCaretVisible(false, false, true); -		if (hsStart != -1 && !PositionIsHotspot(movePos)) +		if (hsStart != -1 && !PositionIsHotspot(movePos.Position()))  			SetHotSpotRange(NULL);  	} else { @@ -5622,11 +5796,11 @@ void Editor::ButtonMove(Point pt) {  void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {  	//Platform::DebugPrintf("ButtonUp %d %d\n", HaveMouseCapture(), inDragDrop); -	int newPos = PositionFromLocation(pt); -	newPos = MovePositionOutsideChar(newPos, currentPos - newPos); +	SelectionPosition newPos = SPositionFromLocation(pt); +	newPos = MovePositionOutsideChar(newPos, sel.MainCaret() - newPos.Position());  	if (inDragDrop == ddInitial) {  		inDragDrop = ddNone; -		SetEmptySelection(newPos); +		SetEmptySelection(newPos.Position());  	}  	if (HaveMouseCapture()) {  		if (PointInSelMargin(pt)) { @@ -5637,31 +5811,29 @@ void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {  		}  		ptMouseLast = pt;  		SetMouseCapture(false); -		int newPos = PositionFromLocation(pt); -		newPos = MovePositionOutsideChar(newPos, currentPos - newPos); -		NotifyIndicatorClick(false, newPos, false, false, false); +		NotifyIndicatorClick(false, newPos.Position(), false, false, false);  		if (inDragDrop == ddDragging) {  			int selStart = SelectionStart();  			int selEnd = SelectionEnd();  			if (selStart < selEnd) {  				if (drag.len) {  					if (ctrl) { -						if (pdoc->InsertString(newPos, drag.s, drag.len)) { -							SetSelection(newPos, newPos + drag.len); +						if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { +							SetSelection(newPos.Position(), newPos.Position() + drag.len);  						} -					} else if (newPos < selStart) { +					} else if (newPos.Position() < selStart) {  						pdoc->DeleteChars(selStart, drag.len); -						if (pdoc->InsertString(newPos, drag.s, drag.len)) { -							SetSelection(newPos, newPos + drag.len); +						if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { +							SetSelection(newPos.Position(), newPos.Position() + drag.len);  						} -					} else if (newPos > selEnd) { +					} else if (newPos.Position() > selEnd) {  						pdoc->DeleteChars(selStart, drag.len); -						newPos -= drag.len; -						if (pdoc->InsertString(newPos, drag.s, drag.len)) { -							SetSelection(newPos, newPos + drag.len); +						newPos.Add(-drag.len); +						if (pdoc->InsertString(newPos.Position(), drag.s, drag.len)) { +							SetSelection(newPos.Position(), newPos.Position() + drag.len);  						}  					} else { -						SetEmptySelection(newPos); +						SetEmptySelection(newPos.Position());  					}  					drag.Free();  				} @@ -5669,14 +5841,20 @@ void Editor::ButtonUp(Point pt, unsigned int curTime, bool ctrl) {  			}  		} else {  			if (selectionType == selChar) { -				SetSelection(newPos); +				if (sel.Count() > 1) { +					sel.RangeMain() =  +						SelectionRange(newPos, sel.Range(sel.Count() - 1).anchor); +					InvalidateSelection(sel.RangeMain(), true); +				} else { +					SetSelection(newPos, sel.RangeMain().anchor); +				}  			}  		}  		SetRectangularRange();  		lastClickTime = curTime;  		lastClick = pt;  		lastXChosen = pt.x; -		if (selType == selStream) { +		if (sel.selType == Selection::selStream) {  			SetLastXChosen();  		}  		inDragDrop = ddNone; @@ -5825,9 +6003,7 @@ void Editor::SetDocPointer(Document *document) {  	pdoc->AddRef();  	// Ensure all positions within document -	selType = selStream; -	currentPos = 0; -	anchor = 0; +	sel.Clear();  	targetStart = 0;  	targetEnd = 0; @@ -5898,7 +6074,7 @@ void Editor::ToggleContraction(int line) {  			if (lineMaxSubord > line) {  				cs.SetVisible(line + 1, lineMaxSubord, false); -				int lineCurrent = pdoc->LineFromPosition(currentPos); +				int lineCurrent = pdoc->LineFromPosition(sel.MainCaret());  				if (lineCurrent > line && lineCurrent <= lineMaxSubord) {  					// This does not re-expand the fold  					EnsureCaretVisible(); @@ -6026,7 +6202,7 @@ void Editor::AddStyledText(char *buffer, int appendLength) {  		pdoc->SetStyles(textLength, text);  		delete []text;  	} -	SetEmptySelection(currentPos + textLength); +	SetEmptySelection(sel.MainCaret() + textLength);  }  static bool ValidMargin(unsigned long wParam) { @@ -6236,7 +6412,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  				nEnd = pdoc->Length();  			if (nStart < 0)  				nStart = nEnd; 	// Remove selection -			selType = selStream; +			sel.selType = Selection::selStream;  			SetSelection(nEnd, nStart);  			EnsureCaretVisible();  		} @@ -6244,17 +6420,16 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  	case SCI_GETSELTEXT: {  			if (lParam == 0) { -				if (selType == selStream) { +				if (sel.selType == Selection::selStream) {  					return 1 + SelectionEnd() - SelectionStart();  				} else {  					// TODO: why is selLines handled the slow way?  					int size = 0;  					int extraCharsPerLine = 0; -					if (selType != selLines) +					if (sel.selType != Selection::selLines)  						extraCharsPerLine = (pdoc->eolMode == SC_EOL_CRLF) ? 2 : 1; -					SelectionLineIterator lineIterator(this); -					while (lineIterator.Iterate()) { -						size += lineIterator.endPos + extraCharsPerLine - lineIterator.startPos; +					for (size_t r=0; r<sel.Count(); r++) { +						size += sel.Range(r).Length() + extraCharsPerLine;  					}  					return 1 + size; @@ -6302,9 +6477,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  			pdoc->BeginUndoAction();  			ClearSelection();  			char *replacement = CharPtrFromSPtr(lParam); -			pdoc->InsertCString(currentPos, replacement); +			pdoc->InsertCString(sel.MainCaret(), replacement);  			pdoc->EndUndoAction(); -			SetEmptySelection(currentPos + istrlen(replacement)); +			SetEmptySelection(sel.MainCaret() + istrlen(replacement));  			EnsureCaretVisible();  		}  		break; @@ -6324,12 +6499,12 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  		return targetEnd;  	case SCI_TARGETFROMSELECTION: -		if (currentPos < anchor) { -			targetStart = currentPos; -			targetEnd = anchor; +		if (sel.MainCaret() < sel.MainAnchor()) { +			targetStart = sel.MainCaret(); +			targetEnd = sel.MainAnchor();  		} else { -			targetStart = anchor; -			targetEnd = currentPos; +			targetStart = sel.MainAnchor(); +			targetEnd = sel.MainCaret();  		}  		break; @@ -6454,7 +6629,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  			if (lParam == 0)  				return 0;  			pdoc->InsertString(CurrentPosition(), CharPtrFromSPtr(lParam), wParam); -			SetEmptySelection(currentPos + wParam); +			SetEmptySelection(sel.MainCaret() + wParam);  			return 0;  		} @@ -6542,32 +6717,32 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  		return pdoc->CharAt(wParam);  	case SCI_SETCURRENTPOS: -		SetSelection(wParam, anchor); +		SetSelection(wParam, sel.MainAnchor());  		break;  	case SCI_GETCURRENTPOS: -		return currentPos; +		return sel.MainCaret();  	case SCI_SETANCHOR: -		SetSelection(currentPos, wParam); +		SetSelection(sel.MainCaret(), wParam);  		break;  	case SCI_GETANCHOR: -		return anchor; +		return sel.MainAnchor();  	case SCI_SETSELECTIONSTART: -		SetSelection(Platform::Maximum(currentPos, wParam), wParam); +		SetSelection(Platform::Maximum(sel.MainCaret(), wParam), wParam);  		break;  	case SCI_GETSELECTIONSTART: -		return Platform::Minimum(anchor, currentPos); +		return Platform::Minimum(sel.MainAnchor(), sel.MainCaret());  	case SCI_SETSELECTIONEND: -		SetSelection(wParam, Platform::Minimum(anchor, wParam)); +		SetSelection(wParam, Platform::Minimum(sel.MainAnchor(), wParam));  		break;  	case SCI_GETSELECTIONEND: -		return Platform::Maximum(anchor, currentPos); +		return Platform::Maximum(sel.MainAnchor(), sel.MainCaret());  	case SCI_SETPRINTMAGNIFICATION:  		printMagnification = wParam; @@ -6663,7 +6838,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  		break;  	case SCI_GETCURLINE: { -			int lineCurrentPos = pdoc->LineFromPosition(currentPos); +			int lineCurrentPos = pdoc->LineFromPosition(sel.MainCaret());  			int lineStart = pdoc->LineStart(lineCurrentPos);  			unsigned int lineEnd = pdoc->LineStart(lineCurrentPos + 1);  			if (lParam == 0) { @@ -6676,7 +6851,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  				ptr[iPlace++] = pdoc->CharAt(iChar);  			}  			ptr[iPlace] = '\0'; -			return currentPos - lineStart; +			return sel.MainCaret() - lineStart;  		}  	case SCI_GETENDSTYLED: @@ -7621,7 +7796,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  	case SCI_CONVERTEOLS:  		pdoc->ConvertLineEnds(wParam); -		SetSelection(currentPos, anchor);	// Ensure selection inside document +		SetSelection(sel.MainCaret(), sel.MainAnchor());	// Ensure selection inside document  		return 0;  	case SCI_SETLENGTHFORENCODE: @@ -7629,48 +7804,57 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  		return 0;  	case SCI_SELECTIONISRECTANGLE: -		return selType == selRectangle ? 1 : 0; +		return sel.selType == Selection::selRectangle ? 1 : 0;  	case SCI_SETSELECTIONMODE: {  			switch (wParam) {  			case SC_SEL_STREAM: -				moveExtendsSelection = !moveExtendsSelection || (selType != selStream); -				selType = selStream; +				sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream)); +				sel.selType = Selection::selStream;  				break;  			case SC_SEL_RECTANGLE: -				moveExtendsSelection = !moveExtendsSelection || (selType != selRectangle); -				selType = selRectangle; +				sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selRectangle)); +				sel.selType = Selection::selRectangle;  				break;  			case SC_SEL_LINES: -				moveExtendsSelection = !moveExtendsSelection || (selType != selLines); -				selType = selLines; +				sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selLines)); +				sel.selType = Selection::selLines; +				break; +			case SC_SEL_THIN: +				sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selThin)); +				sel.selType = Selection::selThin;  				break;  			default: -				moveExtendsSelection = !moveExtendsSelection || (selType != selStream); -				selType = selStream; +				sel.SetMoveExtends(!sel.MoveExtends() || (sel.selType != Selection::selStream)); +				sel.selType = Selection::selStream;  			} -			InvalidateSelection(currentPos, anchor, true); +			InvalidateSelection(sel.RangeMain(), true);  		}  	case SCI_GETSELECTIONMODE: -		switch (selType) { -		case selStream: +		switch (sel.selType) { +		case Selection::selStream:  			return SC_SEL_STREAM; -		case selRectangle: +		case Selection::selRectangle:  			return SC_SEL_RECTANGLE; -		case selLines: +		case Selection::selLines:  			return SC_SEL_LINES; +		case Selection::selThin: +			return SC_SEL_THIN;  		default:	// ?!  			return SC_SEL_STREAM;  		} -	case SCI_GETLINESELSTARTPOSITION: { -			SelectionLineIterator lineIterator(this); -			lineIterator.SetAt(wParam); -			return lineIterator.startPos; -		} +	case SCI_GETLINESELSTARTPOSITION:  	case SCI_GETLINESELENDPOSITION: { -			SelectionLineIterator lineIterator(this); -			lineIterator.SetAt(wParam); -			return lineIterator.endPos; +			for (size_t r=0; r<sel.Count(); r++) { +				int posLineStart = pdoc->LineStart(wParam); +				int posLineEnd = pdoc->LineEnd(wParam); +				SelectionPosition spStart; +				SelectionPosition spEnd; +				if (sel.Range(r).Intersect(posLineStart, posLineEnd, spStart, spEnd)) { +					return (iMessage == SCI_GETLINESELSTARTPOSITION) ? spStart.Position() : spEnd.Position(); +				} +			} +			return INVALID_POSITION;  		}  	case SCI_SETOVERTYPE: @@ -7916,6 +8100,147 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {  		pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE);  		break; +	case SCI_SETMULTILINECARET: +		multiLineCaret = wParam != 0; +		InvalidateCaret(); +		break; + +	case SCI_GETMULTILINECARET: +		return multiLineCaret; + +	case SCI_SETMULTILINECARETBLINKS: +		multiLineCaretBlinks = wParam != 0; +		InvalidateCaret(); +		break; + +	case SCI_GETMULTILINECARETBLINKS: +		return multiLineCaretBlinks; + +	case SCI_GETSELECTIONS: +		return sel.Count(); + +	case SCI_CLEARSELECTIONS: +		sel.Clear(); +		Redraw(); +		break; + +	case SCI_SETSELECTION: +		sel.Clear(); +		sel.RangeMain() = SelectionRange(wParam, lParam); +		Redraw(); +		break; + +	case SCI_ADDSELECTION: +		sel.AddSelection(SelectionPosition(wParam), SelectionPosition(lParam), false); +		Redraw(); +		break; + +	case SCI_SETMAINSELECTION: +		sel.SetMain(wParam); +		Redraw(); +		break; + +	case SCI_GETMAINSELECTION: +		return sel.Main(); + +	case SCI_SETSELECTIONNCARET: +		sel.Range(wParam).caret.SetPosition(lParam); +		Redraw(); +		break; + +	case SCI_GETSELECTIONNCARET: +		return sel.Range(wParam).caret.Position(); + +	case SCI_SETSELECTIONNANCHOR: +		sel.Range(wParam).anchor.SetPosition(lParam); +		Redraw(); +		break; +	case SCI_GETSELECTIONNANCHOR: +		return sel.Range(wParam).anchor.Position(); + +	case SCI_SETSELECTIONNCARETVIRTUALSPACE: +		sel.Range(wParam).caret.SetVirtualSpace(lParam); +		Redraw(); +		break; + +	case SCI_GETSELECTIONNCARETVIRTUALSPACE: +		return sel.Range(wParam).caret.VirtualSpace(); + +	case SCI_SETSELECTIONNANCHORVIRTUALSPACE: +		sel.Range(wParam).anchor.SetVirtualSpace(lParam); +		Redraw(); +		break; + +	case SCI_GETSELECTIONNANCHORVIRTUALSPACE: +		return sel.Range(wParam).anchor.VirtualSpace(); + +	case SCI_SETSELECTIONNSTART: +		sel.Range(wParam).anchor.SetPosition(lParam); +		Redraw(); +		break; + +	case SCI_GETSELECTIONNSTART: +		return sel.Range(wParam).Start().Position(); + +	case SCI_SETSELECTIONNEND: +		sel.Range(wParam).caret.SetPosition(lParam); +		Redraw(); +		break; + +	case SCI_GETSELECTIONNEND: +		return sel.Range(wParam).End().Position(); + +	case SCI_SETRECTANGULARSELECTIONCARET: +		if (!sel.IsRectangular())  +			sel.Clear(); +		sel.selType = Selection::selRectangle; +		sel.Rectangular().caret.SetPosition(wParam); +		Redraw(); +		break; + +	case SCI_GETRECTANGULARSELECTIONCARET: +		return sel.Rectangular().caret.Position(); + +	case SCI_SETRECTANGULARSELECTIONANCHOR: +		if (!sel.IsRectangular())  +			sel.Clear(); +		sel.selType = Selection::selRectangle; +		sel.Rectangular().anchor.SetPosition(wParam); +		Redraw(); +		break; + +	case SCI_GETRECTANGULARSELECTIONANCHOR: +		return sel.Rectangular().anchor.Position(); + +	case SCI_SETRECTANGULARSELECTIONCARETVIRTUALSPACE: +		if (!sel.IsRectangular())  +			sel.Clear(); +		sel.selType = Selection::selRectangle; +		sel.Rectangular().caret.SetVirtualSpace(wParam); +		Redraw(); +		break; + +	case SCI_GETRECTANGULARSELECTIONCARETVIRTUALSPACE: +		return sel.Rectangular().caret.VirtualSpace(); + +	case SCI_SETRECTANGULARSELECTIONANCHORVIRTUALSPACE: +		if (!sel.IsRectangular())  +			sel.Clear(); +		sel.selType = Selection::selRectangle; +		sel.Rectangular().anchor.SetVirtualSpace(wParam); +		Redraw(); +		break; + +	case SCI_GETRECTANGULARSELECTIONANCHORVIRTUALSPACE: +		return sel.Rectangular().anchor.VirtualSpace(); + +	case SCI_SETVIRTUALSPACEOPTIONS: +		virtualSpaceOptions = wParam; +		break; + +	case SCI_GETVIRTUALSPACEOPTIONS: +		return virtualSpaceOptions; +  	default:  		return DefWndProc(iMessage, wParam, lParam);  	} diff --git a/src/Editor.h b/src/Editor.h index a318e6282..ab1e9a1e8 100644 --- a/src/Editor.h +++ b/src/Editor.h @@ -143,6 +143,10 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	bool verticalScrollBarVisible;  	bool endAtLastLine;  	bool caretSticky; +	bool multiLineCaret; +	bool multiLineCaretBlinks; + +	int virtualSpaceOptions;  	Surface *pixmapLine;  	Surface *pixmapSelMargin; @@ -176,8 +180,6 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	int lastXChosen;  	int lineAnchor;  	int originalAnchorPos; -	int currentPos; -	int anchor;  	int targetStart;  	int targetEnd;  	int searchFlags; @@ -199,11 +201,7 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	int modEventMask;  	SelectionText drag; -	enum selTypes { noSel, selStream, selRectangle, selLines }; -	selTypes selType; -	bool moveExtendsSelection; -	int xStartSelect;	///< x position of start of rectangular selection -	int xEndSelect;		///< x position of end of rectangular selection +	Selection sel;  	bool primarySelection;  	int caretXPolicy; @@ -259,9 +257,13 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	int LinesOnScreen();  	int LinesToScroll();  	int MaxScrollPos(); +	SelectionPosition ClampPositionIntoDocument(SelectionPosition sp) const;  	Point LocationFromPosition(int pos);  	int XFromPosition(int pos); +	int XFromPosition(SelectionPosition sp); +	SelectionPosition SPositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false, bool virtualSpace=true);  	int PositionFromLocation(Point pt, bool canReturnInvalid=false, bool charPosition=false); +	SelectionPosition SPositionFromLineX(int lineDoc, int x);  	int PositionFromLineX(int line, int x);  	int LineFromLocation(Point pt);  	void SetTopLine(int topLineNew); @@ -278,15 +280,21 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	int SelectionStart();  	int SelectionEnd();  	void SetRectangularRange(); -	void InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection); +	void InvalidateSelection(SelectionRange newMain, bool invalidateWholeSelection=false); +	void SetSelection(SelectionPosition currentPos_, SelectionPosition anchor_);  	void SetSelection(int currentPos_, int anchor_); +	void SetSelection(SelectionPosition currentPos_);  	void SetSelection(int currentPos_); +	void SetEmptySelection(SelectionPosition currentPos_);  	void SetEmptySelection(int currentPos_);  	bool RangeContainsProtected(int start, int end) const;  	bool SelectionContainsProtected();  	int MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd=true) const; -	int MovePositionTo(int newPos, selTypes sel=noSel, bool ensureVisible=true); -	int MovePositionSoVisible(int pos, int moveDir); +	SelectionPosition MovePositionOutsideChar(SelectionPosition pos, int moveDir, bool checkLineEnd=true) const; +	int MovePositionTo(SelectionPosition newPos, Selection::selTypes sel=Selection::noSel, bool ensureVisible=true); +	int MovePositionTo(int newPos, Selection::selTypes sel=Selection::noSel, bool ensureVisible=true); +	SelectionPosition MovePositionSoVisible(SelectionPosition pos, int moveDir); +	SelectionPosition MovePositionSoVisible(int pos, int moveDir);  	void SetLastXChosen();  	void ScrollTo(int line, bool moveThumb=true); @@ -324,8 +332,10 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	void DrawAnnotation(Surface *surface, ViewStyle &vsDraw, int line, int xStart,          PRectangle rcLine, LineLayout *ll, int subLine);  	void DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVisible, int xStart, -		PRectangle rcLine, LineLayout *ll, int subLine=0); +		PRectangle rcLine, LineLayout *ll, int subLine);  	void DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret); +	void DrawCarets(Surface *surface, ViewStyle &vsDraw, int line, int xStart, +		PRectangle rcLine, LineLayout *ll, int subLine);  	void RefreshPixMaps(Surface *surfaceWindow);  	void Paint(Surface *surfaceWindow, PRectangle rcArea);  	long FormatRange(bool draw, Sci_RangeToFormat *pfr); @@ -344,7 +354,7 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	void ClearAll();  	void ClearDocumentStyle();  	void Cut(); -	void PasteRectangular(int pos, const char *ptr, int len); +	void PasteRectangular(SelectionPosition pos, const char *ptr, int len);  	virtual void Copy() = 0;  	virtual void CopyAllowLine();  	virtual bool CanPaste(); @@ -384,14 +394,14 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	void NotifyStyleNeeded(Document *doc, void *userData, int endPos);  	void NotifyMacroRecord(unsigned int iMessage, uptr_t wParam, sptr_t lParam); -	void PageMove(int direction, selTypes sel=noSel, bool stuttered = false); +	void PageMove(int direction, Selection::selTypes sel=Selection::noSel, bool stuttered = false);  	void ChangeCaseOfSelection(bool makeUpperCase);  	void LineTranspose();  	void Duplicate(bool forLine);  	virtual void CancelModes();  	void NewLine(); -	void CursorUpOrDown(int direction, selTypes sel=noSel); -	void ParaUpOrDown(int direction, selTypes sel=noSel); +	void CursorUpOrDown(int direction, Selection::selTypes sel=Selection::noSel); +	void ParaUpOrDown(int direction, Selection::selTypes sel=Selection::noSel);  	int StartEndDisplayLine(int pos, bool start);  	virtual int KeyCommand(unsigned int iMessage);  	virtual int KeyDefault(int /* key */, int /*modifiers*/); @@ -410,7 +420,6 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	virtual void CopyToClipboard(const SelectionText &selectedText) = 0;  	char *CopyRange(int start, int end); -	void CopySelectionFromRange(SelectionText *ss, bool allowLineCopy, int start, int end);  	void CopySelectionRange(SelectionText *ss, bool allowLineCopy=false);  	void CopyRangeToClipboard(int start, int end);  	void CopyText(int length, const char *text); @@ -419,9 +428,8 @@ protected:	// ScintillaBase subclass needs access to much of Editor  	virtual bool DragThreshold(Point ptStart, Point ptNow);  	virtual void StartDrag();  	void DropAt(int position, const char *value, bool moving, bool rectangular); -	/** PositionInSelection returns 0 if position in selection, -1 if position before selection, and 1 if after. -	 * Before means either before any line of selection or before selection on its line, with a similar meaning to after. */ -	int PositionInSelection(int pos); +	/** PositionInSelection returns true if position in selection. */ +	bool PositionInSelection(int pos);  	bool PointInSelection(Point pt);  	bool PointInSelMargin(Point pt);  	void LineSelection(int lineCurrent_, int lineAnchor_); diff --git a/src/PositionCache.cxx b/src/PositionCache.cxx index 71b408236..258a14860 100644 --- a/src/PositionCache.cxx +++ b/src/PositionCache.cxx @@ -28,6 +28,7 @@  #include "CharClassify.h"  #include "Decoration.h"  #include "Document.h" +#include "Selection.h"  #include "PositionCache.h"  #ifdef SCI_NAMESPACE @@ -46,11 +47,11 @@ LineLayout::LineLayout(int maxLineLength_) :  	inCache(false),  	maxLineLength(-1),  	numCharsInLine(0), +	numCharsBeforeEOL(0),  	validity(llInvalid),  	xHighlightGuide(0),  	highlightColumn(0), -	selStart(0), -	selEnd(0), +	psel(NULL),  	containsCaret(false),  	edgeColumn(0),  	chars(0), @@ -115,12 +116,7 @@ int LineLayout::LineLastVisible(int line) const {  	if (line < 0) {  		return 0;  	} else if ((line >= lines-1) || !lineStarts) { -		int startLine = LineStart(line); -		int endLine = numCharsInLine; -		while ((endLine > startLine) && IsEOLChar(chars[endLine-1])) { -			endLine--; -		} -		return endLine; +		return numCharsBeforeEOL;  	} else {  		return lineStarts[line+1];  	} @@ -412,9 +408,13 @@ BreakFinder::BreakFinder(LineLayout *ll_, int lineStart_, int lineEnd_, int posL  		nextBreak--;  	} -	if (ll->selStart != ll->selEnd) { -		Insert(ll->selStart - posLineStart - 1); -		Insert(ll->selEnd - posLineStart - 1); +	for (size_t r=0; r<ll->psel->Count(); r++) { +		SelectionPosition spStart; +		SelectionPosition spEnd; +		if (ll->psel->Range(r).Intersect(posLineStart, posLineStart + lineEnd, spStart, spEnd)) { +			Insert(spStart.Position() - posLineStart - 1); +			Insert(spEnd.Position() - posLineStart - 1); +		}  	}  	Insert(ll->edgeColumn - 1); diff --git a/src/PositionCache.h b/src/PositionCache.h index 6c4c62efd..bd984d40b 100644 --- a/src/PositionCache.h +++ b/src/PositionCache.h @@ -2,7 +2,7 @@  /** @file PositionCache.h   ** Classes for caching layout information.   **/ -// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org> +// Copyright 1998-2009 by Neil Hodgson <neilh@scintilla.org>  // The License.txt file describes the conditions under which this software may be distributed.  #ifndef POSITIONCACHE_H @@ -30,11 +30,11 @@ public:  	enum { wrapWidthInfinite = 0x7ffffff };  	int maxLineLength;  	int numCharsInLine; +	int numCharsBeforeEOL;  	enum validLevel { llInvalid, llCheckTextAndStyle, llPositions, llLines } validity;  	int xHighlightGuide;  	bool highlightColumn; -	int selStart; -	int selEnd; +	Selection *psel;  	bool containsCaret;  	int edgeColumn;  	char *chars; diff --git a/src/ScintillaBase.cxx b/src/ScintillaBase.cxx index 31e580336..b47986ff0 100644 --- a/src/ScintillaBase.cxx +++ b/src/ScintillaBase.cxx @@ -36,6 +36,7 @@  #include "CharClassify.h"  #include "Decoration.h"  #include "Document.h" +#include "Selection.h"  #include "PositionCache.h"  #include "Editor.h"  #include "ScintillaBase.h" @@ -190,7 +191,7 @@ int ScintillaBase::KeyCommand(unsigned int iMessage) {  			ct.CallTipCancel();  		}  		if ((iMessage == SCI_DELETEBACK) || (iMessage == SCI_DELETEBACKNOTLINE)) { -			if (currentPos <= ct.posStartCallTip) { +			if (sel.MainCaret() <= ct.posStartCallTip) {  				ct.CallTipCancel();  			}  		} @@ -212,24 +213,24 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {  			const char *typeSep = strchr(list, ac.GetTypesep());  			size_t lenInsert = (typeSep) ? (typeSep-list) : strlen(list);  			if (ac.ignoreCase) { -				SetEmptySelection(currentPos - lenEntered); -				pdoc->DeleteChars(currentPos, lenEntered); -				SetEmptySelection(currentPos); -				pdoc->InsertString(currentPos, list, lenInsert); -				SetEmptySelection(currentPos + lenInsert); +				SetEmptySelection(sel.MainCaret() - lenEntered); +				pdoc->DeleteChars(sel.MainCaret(), lenEntered); +				SetEmptySelection(sel.MainCaret()); +				pdoc->InsertString(sel.MainCaret(), list, lenInsert); +				SetEmptySelection(sel.MainCaret() + lenInsert);  			} else { -				SetEmptySelection(currentPos); -				pdoc->InsertString(currentPos, list + lenEntered, lenInsert - lenEntered); -				SetEmptySelection(currentPos + lenInsert - lenEntered); +				SetEmptySelection(sel.MainCaret()); +				pdoc->InsertString(sel.MainCaret(), list + lenEntered, lenInsert - lenEntered); +				SetEmptySelection(sel.MainCaret() + lenInsert - lenEntered);  			}  			return;  		}  	} -	ac.Start(wMain, idAutoComplete, currentPos, LocationFromPosition(currentPos), +	ac.Start(wMain, idAutoComplete, sel.MainCaret(), LocationFromPosition(sel.MainCaret()),  				lenEntered, vs.lineHeight, IsUnicodeMode());  	PRectangle rcClient = GetClientRectangle(); -	Point pt = LocationFromPosition(currentPos - lenEntered); +	Point pt = LocationFromPosition(sel.MainCaret() - lenEntered);  	PRectangle rcPopupBounds = wMain.GetMonitorRect(pt);  	if (rcPopupBounds.Height() == 0)  		rcPopupBounds = rcClient; @@ -239,7 +240,7 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {  	if (pt.x >= rcClient.right - widthLB) {  		HorizontalScrollTo(xOffset + pt.x - rcClient.right + widthLB);  		Redraw(); -		pt = LocationFromPosition(currentPos); +		pt = LocationFromPosition(sel.MainCaret());  	}  	PRectangle rcac;  	rcac.left = pt.x - ac.lb->CaretFromEdge(); @@ -305,7 +306,7 @@ void ScintillaBase::AutoCompleteMoveToCurrentWord() {  	char wordCurrent[1000];  	int i;  	int startWord = ac.posStart - ac.startLen; -	for (i = startWord; i < currentPos && i - startWord < 1000; i++) +	for (i = startWord; i < sel.MainCaret() && i - startWord < 1000; i++)  		wordCurrent[i - startWord] = pdoc->CharAt(i);  	wordCurrent[Platform::Minimum(i - startWord, 999)] = '\0';  	ac.Select(wordCurrent); @@ -322,9 +323,9 @@ void ScintillaBase::AutoCompleteCharacterAdded(char ch) {  }  void ScintillaBase::AutoCompleteCharacterDeleted() { -	if (currentPos < ac.posStart - ac.startLen) { +	if (sel.MainCaret() < ac.posStart - ac.startLen) {  		AutoCompleteCancel(); -	} else if (ac.cancelAtStartPos && (currentPos <= ac.posStart)) { +	} else if (ac.cancelAtStartPos && (sel.MainCaret() <= ac.posStart)) {  		AutoCompleteCancel();  	} else {  		AutoCompleteMoveToCurrentWord(); @@ -367,7 +368,7 @@ void ScintillaBase::AutoCompleteCompleted() {  	if (listType > 0)  		return; -	Position endPos = currentPos; +	Position endPos = sel.MainCaret();  	if (ac.dropRestOfWord)  		endPos = pdoc->ExtendWordSelect(endPos, 1, true);  	if (endPos < firstPos) @@ -401,7 +402,7 @@ void ScintillaBase::CallTipShow(Point pt, const char *defn) {  	if (ct.UseStyleCallTip()) {  		ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back);  	} -	PRectangle rc = ct.CallTipStart(currentPos, pt, +	PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt,  		defn,  		vs.styles[ctStyle].fontName,  		vs.styles[ctStyle].sizeZoomed, @@ -436,10 +437,10 @@ void ScintillaBase::ContextMenu(Point pt) {  		AddToPopUp("Undo", idcmdUndo, writable && pdoc->CanUndo());  		AddToPopUp("Redo", idcmdRedo, writable && pdoc->CanRedo());  		AddToPopUp(""); -		AddToPopUp("Cut", idcmdCut, writable && currentPos != anchor); -		AddToPopUp("Copy", idcmdCopy, currentPos != anchor); +		AddToPopUp("Cut", idcmdCut, writable && !sel.Empty()); +		AddToPopUp("Copy", idcmdCopy, !sel.Empty());  		AddToPopUp("Paste", idcmdPaste, writable && WndProc(SCI_CANPASTE, 0, 0)); -		AddToPopUp("Delete", idcmdDelete, writable && currentPos != anchor); +		AddToPopUp("Delete", idcmdDelete, writable && !sel.Empty());  		AddToPopUp("");  		AddToPopUp("Select All", idcmdSelectAll);  		popup.Show(pt, wMain); diff --git a/src/Selection.cxx b/src/Selection.cxx new file mode 100644 index 000000000..224fafc69 --- /dev/null +++ b/src/Selection.cxx @@ -0,0 +1,345 @@ +// Scintilla source code edit control +/** @file Selection.cxx + ** Classes maintaining the selection. + **/ +// Copyright 2009 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#include <stdlib.h> + +#include "Platform.h" + +#include "Scintilla.h" + +#include "Selection.h" + +#ifdef SCI_NAMESPACE +using namespace Scintilla; +#endif + +void SelectionPosition::MoveForInsertDelete(bool insertion, int startChange, int length) { +	if (insertion) { +		if (position > startChange) { +			position += length; +		} +	} else { +		if (position > startChange) { +			int endDeletion = startChange + length; +			if (position > endDeletion) { +				position -= length; +			} else { +				position = startChange; +			} +		} +	} +} + +bool SelectionPosition::operator <(const SelectionPosition &other) const { +	if (position == other.position) +		return virtualSpace < other.virtualSpace; +	else +		return position < other.position; +} + +bool SelectionPosition::operator >(const SelectionPosition &other) const { +	if (position == other.position) +		return virtualSpace > other.virtualSpace; +	else +		return position > other.position; +} + +bool SelectionPosition::operator <=(const SelectionPosition &other) const { +	if (position == other.position && virtualSpace == other.virtualSpace) +		return true; +	else +		return other > *this; +} + +bool SelectionPosition::operator >=(const SelectionPosition &other) const { +	if (position == other.position && virtualSpace == other.virtualSpace) +		return true; +	else +		return *this > other; +} + +int SelectionRange::Length() const { +	if (anchor > caret) { +		return anchor.Position() - caret.Position(); +	} else { +		return caret.Position() - anchor.Position(); +	} +} + +bool SelectionRange::Contains(int pos) const { +	if (anchor > caret) +		return (pos >= caret.Position()) && (pos <= anchor.Position()); +	else +		return (pos >= anchor.Position()) && (pos <= caret.Position()); +} + +bool SelectionRange::Contains(SelectionPosition sp) const { +	if (anchor > caret) +		return (sp >= caret) && (sp <= anchor); +	else +		return (sp >= anchor) && (sp <= caret); +} + +bool SelectionRange::ContainsCharacter(int posCharacter) const { +	if (anchor > caret) +		return (posCharacter >= caret.Position()) && (posCharacter < anchor.Position()); +	else +		return (posCharacter >= anchor.Position()) && (posCharacter < caret.Position()); +} + +bool SelectionRange::Intersect(int start, int end, SelectionPosition &selStart, SelectionPosition &selEnd) const { +	SelectionPosition spEnd(end, 100000);	// Large amount of virtual space +	SelectionPosition first; +	SelectionPosition last; +	if (anchor > caret) { +		first = caret; +		last = anchor; +	} else { +		first = anchor; +		last = caret; +	} +	if ((first < spEnd) && (last.Position() > start)) { +		if (start > first.Position())  +			selStart = SelectionPosition(start); +		else  +			selStart = first; +		if (spEnd < last)  +			selEnd = SelectionPosition(end); +		else  +			selEnd = last; +		return true; +	} else { +		return false; +	} +} + +bool SelectionRange::Trim(SelectionPosition startPos, SelectionPosition endPos) { +	SelectionPosition startRange = startPos; +	SelectionPosition endRange = endPos; +	if (startPos > endPos) { +		startRange = endPos; +		endRange = startPos; +	} +	SelectionPosition start = Start(); +	SelectionPosition end = End(); +	PLATFORM_ASSERT(start <= end); +	PLATFORM_ASSERT(startRange <= endRange); +	if ((startRange <= end) && (endRange >= start)) { +		if ((start > startRange) && (end < endRange)) { +			// Completely covered by range -> empty at start +			end = start; +		} else if ((start < startRange) && (end > endRange)) { +			// Completely covers range -> empty at start +			end = start; +		} else if (start <= startRange) { +			// Trim end +			end = startRange; +		} else { //  +			PLATFORM_ASSERT(end >= endRange); +			// Trim start +			start = endRange; +		} +		if (anchor > caret) { +			caret = start; +			anchor = end; +		} else { +			anchor = start; +			caret = end; +		} +		return Empty(); +	} else { +		return false; +	} +} + +// If range is all virtual collapse to start of virtual space +void SelectionRange::MinimizeVirtualSpace() { +	if (caret.Position() == anchor.Position()) { +		int virtualSpace = caret.VirtualSpace(); +		if (virtualSpace > anchor.VirtualSpace()) +			virtualSpace = anchor.VirtualSpace(); +		caret.SetVirtualSpace(virtualSpace); +		anchor.SetVirtualSpace(virtualSpace); +	} +} + +void Selection::Allocate() { +	if (nRanges >= allocated) { +		size_t allocateNew = (allocated + 1) * 2; +		SelectionRange *rangesNew = new SelectionRange[allocateNew]; +		for (size_t r=0; r<Count(); r++) +			rangesNew[r] = ranges[r]; +		delete []ranges; +		ranges = rangesNew; +		allocated = allocateNew; +	} +} + +Selection::Selection() : ranges(0), allocated(0), nRanges(0), mainRange(0), moveExtends(false), selType(selStream) { +	AddSelection(SelectionPosition(0)); +} + +Selection::~Selection() { +	delete []ranges; +} + +bool Selection::IsRectangular() const { +	return (selType == selRectangle) || (selType == selThin); +} + +int Selection::MainCaret() const { +	return ranges[mainRange].caret.Position(); +} + +int Selection::MainAnchor() const { +	return ranges[mainRange].anchor.Position(); +} + +SelectionRange &Selection::Rectangular() { +	return rangeRectangular; +} + +size_t Selection::Count() const { +	return nRanges; +} + +size_t Selection::Main() const { +	return mainRange; +} + +void Selection::SetMain(size_t r) { +	PLATFORM_ASSERT(r < nRanges); +	mainRange = r; +} + +SelectionRange &Selection::Range(size_t r) { +	return ranges[r]; +} + +SelectionRange &Selection::RangeMain() { +	return ranges[mainRange]; +} + +void Selection::ClearVirtualSpace(size_t r) { +	ranges[r].ClearVirtualSpace(); +} + +bool Selection::MoveExtends() const { +	return moveExtends; +} + +void Selection::SetMoveExtends(bool moveExtends_) { +	moveExtends = moveExtends_; +} + +bool Selection::Empty() const { +	for (size_t i=0; i<nRanges; i++) { +		if (!ranges[i].Empty()) +			return false; +	} +	return true; +} + +SelectionPosition Selection::Last() const { +	SelectionPosition lastPosition; +	for (size_t i=0; i<nRanges; i++) { +		if (lastPosition < ranges[i].caret) +			lastPosition = ranges[i].caret; +		if (lastPosition < ranges[i].anchor) +			lastPosition = ranges[i].anchor; +	} +	return lastPosition; +} + +int Selection::Length() const { +	int len = 0; +	for (size_t i=0; i<nRanges; i++) { +		len += ranges[i].Length(); +	} +	return len; +} + +void Selection::MovePositions(bool insertion, int startChange, int length) { +	for (size_t i=0; i<nRanges; i++) { +		ranges[i].caret.MoveForInsertDelete(insertion, startChange, length); +		ranges[i].anchor.MoveForInsertDelete(insertion, startChange, length); +	} +} + +void Selection::TrimSelection(SelectionPosition startPos, SelectionPosition endPos) { +	for (size_t i=0; i<nRanges;) { +		if ((i != mainRange) && (ranges[i].Trim(startPos, endPos))) { +			// Trimmed to empty so remove +			for (size_t j=i;j<nRanges-1;j++) { +				ranges[j] = ranges[j+1]; +				if (j == mainRange-1) +					mainRange--; +			} +			nRanges--; +		} else { +			i++; +		} +	} +} + +void Selection::AddSelection(SelectionPosition spPos) { +	Allocate(); +	TrimSelection(spPos, spPos); +	ranges[nRanges] = SelectionRange(spPos); +	mainRange = nRanges; +	nRanges++; +} + +void Selection::AddSelection(SelectionPosition spStartPos, SelectionPosition spEndPos, bool anchorLeft) { +	Allocate(); +	TrimSelection(spStartPos, spEndPos); +	ranges[nRanges].caret = anchorLeft ? spEndPos : spStartPos; +	ranges[nRanges].anchor = anchorLeft ? spStartPos : spEndPos; +	mainRange = nRanges; +	nRanges++; +} + +bool Selection::CharacterInSelection(int posCharacter) const { +	for (size_t i=0; i<nRanges; i++) { +		if (ranges[i].ContainsCharacter(posCharacter)) +			return true; +	} +	return false; +} + +bool Selection::InSelectionForEOL(int pos) const { +	for (size_t i=0; i<nRanges; i++) { +		if (!ranges[i].Empty() && (pos > ranges[i].Start().Position()) && (pos <= ranges[i].End().Position())) +			return true; +	} +	return false; +} + +int Selection::VirtualSpaceFor(int pos) const { +	int virtualSpace = 0; +	for (size_t i=0; i<nRanges; i++) { +		if ((ranges[i].caret.Position() == pos) && (virtualSpace < ranges[i].caret.VirtualSpace())) +			virtualSpace = ranges[i].caret.VirtualSpace(); +		if ((ranges[i].anchor.Position() == pos) && (virtualSpace < ranges[i].anchor.VirtualSpace())) +			virtualSpace = ranges[i].anchor.VirtualSpace(); +	} +	return virtualSpace; +} + +void Selection::Clear() { +	nRanges = 1; +	mainRange = 0; +	selType = selStream; +	moveExtends = false; +	ranges[mainRange].Reset(); +	rangeRectangular.Reset(); +} + +void Selection::EmptyRanges() { +	nRanges = 0; +	mainRange = 0; +} diff --git a/src/Selection.h b/src/Selection.h new file mode 100644 index 000000000..fe6a1c464 --- /dev/null +++ b/src/Selection.h @@ -0,0 +1,142 @@ +// Scintilla source code edit control +/** @file Selection.h + ** Classes maintaining the selection. + **/ +// Copyright 2009 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +#ifndef SELECTION_H +#define SELECTION_H + +#ifdef SCI_NAMESPACE +namespace Scintilla { +#endif + +class SelectionPosition { +	int position; +	int virtualSpace; +public: +	explicit SelectionPosition(int position_=INVALID_POSITION, int virtualSpace_=0) : position(position_), virtualSpace(virtualSpace_) { +		PLATFORM_ASSERT(virtualSpace < 800000); +		if (virtualSpace < 0) +			virtualSpace = 0; +	} +	void Reset() { +		position = 0; +		virtualSpace = 0; +	} +	void MoveForInsertDelete(bool insertion, int startChange, int length); +	bool operator ==(const SelectionPosition &other) const { +		return position == other.position && virtualSpace == other.virtualSpace; +	} +	bool operator <(const SelectionPosition &other) const; +	bool operator >(const SelectionPosition &other) const; +	bool operator <=(const SelectionPosition &other) const; +	bool operator >=(const SelectionPosition &other) const; +	int Position() const { +		return position; +	} +	void SetPosition(int position_) { +		position = position_; +		virtualSpace = 0; +	} +	int VirtualSpace() const { +		return virtualSpace; +	} +	void SetVirtualSpace(int virtualSpace_) { +		PLATFORM_ASSERT(virtualSpace_ < 800000); +		if (virtualSpace_ >= 0) +			virtualSpace = virtualSpace_; +	} +	void Add(int increment) { +		position = position + increment; +	} +}; + +struct SelectionRange { +	SelectionPosition caret; +	SelectionPosition anchor; + +	SelectionRange() { +	} +	SelectionRange(SelectionPosition single) : caret(single), anchor(single) { +	} +	SelectionRange(SelectionPosition caret_, SelectionPosition anchor_) : caret(caret_), anchor(anchor_) { +	} +	SelectionRange(int caret_, int anchor_) : caret(caret_), anchor(anchor_) { +	} +	bool Empty() const { +		return anchor == caret; +	} +	int Length() const; +	bool operator ==(const SelectionRange &other) const { +		return caret == other.caret && anchor == other.anchor; +	} +	void Reset() { +		anchor.Reset(); +		caret.Reset(); +	} +	void ClearVirtualSpace() { +		anchor.SetVirtualSpace(0); +		caret.SetVirtualSpace(0); +	} +	bool Contains(int pos) const; +	bool Contains(SelectionPosition sp) const; +	bool ContainsCharacter(int posCharacter) const; +	bool Intersect(int start, int end, SelectionPosition &selStart, SelectionPosition &selEnd) const; +	SelectionPosition Start() const { +		return (anchor < caret) ? anchor : caret; +	} +	SelectionPosition End() const { +		return (anchor < caret) ? caret : anchor; +	} +	bool Trim(SelectionPosition startPos, SelectionPosition endPos); +	// If range is all virtual collapse to start of virtual space +	void MinimizeVirtualSpace(); +}; + +class Selection { +	SelectionRange *ranges; +	SelectionRange rangeRectangular; +	size_t allocated; +	size_t nRanges; +	size_t mainRange; +	bool moveExtends; +	void Allocate(); +public: +	enum selTypes { noSel, selStream, selRectangle, selLines, selThin }; +	selTypes selType; + +	Selection(); +	~Selection(); +	bool IsRectangular() const; +	int MainCaret() const; +	int MainAnchor() const; +	SelectionRange &Rectangular(); +	size_t Count() const; +	size_t Main() const; +	void SetMain(size_t r); +	SelectionRange &Range(size_t r); +	SelectionRange &RangeMain(); +	void ClearVirtualSpace(size_t r); +	bool MoveExtends() const; +	void SetMoveExtends(bool moveExtends_); +	bool Empty() const; +	SelectionPosition Last() const; +	int Length() const; +	void MovePositions(bool insertion, int startChange, int length); +	void TrimSelection(SelectionPosition startPos, SelectionPosition endPos); +	void AddSelection(SelectionPosition spPos); +	void AddSelection(SelectionPosition spStartPos, SelectionPosition spEndPos, bool anchorLeft); +	bool CharacterInSelection(int posCharacter) const; +	bool InSelectionForEOL(int pos) const; +	int VirtualSpaceFor(int pos) const; +	void Clear(); +	void EmptyRanges(); +}; + +#ifdef SCI_NAMESPACE +} +#endif + +#endif diff --git a/vcbuild/SciLexer.dsp b/vcbuild/SciLexer.dsp index 8c040906b..f6d7d6870 100644 --- a/vcbuild/SciLexer.dsp +++ b/vcbuild/SciLexer.dsp @@ -494,6 +494,10 @@ SOURCE=..\win32\ScintRes.rc  # End Source File  # Begin Source File +SOURCE=..\src\Selection.cxx +# End Source File +# Begin Source File +  SOURCE=..\src\Style.cxx  # End Source File  # Begin Source File diff --git a/win32/ScintillaWin.cxx b/win32/ScintillaWin.cxx index 502dca7dd..9c8036aa9 100644 --- a/win32/ScintillaWin.cxx +++ b/win32/ScintillaWin.cxx @@ -45,6 +45,7 @@  #include "CharClassify.h"  #include "Decoration.h"  #include "Document.h" +#include "Selection.h"  #include "PositionCache.h"  #include "Editor.h"  #include "ScintillaBase.h" @@ -238,7 +239,7 @@ class ScintillaWin :  	virtual bool GetScrollInfo(int nBar, LPSCROLLINFO lpsi);  	void ChangeScrollPos(int barType, int pos); -	void InsertPasteText(const char *text, int len, int selStart, bool isRectangular, bool isLine); +	void InsertPasteText(const char *text, int len, SelectionPosition selStart, bool isRectangular, bool isLine);  public:  	// Public for benefit of Scintilla_DirectFunction @@ -523,7 +524,7 @@ sptr_t ScintillaWin::HandleComposition(uptr_t wParam, sptr_t lParam) {  				}  			}  			// Set new position after converted -			Point pos = LocationFromPosition(currentPos); +			Point pos = LocationFromPosition(sel.MainCaret());  			COMPOSITIONFORM CompForm;  			CompForm.dwStyle = CFS_POINT;  			CompForm.ptCurrentPos.x = pos.x; @@ -903,7 +904,7 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  				Point pt = Point::FromLong(lParam);  				if ((pt.x == -1) && (pt.y == -1)) {  					// Caused by keyboard so display menu near caret -					pt = LocationFromPosition(currentPos); +					pt = LocationFromPosition(sel.MainCaret());  					POINT spt = {pt.x, pt.y};  					::ClientToScreen(MainHWND(), &spt);  					pt = Point(spt.x, spt.y); @@ -996,7 +997,7 @@ sptr_t ScintillaWin::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam  					return 0;  				}  				Sci_CharacterRange *pCR = reinterpret_cast<Sci_CharacterRange *>(lParam); -				selType = selStream; +				sel.selType = Selection::selStream;  				if (pCR->cpMin == 0 && pCR->cpMax == -1) {  					SetSelection(pCR->cpMin, pdoc->Length());  				} else { @@ -1135,7 +1136,7 @@ void ScintillaWin::UpdateSystemCaret() {  			DestroySystemCaret();  			CreateSystemCaret();  		} -		Point pos = LocationFromPosition(currentPos); +		Point pos = LocationFromPosition(sel.MainCaret());  		::SetCaretPos(pos.x, pos.y);  	}  } @@ -1259,7 +1260,7 @@ void ScintillaWin::NotifyDoubleClick(Point pt, bool shift, bool ctrl, bool alt)  void ScintillaWin::Copy() {  	//Platform::DebugPrintf("Copy\n"); -	if (currentPos != anchor) { +	if (!sel.Empty()) {  		SelectionText selectedText;  		CopySelectionRange(&selectedText);  		CopyToClipboard(selectedText); @@ -1321,7 +1322,7 @@ public:  	}  }; -void ScintillaWin::InsertPasteText(const char *text, int len, int selStart, bool isRectangular, bool isLine) { +void ScintillaWin::InsertPasteText(const char *text, int len, SelectionPosition selStart, bool isRectangular, bool isLine) {  	if (isRectangular) {  		PasteRectangular(selStart, text, len);  	} else { @@ -1332,7 +1333,7 @@ void ScintillaWin::InsertPasteText(const char *text, int len, int selStart, bool  			text = convertedText;  		}  		if (isLine) { -			int insertPos = pdoc->LineStart(pdoc->LineFromPosition(currentPos)); +			int insertPos = pdoc->LineStart(pdoc->LineFromPosition(sel.MainCaret()));  			pdoc->InsertString(insertPos, text, len);  			// add the newline if necessary  			if ((len > 0) && (text[len-1] != '\n' && text[len-1] != '\r')) { @@ -1340,11 +1341,11 @@ void ScintillaWin::InsertPasteText(const char *text, int len, int selStart, bool  				pdoc->InsertString(insertPos + len, endline, strlen(endline));  				len += strlen(endline);  			} -			if (currentPos == insertPos) { -				SetEmptySelection(currentPos + len); +			if (sel.MainCaret() == insertPos) { +				SetEmptySelection(sel.MainCaret() + len);  			} -		} else if (pdoc->InsertString(currentPos, text, len)) { -			SetEmptySelection(currentPos + len); +		} else if (pdoc->InsertString(sel.MainCaret(), text, len)) { +			SetEmptySelection(sel.MainCaret() + len);  		}  		delete []convertedText;  	} @@ -1356,7 +1357,7 @@ void ScintillaWin::Paste() {  	pdoc->BeginUndoAction();  	bool isLine = SelectionEmpty() && (::IsClipboardFormatAvailable(cfLineSelect) != 0);  	ClearSelection(); -	int selStart = SelectionStart(); +	SelectionPosition selStart = sel.Range(sel.Main()).Start();  	bool isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;  	// Always use CF_UNICODETEXT if available @@ -1816,7 +1817,7 @@ void ScintillaWin::ImeStartComposition() {  	if (caret.active) {  		// Move IME Window to current caret position  		HIMC hIMC = ::ImmGetContext(MainHWND()); -		Point pos = LocationFromPosition(currentPos); +		Point pos = LocationFromPosition(sel.MainCaret());  		COMPOSITIONFORM CompForm;  		CompForm.dwStyle = CFS_POINT;  		CompForm.ptCurrentPos.x = pos.x; @@ -1828,7 +1829,7 @@ void ScintillaWin::ImeStartComposition() {  		if (stylesValid) {  			// Since the style creation code has been made platform independent,  			// The logfont for the IME is recreated here. -			int styleHere = (pdoc->StyleAt(currentPos)) & 31; +			int styleHere = (pdoc->StyleAt(sel.MainCaret())) & 31;  			LOGFONTA lf = {0,0,0,0,0,0,0,0,0,0,0,0,0, ""};  			int sizeZoomed = vs.styles[styleHere].size + vs.zoomLevel;  			if (sizeZoomed <= 2)	// Hangs if sizeZoomed <= 1 diff --git a/win32/makefile b/win32/makefile index 143be32e0..5f495c7a4 100644 --- a/win32/makefile +++ b/win32/makefile @@ -67,14 +67,14 @@ LexTADS3.o LexTAL.o LexTCL.o LexTeX.o LexVB.o LexVerilog.o LexVHDL.o LexYAML.o  SOBJS	= ScintillaWin.o ScintillaBase.o Editor.o CharClassify.o Decoration.o \  	Document.o ContractionState.o CellBuffer.o CallTip.o \  	ScintRes.o PlatWin.o PositionCache.o KeyMap.o Indicator.o LineMarker.o RESearch.o RunStyles.o \ -	Style.o ViewStyle.o AutoComplete.o UniConversion.o PropSet.o XPM.o PerLine.o +	Selection.o Style.o ViewStyle.o AutoComplete.o UniConversion.o PropSet.o XPM.o PerLine.o  $(COMPONENT): $(SOBJS) Scintilla.def  	$(DLLWRAP) --add-stdcall-alias --target i386-mingw32 -o $@ $(SOBJS) $(LDFLAGS) -s --relocatable  LOBJS	= ScintillaWinL.o ScintillaBaseL.o Editor.o CharClassify.o Decoration.o \  	Document.o ContractionState.o CellBuffer.o CallTip.o \  	ScintRes.o PlatWin.o PositionCache.o KeyMap.o Indicator.o LineMarker.o RESearch.o RunStyles.o \ -	Style.o ViewStyle.o AutoComplete.o UniConversion.o KeyWords.o \ +	Selection.o Style.o ViewStyle.o AutoComplete.o UniConversion.o KeyWords.o \  	DocumentAccessor.o PropSet.o ExternalLexer.o StyleContext.o XPM.o PerLine.o $(LEXOBJS)  $(LEXCOMPONENT): $(LOBJS) Scintilla.def  	$(DLLWRAP) --add-stdcall-alias --target i386-mingw32 -o $@ $(LOBJS) $(LDFLAGS) -s --relocatable diff --git a/win32/scintilla.mak b/win32/scintilla.mak index ff8dc8f57..4e715e02b 100644 --- a/win32/scintilla.mak +++ b/win32/scintilla.mak @@ -105,6 +105,7 @@ SOBJS=\  	$(DIR_O)\RunStyles.obj \  	$(DIR_O)\ScintillaBase.obj \  	$(DIR_O)\ScintillaWin.obj \ +	$(DIR_O)\Selection.obj \  	$(DIR_O)\Style.obj \  	$(DIR_O)\UniConversion.obj \  	$(DIR_O)\ViewStyle.obj \ @@ -216,6 +217,7 @@ LOBJS=\  	$(DIR_O)\RunStyles.obj \  	$(DIR_O)\ScintillaBaseL.obj \  	$(DIR_O)\ScintillaWinL.obj \ +	$(DIR_O)\Selection.obj \  	$(DIR_O)\Style.obj \  	$(DIR_O)\StyleContext.obj \  	$(DIR_O)\UniConversion.obj \ @@ -299,7 +301,7 @@ $(DIR_O)\Editor.obj: ../src/Editor.cxx ../include/Platform.h ../include/Scintill    ../src/Partitioning.h ../src/CellBuffer.h ../src/KeyMap.h \    ../src/RunStyles.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \    ../src/Style.h ../src/ViewStyle.h ../src/CharClassify.h \ -  ../src/Decoration.h ../src/Document.h ../src/Editor.h ../src/PositionCache.h +  ../src/Decoration.h ../src/Document.h ../src/Editor.h ../src/Selection.h ../src/PositionCache.h  $(DIR_O)\ExternalLexer.obj: ../src/ExternalLexer.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/SciLexer.h ../include/PropSet.h \    ../include/SString.h ../include/Accessor.h ../src/DocumentAccessor.h \ @@ -484,7 +486,7 @@ $(DIR_O)\PositionCache.obj: ../src/Editor.cxx ../include/Platform.h ../include/S    ../src/Partitioning.h ../src/CellBuffer.h ../src/KeyMap.h \    ../src/RunStyles.h ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h \    ../src/Style.h ../src/ViewStyle.h ../src/CharClassify.h \ -  ../src/Decoration.h ../src/Document.h ../src/Editor.h ../src/PositionCache.h +  ../src/Decoration.h ../src/Document.h ../src/Editor.h ../src/Selection.h ../src/PositionCache.h  $(DIR_O)\PropSet.obj: ../src/PropSet.cxx ../include/Platform.h ../include/PropSet.h \    ../include/SString.h  $(DIR_O)\RESearch.obj: ../src/RESearch.cxx ../src/CharClassify.h ../src/RESearch.h @@ -498,7 +500,7 @@ $(DIR_O)\ScintillaBase.obj: ../src/ScintillaBase.cxx ../include/Platform.h \    ../src/CallTip.h ../src/KeyMap.h ../src/Indicator.h ../src/XPM.h \    ../src/LineMarker.h ../src/Style.h ../src/ViewStyle.h \    ../src/AutoComplete.h ../src/CharClassify.h ../src/Decoration.h \ -  ../src/Document.h ../src/Editor.h ../src/ScintillaBase.h +  ../src/Document.h ../src/Editor.h ../src/Selection.h ../src/ScintillaBase.h  $(DIR_O)\ScintillaBaseL.obj: ../src/ScintillaBase.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/PropSet.h ../include/SString.h \    ../src/ContractionState.h ../src/SVector.h ../src/SplitVector.h \ @@ -506,7 +508,7 @@ $(DIR_O)\ScintillaBaseL.obj: ../src/ScintillaBase.cxx ../include/Platform.h \    ../src/CallTip.h ../src/KeyMap.h ../src/Indicator.h ../src/XPM.h \    ../src/LineMarker.h ../src/Style.h ../src/ViewStyle.h \    ../src/AutoComplete.h ../src/CharClassify.h ../src/Decoration.h \ -  ../src/Document.h ../src/Editor.h ../src/ScintillaBase.h +  ../src/Document.h ../src/Editor.h ../src/Selection.h ../src/ScintillaBase.h  $(DIR_O)\ScintillaWin.obj: ScintillaWin.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/SString.h ../src/ContractionState.h \    ../src/SVector.h ../src/SplitVector.h ../src/Partitioning.h \ @@ -514,7 +516,7 @@ $(DIR_O)\ScintillaWin.obj: ScintillaWin.cxx ../include/Platform.h \    ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \    ../src/AutoComplete.h ../src/ViewStyle.h ../src/CharClassify.h \    ../src/Decoration.h ../src/Document.h ../src/Editor.h \ -  ../src/ScintillaBase.h ../src/UniConversion.h +  ../src/ScintillaBase.h ../src/Selection.h ../src/UniConversion.h  $(DIR_O)\ScintillaWinS.obj: ScintillaWin.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/SString.h ../src/ContractionState.h \    ../src/SVector.h ../src/SplitVector.h ../src/Partitioning.h \ @@ -522,7 +524,7 @@ $(DIR_O)\ScintillaWinS.obj: ScintillaWin.cxx ../include/Platform.h \    ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \    ../src/AutoComplete.h ../src/ViewStyle.h ../src/CharClassify.h \    ../src/Decoration.h ../src/Document.h ../src/Editor.h \ -  ../src/ScintillaBase.h ../src/UniConversion.h +  ../src/ScintillaBase.h ../src/Selection.h ../src/UniConversion.h  $(DIR_O)\ScintillaWinL.obj: ScintillaWin.cxx ../include/Platform.h \    ../include/Scintilla.h ../include/SString.h ../src/ContractionState.h \    ../src/SVector.h ../src/SplitVector.h ../src/Partitioning.h \ @@ -530,7 +532,9 @@ $(DIR_O)\ScintillaWinL.obj: ScintillaWin.cxx ../include/Platform.h \    ../src/Indicator.h ../src/XPM.h ../src/LineMarker.h ../src/Style.h \    ../src/AutoComplete.h ../src/ViewStyle.h ../src/CharClassify.h \    ../src/Decoration.h ../src/Document.h ../src/Editor.h \ -  ../src/ScintillaBase.h ../src/UniConversion.h +  ../src/ScintillaBase.h ../src/Selection.h ../src/UniConversion.h +$(DIR_O)\Selection.obj: ../src/Selection.cxx ../include/Platform.h ../include/Scintilla.h \ +  ../src/Selection.h  $(DIR_O)\Style.obj: ../src/Style.cxx ../include/Platform.h ../include/Scintilla.h \    ../src/Style.h  $(DIR_O)\StyleContext.obj: ../src/StyleContext.cxx ../include/Platform.h \ | 
