Revision: 4723 http://geany.svn.sourceforge.net/geany/?rev=4723&view=rev Author: eht16 Date: 2010-03-07 10:31:51 +0000 (Sun, 07 Mar 2010)
Log Message: ----------- Update Scintilla to version 2.03.
Modified Paths: -------------- trunk/scintilla/AutoComplete.cxx trunk/scintilla/CallTip.cxx trunk/scintilla/CallTip.h trunk/scintilla/CellBuffer.cxx trunk/scintilla/CharClassify.cxx trunk/scintilla/CharClassify.h trunk/scintilla/Document.cxx trunk/scintilla/Document.h trunk/scintilla/DocumentAccessor.h trunk/scintilla/Editor.cxx trunk/scintilla/Editor.h trunk/scintilla/ExternalLexer.cxx trunk/scintilla/ExternalLexer.h trunk/scintilla/KeyWords.cxx trunk/scintilla/LexAda.cxx trunk/scintilla/LexCaml.cxx trunk/scintilla/LexCmake.cxx trunk/scintilla/LexHTML.cxx trunk/scintilla/LexHaskell.cxx trunk/scintilla/LexNsis.cxx trunk/scintilla/LexOthers.cxx trunk/scintilla/LexPython.cxx trunk/scintilla/LexSQL.cxx trunk/scintilla/Makefile.am trunk/scintilla/PerLine.cxx trunk/scintilla/PlatGTK.cxx trunk/scintilla/PositionCache.cxx trunk/scintilla/PositionCache.h trunk/scintilla/PropSet.cxx trunk/scintilla/RESearch.cxx trunk/scintilla/SVector.h trunk/scintilla/ScintillaBase.cxx trunk/scintilla/ScintillaBase.h trunk/scintilla/ScintillaGTK.cxx trunk/scintilla/Style.cxx trunk/scintilla/Style.h trunk/scintilla/StyleContext.h trunk/scintilla/ViewStyle.cxx trunk/scintilla/ViewStyle.h trunk/scintilla/include/KeyWords.h trunk/scintilla/include/Platform.h trunk/scintilla/include/PropSet.h trunk/scintilla/include/SciLexer.h trunk/scintilla/include/Scintilla.h trunk/scintilla/include/Scintilla.iface trunk/scintilla/include/WindowAccessor.h trunk/scintilla/makefile.win32 trunk/scintilla/scintilla_changes.patch trunk/wscript
Added Paths: ----------- trunk/scintilla/PropSetSimple.h trunk/scintilla/Selection.cxx trunk/scintilla/Selection.h
Modified: trunk/scintilla/AutoComplete.cxx =================================================================== --- trunk/scintilla/AutoComplete.cxx 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/AutoComplete.cxx 2010-03-07 10:31:51 UTC (rev 4723) @@ -11,7 +11,7 @@
#include "Platform.h"
-#include "PropSet.h" +#include "CharClassify.h" #include "AutoComplete.h"
#ifdef SCI_NAMESPACE
Modified: trunk/scintilla/CallTip.cxx =================================================================== --- trunk/scintilla/CallTip.cxx 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/CallTip.cxx 2010-03-07 10:31:51 UTC (rev 4723) @@ -254,11 +254,9 @@ const char *faceName, int size, int codePage_, int characterSet, Window &wParent) { clickPlace = 0; - if (val) - delete []val; + delete []val; + val = 0; val = new char[strlen(defn) + 1]; - if (!val) - return PRectangle(); strcpy(val, defn); codePage = codePage_; Surface *surfaceMeasure = Surface::Allocate();
Modified: trunk/scintilla/CallTip.h =================================================================== --- trunk/scintilla/CallTip.h 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/CallTip.h 2010-03-07 10:31:51 UTC (rev 4723) @@ -27,8 +27,8 @@ bool useStyleCallTip; // if true, STYLE_CALLTIP should be used
// Private so CallTip objects can not be copied - CallTip(const CallTip &) {} - CallTip &operator=(const CallTip &) { return *this; } + CallTip(const CallTip &); + CallTip &operator=(const CallTip &); void DrawChunk(Surface *surface, int &x, const char *s, int posStart, int posEnd, int ytext, PRectangle rcClient, bool highlight, bool draw);
Modified: trunk/scintilla/CellBuffer.cxx =================================================================== --- trunk/scintilla/CellBuffer.cxx 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/CellBuffer.cxx 2010-03-07 10:31:51 UTC (rev 4723) @@ -71,6 +71,7 @@ position = 0; data = 0; lenData = 0; + mayCoalesce = false; }
Action::~Action() { @@ -150,8 +151,6 @@ // Run out of undo nodes so extend the array int lenActionsNew = lenActions * 2; Action *actionsNew = new Action[lenActionsNew]; - if (!actionsNew) - return; for (int act = 0; act <= currentAction; act++) actionsNew[act].Grab(&actions[act]); delete []actions;
Modified: trunk/scintilla/CharClassify.cxx =================================================================== --- trunk/scintilla/CharClassify.cxx 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/CharClassify.cxx 2010-03-07 10:31:51 UTC (rev 4723) @@ -5,6 +5,7 @@ // Copyright 2006 by Neil Hodgson neilh@scintilla.org // The License.txt file describes the conditions under which this software may be distributed.
+#include <stdlib.h> #include <ctype.h>
#include "CharClassify.h" @@ -41,3 +42,37 @@ } } } + +int CompareCaseInsensitive(const char *a, const char *b) { + while (*a && *b) { + if (*a != *b) { + char upperA = MakeUpperCase(*a); + char upperB = MakeUpperCase(*b); + if (upperA != upperB) + return upperA - upperB; + } + a++; + b++; + } + // Either *a or *b is nul + return *a - *b; +} + +int CompareNCaseInsensitive(const char *a, const char *b, size_t len) { + while (*a && *b && len) { + if (*a != *b) { + char upperA = MakeUpperCase(*a); + char upperB = MakeUpperCase(*b); + if (upperA != upperB) + return upperA - upperB; + } + a++; + b++; + len--; + } + if (len == 0) + return 0; + else + // Either *a or *b is nul + return *a - *b; +}
Modified: trunk/scintilla/CharClassify.h =================================================================== --- trunk/scintilla/CharClassify.h 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/CharClassify.h 2010-03-07 10:31:51 UTC (rev 4723) @@ -2,7 +2,7 @@ /** @file CharClassify.h ** Character classifications used by Document and RESearch. **/ -// Copyright 2006 by Neil Hodgson neilh@scintilla.org +// Copyright 2006-2009 by Neil Hodgson neilh@scintilla.org // The License.txt file describes the conditions under which this software may be distributed.
#ifndef CHARCLASSIFY_H @@ -22,4 +22,16 @@ enum { maxChar=256 }; unsigned char charClass[maxChar]; // not type cc to save space }; + +// These functions are implemented because each platform calls them something different. +int CompareCaseInsensitive(const char *a, const char *b); +int CompareNCaseInsensitive(const char *a, const char *b, size_t len); + +inline char MakeUpperCase(char ch) { + if (ch < 'a' || ch > 'z') + return ch; + else + return static_cast<char>(ch - 'a' + 'A'); +} + #endif
Modified: trunk/scintilla/Document.cxx =================================================================== --- trunk/scintilla/Document.cxx 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/Document.cxx 2010-03-07 10:31:51 UTC (rev 4723) @@ -217,6 +217,10 @@ 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); @@ -757,10 +761,9 @@ CreateIndentation(linebuf, sizeof(linebuf), indent, tabInChars, !useTabs); int thisLineStart = LineStart(line); int indentPos = GetLineIndentPosition(line); - BeginUndoAction(); + UndoGroup ug(this); DeleteChars(thisLineStart, indentPos - thisLineStart); InsertCString(thisLineStart, linebuf); - EndUndoAction(); } }
@@ -801,8 +804,8 @@
int Document::FindColumn(int line, int column) { int position = LineStart(line); - int columnCurrent = 0; if ((line >= 0) && (line < LinesTotal())) { + int columnCurrent = 0; while ((columnCurrent < column) && (position < Length())) { char ch = cb.CharAt(position); if (ch == '\t') { @@ -867,7 +870,7 @@ }
void Document::ConvertLineEnds(int eolModeSet) { - BeginUndoAction(); + UndoGroup ug(this);
for (int pos = 0; pos < Length(); pos++) { if (cb.CharAt(pos) == '\r') { @@ -902,7 +905,6 @@ } }
- EndUndoAction(); }
bool Document::IsWhiteLine(int line) const { @@ -1065,16 +1067,6 @@ return IsWordStartAt(start) && IsWordEndAt(end); }
-// The comparison and case changing functions here assume ASCII -// or extended ASCII such as the normal Windows code page. - -static inline char MakeUpperCase(char ch) { - if (ch < 'a' || ch > 'z') - return ch; - else - return static_cast<char>(ch - 'a' + 'A'); -} - static inline char MakeLowerCase(char ch) { if (ch < 'A' || ch > 'Z') return ch; @@ -1374,8 +1366,6 @@ return false; } WatcherWithUserData *pwNew = new WatcherWithUserData[lenWatchers + 1]; - if (!pwNew) - return false; for (int j = 0; j < lenWatchers; j++) pwNew[j] = watchers[j]; pwNew[lenWatchers].watcher = watcher; @@ -1396,8 +1386,6 @@ lenWatchers = 0; } else { WatcherWithUserData *pwNew = new WatcherWithUserData[lenWatchers]; - if (!pwNew) - return false; for (int j = 0; j < lenWatchers - 1; j++) { pwNew[j] = (j < i) ? watchers[j] : watchers[j + 1]; } @@ -1758,8 +1746,6 @@ } } substituted = new char[lenResult + 1]; - if (!substituted) - return 0; char *o = substituted; for (int j = 0; j < *length; j++) { if (text[j] == '\') {
Modified: trunk/scintilla/Document.h =================================================================== --- trunk/scintilla/Document.h 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/Document.h 2010-03-07 10:31:51 UTC (rev 4723) @@ -239,6 +239,7 @@ 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); @@ -319,6 +320,27 @@ void NotifyModified(DocModification mh); };
+class UndoGroup { + Document *pdoc; + bool groupNeeded; +public: + UndoGroup(Document *pdoc_, bool groupNeeded_=true) : + pdoc(pdoc_), groupNeeded(groupNeeded_) { + if (groupNeeded) { + pdoc->BeginUndoAction(); + } + } + ~UndoGroup() { + if (groupNeeded) { + pdoc->EndUndoAction(); + } + } + bool Needed() const { + return groupNeeded; + } +}; + + /** * To optimise processing of document modifications by DocWatchers, a hint is passed indicating the * scope of the change.
Modified: trunk/scintilla/DocumentAccessor.h =================================================================== --- trunk/scintilla/DocumentAccessor.h 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/DocumentAccessor.h 2010-03-07 10:31:51 UTC (rev 4723) @@ -14,14 +14,15 @@
/** */ + class DocumentAccessor : public Accessor { // Private so DocumentAccessor objects can not be copied - DocumentAccessor(const DocumentAccessor &source) : Accessor(), props(source.props) {} - DocumentAccessor &operator=(const DocumentAccessor &) { return *this; } + DocumentAccessor(const DocumentAccessor &source); + DocumentAccessor &operator=(const DocumentAccessor &);
protected: Document *pdoc; - PropSet &props; + PropertyGet &props; WindowID id; int lenDoc;
@@ -37,7 +38,7 @@ void Fill(int position);
public: - DocumentAccessor(Document *pdoc_, PropSet &props_, WindowID id_=0) : + DocumentAccessor(Document *pdoc_, PropertyGet &props_, WindowID id_=0) : Accessor(), pdoc(pdoc_), props(props_), id(id_), lenDoc(-1), validLen(0), chFlags(0), chWhile(0), startSeg(0), startPosStyling(0),
Modified: trunk/scintilla/Editor.cxx =================================================================== --- trunk/scintilla/Editor.cxx 2010-03-05 18:07:41 UTC (rev 4722) +++ trunk/scintilla/Editor.cxx 2010-03-07 10:31:51 UTC (rev 4723) @@ -10,6 +10,18 @@ #include <stdio.h> #include <ctype.h>
+#include <string> +#include <vector> +#include <algorithm> + +// With Borland C++ 5.5, including <string> includes Windows.h leading to defining +// FindText to FindTextA which makes calls here to Document::FindText fail. +#ifdef __BORLANDC__ +#ifdef FindText +#undef FindText +#endif +#endif + #include "Platform.h"
#include "Scintilla.h" @@ -28,6 +40,7 @@ #include "CharClassify.h" #include "Decoration.h" #include "Document.h" +#include "Selection.h" #include "PositionCache.h" #include "Editor.h"
@@ -108,18 +121,14 @@ ptMouseLast.y = 0; inDragDrop = ddNone; dropWentOutside = false; - posDrag = invalidPosition; - posDrop = invalidPosition; + posDrag = SelectionPosition(invalidPosition); + posDrop = SelectionPosition(invalidPosition); selectionType = selChar;
lastXChosen = 0; lineAnchor = 0; originalAnchorPos = 0;
- selType = selStream; - moveExtendsSelection = false; - xStartSelect = 0; - xEndSelect = 0; primarySelection = true;
caretXPolicy = CARET_SLOP | CARET_EVEN; @@ -139,6 +148,11 @@ verticalScrollBarVisible = true; endAtLastLine = true; caretSticky = false; + multipleSelection = false; + additionalSelectionTyping = false; + additionalCaretsBlink = true; + additionalCaretsVisible = true; + virtualSpaceOptions = SCVS_NONE;
pixmapLine = Surface::Allocate(); pixmapSelMargin = Surface::Allocate(); @@ -146,9 +160,6 @@ pixmapIndentGuide = Surface::Allocate(); pixmapIndentGuideHighlight = Surface::Allocate();
- currentPos = 0; - anchor = 0; - targetStart = 0; targetEnd = 0; searchFlags = 0; @@ -227,10 +238,6 @@ palette.Release(); llc.Invalidate(LineLayout::llInvalid); posCache.Clear(); - if (selType == selRectangle) { - xStartSelect = XFromPosition(anchor); - xEndSelect = XFromPosition(currentPos); - } }
void Editor::InvalidateStyleRedraw() { @@ -263,6 +270,7 @@ wrapAddIndent = vs.aveCharWidth; // must indent to show start visual } SetScrollBars(); + SetRectangularRange(); } }
@@ -328,7 +336,7 @@ class AutoLineLayout { LineLayoutCache &llc; LineLayout *ll; - AutoLineLayout &operator=(const AutoLineLayout &) { return * this; } + AutoLineLayout &operator=(const AutoLineLayout &); public: AutoLineLayout(LineLayoutCache &llc_, LineLayout *ll_) : llc(llc_), ll(ll_) {} ~AutoLineLayout() { @@ -347,98 +355,25 @@ } };
-#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; - } +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; } - - 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; - } -}; - -#ifdef SCI_NAMESPACE } -#endif
-Point Editor::LocationFromPosition(int pos) { +Point Editor::LocationFromPosition(SelectionPosition pos) { Point pt; RefreshStyleData(); - if (pos == INVALID_POSITION) + if (pos.Position() == INVALID_POSITION) return pt; - int line = pdoc->LineFromPosition(pos); + int line = pdoc->LineFromPosition(pos.Position()); int lineVisible = cs.DisplayFromDoc(line); //Platform::DebugPrintf("line=%d\n", line); AutoSurface surface(this); @@ -449,7 +384,7 @@ pt.x = 0; unsigned int posLineStart = pdoc->LineStart(line); LayoutLine(line, surface, vs, ll, wrapWidth); - int posInLine = pos - posLineStart; + int posInLine = pos.Position() - posLineStart; // In case of very long line put x at arbitrary large position if (posInLine > ll->maxLineLength) { pt.x = ll->positions[ll->maxLineLength] - ll->positions[ll->LineStart(ll->lines)]; @@ -470,14 +405,24 @@ } pt.x += vs.fixedColumnWidth - xOffset; } + pt.x += pos.VirtualSpace() * static_cast<int>(vs.styles[ll->EndLineStyle()].spaceWidth); return pt; }
+Point Editor::LocationFromPosition(int pos) { + return LocationFromPosition(SelectionPosition(pos)); +} + int Editor::XFromPosition(int pos) { Point pt = LocationFromPosition(pos); return pt.x - vs.fixedColumnWidth + xOffset; }
+int Editor::XFromPosition(SelectionPosition sp) { + Point pt = LocationFromPosition(sp); + return pt.x - vs.fixedColumnWidth + xOffset; +} + int Editor::LineFromLocation(Point pt) { return cs.DocFromDisplay(pt.y / vs.lineHeight + topLine); } @@ -487,16 +432,16 @@ 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 +452,11 @@ 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 +476,38 @@ 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.styles[ll->EndLineStyle()].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. @@ -569,7 +523,7 @@ if (surface && ll) { unsigned int posLineStart = pdoc->LineStart(lineDoc); LayoutLine(lineDoc, surface, vs, ll, wrapWidth); - retVal = ll->numCharsInLine + posLineStart; + retVal = ll->numCharsBeforeEOL + posLineStart; int subLine = 0; int lineStart = ll->LineStart(subLine); int lineEnd = ll->LineLastVisible(subLine); @@ -592,6 +546,45 @@ }
/** + * 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.styles[ll->EndLineStyle()].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 +669,125 @@ }
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); +SelectionPosition Editor::SelectionStart() { + return sel.RangeMain().Start(); }
-int Editor::SelectionEnd() { - return Platform::Maximum(currentPos, anchor); +SelectionPosition Editor::SelectionEnd() { + return sel.RangeMain().End(); }
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); + if (sel.selType == Selection::selThin) { + xCaret = xAnchor; + } + int lineAnchor = pdoc->LineFromPosition(sel.Rectangular().anchor.Position()); + int lineCaret = pdoc->LineFromPosition(sel.Rectangular().caret.Position()); + int increment = (lineCaret > lineAnchor) ? 1 : -1; + for (int line=lineAnchor; line != lineCaret+increment; line += increment) { + SelectionRange range(SPositionFromLineX(line, xCaret), SPositionFromLineX(line, xAnchor)); + if ((virtualSpaceOptions & SCVS_RECTANGULARSELECTION) == 0) + range.ClearVirtualSpace(); + if (line == lineAnchor) + sel.SetSelection(range); + else + sel.AddSelection(range); + } } }
-void Editor::InvalidateSelection(int currentPos_, int anchor_, bool invalidateWholeSelection) { - if (anchor != anchor_ || selType == selRectangle) { +void Editor::ThinRectangularRange() { + if (sel.IsRectangular()) { + sel.selType = Selection::selThin; + if (sel.Rectangular().caret < sel.Rectangular().anchor) { + sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).caret, sel.Range(0).anchor); + } else { + sel.Rectangular() = SelectionRange(sel.Range(sel.Count()-1).anchor, sel.Range(0).caret); + } + SetRectangularRange(); + } +} + +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 = Platform::Minimum(sel.RangeMain().Start().Position(), newMain.Start().Position()); + // +1 for lastAffected ensures caret repainted + int lastAffected = Platform::Maximum(newMain.caret.Position()+1, newMain.anchor.Position()); + lastAffected = Platform::Maximum(lastAffected, sel.RangeMain().End().Position()); if (invalidateWholeSelection) { - if (firstAffected > anchor) - firstAffected = anchor; - if (firstAffected > anchor_) - firstAffected = 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 (firstAffected > currentPos_) - firstAffected = currentPos_; - int lastAffected = currentPos; - if (invalidateWholeSelection) { - if (lastAffected < anchor) - lastAffected = anchor; - if (lastAffected < anchor_) - lastAffected = anchor_; - } - 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,54 +807,59 @@ }
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; }
/** * Asks document to find a good position and then moves out of any invisible positions. */ int Editor::MovePositionOutsideChar(int pos, int moveDir, bool checkLineEnd) const { - pos = pdoc->MovePositionOutsideChar(pos, moveDir, checkLineEnd); + return MovePositionOutsideChar(SelectionPosition(pos), moveDir, checkLineEnd).Position(); +} + +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 > 0) && vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected()) { - while ((pos < pdoc->Length()) && - (vs.styles[pdoc->StyleAt(pos) & mask].IsProtected())) - pos++; + 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) & mask].IsProtected()) { - while ((pos > 0) && - (vs.styles[pdoc->StyleAt(pos - 1) & mask].IsProtected())) - pos--; + 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(int newPos, selTypes sel, bool ensureVisible) { - int delta = newPos - currentPos; - newPos = pdoc->ClampPositionIntoDocument(newPos); +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 != noSel) { - selType = sel; + if (!sel.IsRectangular() && (selt == Selection::selRectangle)) { + // Switching to rectangular + SelectionRange rangeMain = sel.RangeMain(); + sel.Clear(); + sel.Rectangular() = rangeMain; } - if (sel != noSel || moveExtendsSelection) { + if (selt != Selection::noSel) { + sel.selType = selt; + } + if (selt != Selection::noSel || sel.MoveExtends()) { SetSelection(newPos); } else { SetEmptySelection(newPos); @@ -828,10 +871,14 @@ return 0; }
-int Editor::MovePositionSoVisible(int pos, int moveDir) { - pos = pdoc->ClampPositionIntoDocument(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); + int lineDoc = pdoc->LineFromPosition(pos.Position()); if (cs.GetVisible(lineDoc)) { return pos; } else { @@ -839,20 +886,28 @@ 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); +} + +Point Editor::PointMainCaret() { + return LocationFromPosition(sel.Range(sel.Main()).caret); +} + /** * 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 = PointMainCaret(); lastXChosen = pt.x; }
@@ -897,16 +952,16 @@
void Editor::MoveCaretInsideView(bool ensureVisible) { PRectangle rcClient = GetTextRectangle(); - Point pt = LocationFromPosition(currentPos); + Point pt = PointMainCaret(); 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,14 +1033,14 @@ //Platform::DebugPrintf("EnsureCaretVisible %d %s\n", xOffset, useMargin ? " margin" : " "); PRectangle rcClient = GetTextRectangle(); //int rcClientFullWidth = rcClient.Width(); - int posCaret = currentPos; - if (posDrag >= 0) { + SelectionPosition posCaret = sel.RangeMain().caret; + if (posDrag.IsValid()) { posCaret = posDrag; } Point pt = LocationFromPosition(posCaret); Point ptBottomCaret = pt; ptBottomCaret.y += vs.lineHeight - 1; - int lineCaret = DisplayFromPosition(posCaret); + int lineCaret = DisplayFromPosition(posCaret.Position()); bool bSlop, bStrict, bJump, bEven;
// Vertical positioning @@ -1222,10 +1277,13 @@ }
void Editor::InvalidateCaret() { - if (posDrag >= 0) - InvalidateRange(posDrag, posDrag + 1); - else - InvalidateRange(currentPos, currentPos + 1); + if (posDrag.IsValid()) { + InvalidateRange(posDrag.Position(), posDrag.Position() + 1); + } else { + for (size_t r=0; r<sel.Count(); r++) { + InvalidateRange(sel.Range(r).caret.Position(), sel.Range(r).caret.Position() + 1); + } + } UpdateSystemCaret(); }
@@ -1255,14 +1313,14 @@ LayoutLine(lineToWrap, surface, vs, ll, wrapWidth); linesWrapped = ll->lines; } - return cs.SetHeight(lineToWrap, linesWrapped + + return cs.SetHeight(lineToWrap, linesWrapped + (vs.annotationVisible ? pdoc->AnnotationLines(lineToWrap) : 0)); }
// Check if wrapping needed and perform any needed wrapping. // fullwrap: if true, all lines which need wrapping will be done, // in this single call. -// priorityWrapLineStart: If greater than zero, all lines starting from +// priorityWrapLineStart: If greater than or equal to zero, all lines starting from // here to 1 page + 100 lines past will be wrapped (even if there are // more lines under wrapping process in idle). // If it is neither fullwrap, nor priorityWrap, then 1 page + 100 lines will be @@ -1294,7 +1352,7 @@ if (wrapWidth != LineLayout::wrapWidthInfinite) { wrapWidth = LineLayout::wrapWidthInfinite; for (int lineDoc = 0; lineDoc < pdoc->LinesTotal(); lineDoc++) { - cs.SetHeight(lineDoc, 1 + + cs.SetHeight(lineDoc, 1 + (vs.annotationVisible ? pdoc->AnnotationLines(lineDoc) : 0)); } wrapOccurred = true; @@ -1368,7 +1426,7 @@
void Editor::LinesJoin() { if (!RangeContainsProtected(targetStart, targetEnd)) { - pdoc->BeginUndoAction(); + UndoGroup ug(pdoc); bool prevNonWS = true; for (int pos = targetStart; pos < targetEnd; pos++) { if (IsEOLChar(pdoc->CharAt(pos))) { @@ -1383,7 +1441,6 @@ prevNonWS = pdoc->CharAt(pos) != ' '; } } - pdoc->EndUndoAction(); } }
@@ -1406,7 +1463,7 @@ int lineStart = pdoc->LineFromPosition(targetStart); int lineEnd = pdoc->LineFromPosition(targetEnd); const char *eol = StringFromEOLMode(pdoc->eolMode); - pdoc->BeginUndoAction(); + UndoGroup ug(pdoc); for (int line = lineStart; line <= lineEnd; line++) { AutoSurface surface(this); AutoLineLayout ll(llc, RetrieveLineLayout(line)); @@ -1421,7 +1478,6 @@ } lineEnd = pdoc->LineFromPosition(targetEnd); } - pdoc->EndUndoAction(); } }
@@ -1483,7 +1539,7 @@ return widthMax; }
-void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent, +void DrawStyledText(Surface *surface, ViewStyle &vs, int styleOffset, PRectangle rcText, int ascent, const StyledText &st, size_t start, size_t length) {
if (st.multipleStyles) { @@ -1700,13 +1756,13 @@ if (firstSubLine) { const StyledText stMargin = pdoc->MarginStyledText(lineDoc); if (stMargin.text && ValidStyledText(vs, vs.marginStyleOffset, stMargin)) { - surface->FillRectangle(rcMarker, + surface->FillRectangle(rcMarker, vs.styles[stMargin.StyleAt(0)+vs.marginStyleOffset].back.allocated); if (vs.ms[margin].style == SC_MARGIN_RTEXT) { int width = WidestLineWidth(surface, vs, vs.marginStyleOffset, stMargin); rcMarker.left = rcMarker.right - width - 3; } - DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent, + DrawStyledText(surface, vs, vs.marginStyleOffset, rcMarker, rcMarker.top + vs.maxAscent, stMargin, 0, stMargin.length); } } @@ -1757,7 +1813,7 @@ 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 +1940,7 @@ 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 +1967,8 @@ 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 +2051,7 @@ 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 @@ -2072,16 +2132,22 @@ } }
-ColourAllocated Editor::SelectionBackground(ViewStyle &vsDraw) { - return primarySelection ? vsDraw.selbackground.allocated : vsDraw.selbackground2.allocated; +ColourAllocated Editor::SelectionBackground(ViewStyle &vsDraw, bool main) { + return main ? + (primarySelection ? vsDraw.selbackground.allocated : vsDraw.selbackground2.allocated) : + vsDraw.selAdditionalBackground.allocated; }
ColourAllocated Editor::TextBackground(ViewStyle &vsDraw, bool overrideBackground, - ColourAllocated background, bool inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) { - if (inSelection) { + ColourAllocated background, int inSelection, bool inHotspot, int styleMain, int i, LineLayout *ll) { + if (inSelection == 1) { if (vsDraw.selbackset && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { - return SelectionBackground(vsDraw); + return SelectionBackground(vsDraw, true); } + } else if (inSelection == 2) { + if (vsDraw.selbackset && (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)) { + return SelectionBackground(vsDraw, false); + } } else { if ((vsDraw.edgeState == EDGE_BACKGROUND) && (i >= ll->edgeColumn) && @@ -2183,35 +2249,103 @@ bool overrideBackground, ColourAllocated background, bool drawWrapMarkEnd, ColourAllocated wrapColour) {
- int styleMask = pdoc->stylingBitsMask; + const int posLineStart = pdoc->LineStart(line); + const int styleMask = pdoc->stylingBitsMask; PRectangle rcSegment = rcLine;
+ const bool lastSubLine = subLine == (ll->lines - 1); + int virtualSpace = 0; + if (lastSubLine) { + const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth); + virtualSpace = sel.VirtualSpaceFor(pdoc->LineEnd(line)) * 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)) { - surface->FillRectangle(rcSegment, SelectionBackground(vsDraw)); + // Fill the virtual space and show selections within it + if (virtualSpace) { + rcSegment.left = xEol + xStart; + rcSegment.right = xEol + xStart + virtualSpace; + surface->FillRectangle(rcSegment, overrideBackground ? background : vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated); + if (!hideSelection && ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA))) { + SelectionSegment virtualSpaceRange(SelectionPosition(pdoc->LineEnd(line)), SelectionPosition(pdoc->LineEnd(line), sel.VirtualSpaceFor(pdoc->LineEnd(line)))); + for (size_t r=0; r<sel.Count(); r++) { + int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + if (alpha == SC_ALPHA_NOALPHA) { + SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth); + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * spaceWidth; + rcSegment.left = Platform::Maximum(rcSegment.left, rcLine.left); + rcSegment.right = Platform::Minimum(rcSegment.right, rcLine.right); + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, r == sel.Main())); + } + } + } + } + } + + int posAfterLineEnd = pdoc->LineStart(line + 1); + int eolInSelection = (subLine == (ll->lines - 1)) ? sel.InSelectionForEOL(posAfterLineEnd) : 0; + int alpha = (eolInSelection == 1) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + + // Draw the [CR], [LF], or [CR][LF] blobs if visible line ends are on + int blobsWidth = 0; + if (lastSubLine) { + for (int eolPos=ll->numCharsBeforeEOL; eolPos<ll->numCharsInLine; eolPos++) { + rcSegment.left = xStart + ll->positions[eolPos] - subLineStart + virtualSpace; + rcSegment.right = xStart + ll->positions[eolPos+1] - subLineStart + virtualSpace; + blobsWidth += rcSegment.Width(); + const char *ctrlChar = ControlCharacterString(ll->chars[eolPos]); + int inSelection = 0; + 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 (alpha == SC_ALPHA_NOALPHA) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); + } else { + surface->FillRectangle(rcSegment, textBack); + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); + } + } else { + surface->FillRectangle(rcSegment, textBack); + } + DrawTextBlob(surface, vsDraw, rcSegment, ctrlChar, textBack, textFore, twoPhaseDraw); + } + } + + // Draw the eol-is-selected rectangle + rcSegment.left = xEol + xStart + virtualSpace + blobsWidth; + rcSegment.right = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth; + + if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); } else { if (overrideBackground) { surface->FillRectangle(rcSegment, background); + } else if (line < pdoc->LinesTotal() - 1) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated); + } else if (vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].eolFilled) { + surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated); } else { - surface->FillRectangle(rcSegment, vsDraw.styles[ll->styles[ll->numCharsInLine] & styleMask].back.allocated); + surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated); } - if (eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) { - SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha); + if (!hideSelection && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); } }
- rcSegment.left = xEol + vsDraw.aveCharWidth + xStart; + // Fill the remainder of the line + rcSegment.left = xEol + xStart + virtualSpace + blobsWidth + vsDraw.aveCharWidth; rcSegment.right = rcLine.right;
- if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha == SC_ALPHA_NOALPHA)) { - surface->FillRectangle(rcSegment, SelectionBackground(vsDraw)); + if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha == SC_ALPHA_NOALPHA)) { + surface->FillRectangle(rcSegment, SelectionBackground(vsDraw, eolInSelection == 1)); } else { if (overrideBackground) { surface->FillRectangle(rcSegment, background); @@ -2220,8 +2354,8 @@ } else { surface->FillRectangle(rcSegment, vsDraw.styles[STYLE_DEFAULT].back.allocated); } - if (vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (vsDraw.selAlpha != SC_ALPHA_NOALPHA)) { - SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw), vsDraw.selAlpha); + if (!hideSelection && vsDraw.selEOLFilled && eolInSelection && vsDraw.selbackset && (line < pdoc->LinesTotal() - 1) && (alpha != SC_ALPHA_NOALPHA)) { + SimpleAlphaRectangle(surface, rcSegment, SelectionBackground(vsDraw, eolInSelection == 1), alpha); } }
@@ -2229,7 +2363,7 @@ PRectangle rcPlace = rcSegment;
if (wrapVisualFlagsLocation & SC_WRAPVISUALFLAGLOC_END_BY_TEXT) { - rcPlace.left = xEol + xStart; + rcPlace.left = xEol + xStart + virtualSpace; rcPlace.right = rcPlace.left + vsDraw.aveCharWidth; } else { // draw left of the right text margin, to avoid clipping by the current clip rect @@ -2336,11 +2470,11 @@ } PRectangle rcText = rcSegment; if (vs.annotationVisible == ANNOTATION_BOXED) { - surface->FillRectangle(rcText, + surface->FillRectangle(rcText, vsDraw.styles[stAnnotation.StyleAt(start) + vsDraw.annotationStyleOffset].back.allocated); rcText.left += vsDraw.spaceWidth; } - DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent, + DrawStyledText(surface, vsDraw, vsDraw.annotationStyleOffset, rcText, rcText.top + vsDraw.maxAscent, stAnnotation, start, lengthAnnotation); if (vs.annotationVisible == ANNOTATION_BOXED) { surface->MoveTo(rcSegment.left, rcSegment.top); @@ -2350,7 +2484,7 @@ if (subLine == ll->lines){ surface->MoveTo(rcSegment.left, rcSegment.top); surface->LineTo(rcSegment.right, rcSegment.top); - } + } if (subLine == ll->lines+annotationLines-1) { surface->MoveTo(rcSegment.left, rcSegment.bottom - 1); surface->LineTo(rcSegment.right, rcSegment.bottom - 1); @@ -2427,6 +2561,9 @@ 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; @@ -2478,10 +2615,15 @@ } }
+ bool selBackDrawn = vsDraw.selbackset && + ((vsDraw.selAlpha == SC_ALPHA_NOALPHA) || (vsDraw.selAdditionalAlpha == SC_ALPHA_NOALPHA)); + // Does not take margin into account but not significant int xStartVisible = subLineStart - xStart;
- BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible); + ll->psel = &sel; + + BreakFinder bfBack(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible, selBackDrawn); int next = bfBack.First();
// Background drawing loop @@ -2502,7 +2644,7 @@ 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 int inSelection = hideSelection ? 0 : 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') { @@ -2571,7 +2713,8 @@
inIndentation = subLine == 0; // Do not handle indentation except on first subline. // Foreground drawing loop - BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible); + BreakFinder bfFore(ll, lineStart, lineEnd, posLineStart, IsUnicodeMode(), xStartVisible, + ((!twoPhaseDraw && selBackDrawn) || vsDraw.selforeset)); next = bfFore.First();
while (next < lineEnd) { @@ -2595,9 +2738,9 @@ if (vsDraw.hotspotForegroundSet) textFore = vsDraw.hotspotForeground.allocated; } - bool inSelection = (iDoc >= ll->selStart) && (iDoc < ll->selEnd) && (ll->selStart != ll->selEnd); + const int inSelection = hideSelection ? 0 : sel.CharacterInSelection(iDoc); if (inSelection && (vsDraw.selforeset)) { - textFore = vsDraw.selforeground.allocated; + textFore = (inSelection == 1) ? vsDraw.selforeground.allocated : vsDraw.selAdditionalForeground.allocated; } bool inHotspot = (ll->hsStart != -1) && (iDoc >= ll->hsStart) && (iDoc < ll->hsEnd); ColourAllocated textBack = TextBackground(vsDraw, overrideBackground, background, inSelection, inHotspot, styleMain, i, ll); @@ -2679,8 +2822,8 @@ surface->FillRectangle(rcSpace, textBack); } PRectangle rcDot(xmid + xStart - subLineStart, rcSegment.top + vsDraw.lineHeight / 2, 0, 0); - rcDot.right = rcDot.left + 1; - rcDot.bottom = rcDot.top + 1; + rcDot.right = rcDot.left + vs.whitespaceSize; + rcDot.bottom = rcDot.top + vs.whitespaceSize; surface->FillRectangle(rcDot, textFore); } } @@ -2718,6 +2861,8 @@ if ((vsDraw.viewIndentationGuides == ivLookForward || vsDraw.viewIndentationGuides == ivLookBoth) && (subLine == 0)) { int indentSpace = pdoc->GetLineIndentation(line); + int xStartText = ll->positions[pdoc->GetLineIndentPosition(line) - posLineStart]; + // Find the most recent line with some text
int lineLastWithText = line; @@ -2725,6 +2870,7 @@ lineLastWithText--; } if (lineLastWithText < line) { + xStartText = 100000; // Don't limit to visible indentation on empty line // This line is empty, so use indentation of last line with text int indentLastWithText = pdoc->GetLineIndentation(lineLastWithText); int isFoldHeader = pdoc->GetLevel(lineLastWithText) & SC_FOLDLEVELHEADERFLAG; @@ -2754,8 +2900,10 @@
for (int indentPos = pdoc->IndentSize(); indentPos < indentSpace; indentPos += pdoc->IndentSize()) { int xIndent = indentPos * vsDraw.spaceWidth; - DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, - (ll->xHighlightGuide == xIndent)); + if (xIndent < xStartText) { + DrawIndentGuide(surface, lineVisible, vsDraw.lineHeight, xIndent + xStart, rcSegment, + (ll->xHighlightGuide == xIndent)); + } } }
@@ -2767,16 +2915,29 @@ 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) || (vsDraw.selAdditionalAlpha != SC_ALPHA_NOALPHA))) { + // For each selection draw + int virtualSpaces = 0; + if (subLine == (ll->lines - 1)) { + virtualSpaces = sel.VirtualSpaceFor(pdoc->LineEnd(line)); } + SelectionPosition posStart(posLineStart); + SelectionPosition posEnd(posLineStart + lineEnd, virtualSpaces); + SelectionSegment virtualSpaceRange(posStart, posEnd); + for (size_t r=0; r<sel.Count(); r++) { + int alpha = (r == sel.Main()) ? vsDraw.selAlpha : vsDraw.selAdditionalAlpha; + if (alpha != SC_ALPHA_NOALPHA) { + SelectionSegment portion = sel.Range(r).Intersect(virtualSpaceRange); + if (!portion.Empty()) { + const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth); + rcSegment.left = xStart + ll->positions[portion.start.Position() - posLineStart] - subLineStart + portion.start.VirtualSpace() * spaceWidth; + rcSegment.right = xStart + ll->positions[portion.end.Position() - posLineStart] - subLineStart + portion.end.VirtualSpace() * 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()), alpha); + } + } + } }
// Draw any translucent whole line states @@ -2809,7 +2970,8 @@ } }
-void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, int xStart, int offset, int posCaret, PRectangle rcCaret) { +void Editor::DrawBlockCaret(Surface *surface, ViewStyle &vsDraw, LineLayout *ll, int subLine, + int xStart, int offset, int posCaret, PRectangle rcCaret, ColourAllocated caretColour) {
int lineStart = ll->LineStart(subLine); int posBefore = posCaret; @@ -2868,7 +3030,7 @@ surface->DrawTextClipped(rcCaret, vsDraw.styles[styleMain].font, rcCaret.top + vsDraw.maxAscent, ll->chars + offsetFirstChar, numCharsToDraw, vsDraw.styles[styleMain].back.allocated, - vsDraw.caretcolour.allocated); + caretColour); }
void Editor::RefreshPixMaps(Surface *surfaceWindow) { @@ -2937,6 +3099,89 @@ } }
+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.IsValid(); + if (hideSelection && !drawDrag) + return; + const int posLineStart = pdoc->LineStart(lineDoc); + // For each selection draw + for (size_t r=0; (r<sel.Count()) || drawDrag; r++) { + const bool mainCaret = r == sel.Main(); + const SelectionPosition posCaret = (drawDrag ? posDrag : sel.Range(r).caret); + const int offset = posCaret.Position() - posLineStart; + const int spaceWidth = static_cast<int>(vsDraw.styles[ll->EndLineStyle()].spaceWidth); + const int virtualOffset = posCaret.VirtualSpace() * spaceWidth; + if (ll->InLine(offset, subLine) && offset <= ll->numCharsBeforeEOL) { + int xposCaret = ll->positions[offset] + virtualOffset - ll->positions[ll->LineStart(subLine)]; + if (ll->wrapIndent != 0) { + int lineStart = ll->LineStart(subLine); + if (lineStart != 0) // Wrapped + xposCaret += ll->wrapIndent; + } + bool caretBlinkState = (caret.active && caret.on) || (!additionalCaretsBlink && !mainCaret); + bool caretVisibleState = additionalCaretsVisible || mainCaret; + if ((xposCaret >= 0) && (vsDraw.caretWidth > 0) && (vsDraw.caretStyle != CARETSTYLE_INVISIBLE) && + ((posDrag.IsValid()) || (caretBlinkState && caretVisibleState))) { + bool caretAtEOF = false; + bool caretAtEOL = false; + bool drawBlockCaret = false; + int widthOverstrikeCaret; + int caretWidthOffset = 0; + PRectangle rcCaret = rcLine; + + if (posCaret.Position() == pdoc->Length()) { // At end of document + caretAtEOF = true; + widthOverstrikeCaret = vsDraw.aveCharWidth; + } else if ((posCaret.Position() - posLineStart) >= 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 (xposCaret > 0) + caretWidthOffset = 1; // Move back so overlaps both character cells. + xposCaret += xStart; + if (posDrag.IsValid()) { + /* 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; + } + ColourAllocated caretColour = mainCaret ? vsDraw.caretcolour.allocated : vsDraw.additionalCaretColour.allocated; + if (drawBlockCaret) { + DrawBlockCaret(surface, vsDraw, ll, subLine, xStart, offset, posCaret.Position(), rcCaret, caretColour); + } else { + surface->FillRectangle(rcCaret, caretColour); + } + } + } + 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); @@ -2989,7 +3234,7 @@ // lines first). int startLineToWrap = cs.DocFromDisplay(topLine) - 5; if (startLineToWrap < 0) - startLineToWrap = -1; + startLineToWrap = 0; if (WrapLines(false, startLineToWrap)) { // The wrapping process has changed the height of some lines so // abandon this paint for a complete repaint. @@ -3036,10 +3281,10 @@
int visibleLine = topLine + screenLinePaintFirst;
- int posCaret = currentPos; - if (posDrag >= 0) + SelectionPosition posCaret = sel.RangeMain().caret; + if (posDrag.IsValid()) posCaret = posDrag; - int lineCaret = pdoc->LineFromPosition(posCaret); + int lineCaret = pdoc->LineFromPosition(posCaret.Position());
// Remove selection margin from drawing area so text will not be drawn // on it in unbuffered mode. @@ -3055,7 +3300,6 @@ //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 +3313,6 @@ //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 +3320,8 @@ //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,78 +3365,17 @@ } }
- // 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; + DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);
- 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); - } - } - } - } - if (bufferedDraw) { Point from(vs.fixedColumnWidth, 0); PRectangle rcCopyArea(vs.fixedColumnWidth, yposScreen, rcClient.right, yposScreen + vs.lineHeight); surfaceWindow->Copy(rcCopyArea, from, *pixmapLine); } + + lineWidthMaxSeen = Platform::Maximum( + lineWidthMaxSeen, ll->positions[ll->numCharsInLine]); //durCopy += et.Duration(true); }
@@ -3214,8 +3386,6 @@ yposScreen += vs.lineHeight; visibleLine++;
- lineWidthMaxSeen = Platform::Maximum( - lineWidthMaxSeen, ll->positions[ll->numCharsInLine]); //gdk_flush(); } ll.Set(0); @@ -3298,6 +3468,7 @@ vsPrint.selbackset = false; vsPrint.selforeset = false; vsPrint.selAlpha = SC_ALPHA_NOALPHA; + vsPrint.selAdditionalAlpha = SC_ALPHA_NOALPHA; vsPrint.whitespaceBackgroundSet = false; vsPrint.whitespaceForegroundSet = false; vsPrint.showCaretLineBackground = false; @@ -3375,8 +3546,6 @@ LineLayout ll(8000); LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
- ll.selStart = -1; - ll.selEnd = -1; ll.containsCaret = false;
PRectangle rcLine; @@ -3499,6 +3668,15 @@ } }
+int Editor::InsertSpace(int position, unsigned int spaces) { + if (spaces > 0) { + std::string spaceText(spaces, ' '); + pdoc->InsertString(position, spaceText.c_str(), spaces); + position += spaces; + } + return position; +} + void Editor::AddChar(char ch) { char s[2]; s[0] = ch; @@ -3506,63 +3684,60 @@ AddCharUTF(s, 1); }
+void Editor::FilterSelections() { + if (!additionalSelectionTyping && (sel.Count() > 1)) { + SelectionRange rangeOnly = sel.RangeMain(); + InvalidateSelection(rangeOnly, true); + sel.SetSelection(rangeOnly); + } +} + // 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; - if(wasSelection && selType == selRectangle ) { - int startPos; - int endPos; - - int c1 = pdoc->GetColumn(currentPos); - int c2 = pdoc->GetColumn(anchor); - int offset = c1 < c2 ? c1 : c2; - - pdoc->BeginUndoAction(); - SelectionLineIterator lineIterator(this, false); - while (lineIterator.Iterate()) { - startPos = lineIterator.startPos; - endPos = lineIterator.endPos; - - if(pdoc->GetColumn(endPos) >= offset){ - unsigned int chars = endPos - startPos; - if (0 != chars) { - pdoc->DeleteChars(startPos, chars); - } - pdoc->InsertString(startPos, s, len); - } - } - anchor += len; - currentPos += len; - SetRectangularRange(); - pdoc->EndUndoAction(); - - } else { - 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); + FilterSelections(); + { + UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty() || inOverstrike); + 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.Range(r).ClearVirtualSpace(); + } 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.Range(r).ClearVirtualSpace(); + } + } } + positionInsert = InsertSpace(positionInsert, sel.Range(r).caret.VirtualSpace()); + if (pdoc->InsertString(positionInsert, s, len)) { + sel.Range(r).caret.SetPosition(positionInsert + len); + sel.Range(r).anchor.SetPosition(positionInsert + len); + } + sel.Range(r).ClearVirtualSpace(); + // 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) { - 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(); } + ThinRectangularRange(); + // If in wrap mode rewrap current line so EnsureCaretVisible has accurate information EnsureCaretVisible(); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); @@ -3606,48 +3781,44 @@ } NotifyChar(byte); } + + if (recordingMacro) { + NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(s)); + } }
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(); + if (!sel.IsRectangular()) + FilterSelections(); + UndoGroup ug(pdoc); + 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.Range(r) = sel.Range(r).Start(); } - } 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->EndUndoAction(); - selType = selStream; } - SetEmptySelection(startPos); } + ThinRectangularRange(); + sel.RemoveDuplicates(); + ClaimSelection(); }
void Editor::ClearAll() { - pdoc->BeginUndoAction(); - if (0 != pdoc->Length()) { - pdoc->DeleteChars(0, pdoc->Length()); + { + UndoGroup ug(pdoc); + if (0 != pdoc->Length()) { + pdoc->DeleteChars(0, pdoc->Length()); + } + if (!pdoc->IsReadOnly()) { + cs.Clear(); + pdoc->AnnotationClearAll(); + pdoc->MarginClearAll(); + } } - if (!pdoc->IsReadOnly()) { - cs.Clear(); - pdoc->AnnotationClearAll(); - pdoc->MarginClearAll(); - } - pdoc->EndUndoAction(); - anchor = 0; - currentPos = 0; + sel.Clear(); SetTopLine(0); SetVerticalScrollPos(); InvalidateStyleRedraw(); @@ -3684,15 +3855,20 @@ } }
-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); + int line = pdoc->LineFromPosition(sel.MainCaret()); + UndoGroup ug(pdoc); + sel.RangeMain().caret = SelectionPosition( + InsertSpace(sel.RangeMain().caret.Position(), sel.RangeMain().caret.VirtualSpace())); + int xInsert = XFromPosition(sel.RangeMain().caret); bool prevCr = false; - pdoc->BeginUndoAction(); + while ((len > 0) && IsEOLChar(ptr[len-1])) + len--; for (int i = 0; i < len; i++) { if (IsEOLChar(ptr[i])) { if ((ptr[i] == '\r') || (!prevCr)) @@ -3704,21 +3880,20 @@ 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; } } - pdoc->EndUndoAction(); SetEmptySelection(pos); }
@@ -3727,44 +3902,33 @@ }
void Editor::Clear() { - bool wasSelection = currentPos != anchor; - if(wasSelection && selType == selRectangle ) { - int startPos; - int endPos; - - int c1 = pdoc->GetColumn(currentPos); - int c2 = pdoc->GetColumn(anchor); - int offset = c1 < c2 ? c1 : c2; - - pdoc->BeginUndoAction(); - SelectionLineIterator lineIterator(this, false); - while (lineIterator.Iterate()) { - startPos = lineIterator.startPos; - endPos = lineIterator.endPos; - - if(pdoc->GetColumn(endPos) >= offset){ - unsigned int chars = endPos - startPos; - if (0 != chars) { - pdoc->DeleteChars(startPos, chars); - } else - pdoc->DelChar(startPos); - } - } - SetRectangularRange(); - pdoc->EndUndoAction(); - - } else if (currentPos == anchor) { - if (!RangeContainsProtected(currentPos, currentPos + 1)) { - DelChar(); + UndoGroup ug(pdoc); + // If multiple selections, don't delete EOLS + 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).Start().VirtualSpace()) { + if (sel.Range(r).anchor < sel.Range(r).caret) + sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).anchor.Position(), sel.Range(r).anchor.VirtualSpace())); + else + sel.Range(r) = SelectionPosition(InsertSpace(sel.Range(r).caret.Position(), sel.Range(r).caret.VirtualSpace())); + } + if ((sel.Count() == 1) || !IsEOLChar(pdoc->CharAt(sel.Range(r).caret.Position()))) { + pdoc->DelChar(sel.Range(r).caret.Position()); + sel.Range(r).ClearVirtualSpace(); + } // else multiple selection so don't eat line ends + } else { + sel.Range(r).ClearVirtualSpace(); + } } } else { ClearSelection(); } - if( !wasSelection ) - SetEmptySelection(currentPos); + sel.RemoveDuplicates(); }
void Editor::SelectAll() { + sel.Clear(); SetSelection(0, pdoc->Length()); Redraw(); } @@ -3789,65 +3953,54 @@ }
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) { - bool wasSelection = currentPos != anchor; - if(wasSelection && selType == selRectangle ) { - int startPos; - int endPos; - - int c1 = pdoc->GetColumn(currentPos); - int c2 = pdoc->GetColumn(anchor); - int offset = c1 < c2 ? c1 : c2; - - pdoc->BeginUndoAction(); - SelectionLineIterator lineIterator(this, false); - while (lineIterator.Iterate()) { - startPos = lineIterator.startPos; - endPos = lineIterator.endPos; - - if(pdoc->GetColumn(endPos) >= offset){ - unsigned int chars = endPos - startPos; - if (0 != chars) { - pdoc->DeleteChars(startPos, chars); - } else - pdoc->DelCharBack(startPos); - } - } - SetRectangularRange(); - pdoc->EndUndoAction(); - - } else 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) { - 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)); + if (!sel.IsRectangular()) + FilterSelections(); + if (sel.IsRectangular()) + allowLineStartDeletion = false; + UndoGroup ug(pdoc, (sel.Count() > 1) || !sel.Empty()); + 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) { + UndoGroup ugInner(pdoc, !ug.Needed()); + 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)); + } else { + pdoc->DelCharBack(sel.Range(r).caret.Position()); + } } - SetEmptySelection(pdoc->GetLineIndentPosition(lineCurrentPos)); - pdoc->EndUndoAction(); - } else { - pdoc->DelCharBack(currentPos); } + } else { + sel.Range(r).ClearVirtualSpace(); } } } else { ClearSelection(); - SetEmptySelection(currentPos); } + sel.RemoveDuplicates(); // Avoid blinking during rapid typing: ShowCaretAtCurrentPosition(); } @@ -3870,12 +4023,6 @@ scn.nmhdr.code = SCN_CHARADDED; scn.ch = ch; NotifyParent(scn); - if (recordingMacro) { - char txt[2]; - txt[0] = static_cast<char>(ch); - txt[1] = '\0'; - NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt)); - } }
void Editor::NotifySavePoint(bool isSavePoint) { @@ -4072,13 +4219,11 @@ } 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); } @@ -4310,11 +4455,11 @@ * 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( @@ -4330,7 +4475,7 @@ 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()); @@ -4340,39 +4485,29 @@
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); + UndoGroup ug(pdoc); + 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(); + UndoGroup ug(pdoc); int startPrev = pdoc->LineStart(line - 1); int endPrev = pdoc->LineEnd(line - 1); int start = pdoc->LineStart(line); @@ -4385,37 +4520,54 @@ 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(); } }
void Editor::Duplicate(bool forLine) { - int start = SelectionStart(); - int end = SelectionEnd(); - if (start == end) { + if (sel.Empty()) { forLine = true; } + UndoGroup ug(pdoc, sel.Count() > 1); + SelectionPosition last; + const char *eol = ""; + int eolLen = 0; if (forLine) { - int line = pdoc->LineFromPosition(currentPos); - start = pdoc->LineStart(line); - end = pdoc->LineEnd(line); + eol = StringFromEOLMode(pdoc->eolMode); + eolLen = istrlen(eol); } - char *text = CopyRange(start, end); - if (forLine) { - const char *eol = StringFromEOLMode(pdoc->eolMode); - pdoc->InsertCString(end, eol); - pdoc->InsertString(end + istrlen(eol), text, end - start); - } else { - pdoc->InsertString(end, text, end - start); + for (size_t r=0; r<sel.Count(); r++) { + SelectionPosition start = sel.Range(r).Start(); + SelectionPosition end = sel.Range(r).End(); + if (forLine) { + int line = pdoc->LineFromPosition(sel.Range(r).caret.Position()); + start = SelectionPosition(pdoc->LineStart(line)); + end = SelectionPosition(pdoc->LineEnd(line)); + } + char *text = CopyRange(start.Position(), end.Position()); + if (forLine) + pdoc->InsertString(end.Position(), eol, eolLen); + pdoc->InsertString(end.Position() + eolLen, text, SelectionRange(end, start).Length()); + delete []text; } - delete []text; + if (sel.Count() && sel.IsRectangular()) { + SelectionPosition last = sel.Last(); + if (forLine) { + int line = pdoc->LineFromPosition(last.Position()); + last = SelectionPosition(last.Position() + pdoc->LineStart(line+1) - pdoc->LineStart(line)); + } + if (sel.Rectangular().anchor > sel.Rectangular().caret) + sel.Rectangular().anchor = last; + else + sel.Rectangular().caret = last; + SetRectangularRange(); + } }
void Editor::CancelModes() { - moveExtendsSelection = false; + sel.SetMoveExtends(false); }
void Editor::NewLine() { @@ -4426,10 +4578,16 @@ } 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); + if (recordingMacro) { + char txt[2]; + txt[0] = *eol; + txt[1] = '\0'; + NotifyMacroRecord(SCI_REPLACESEL, 0, reinterpret_cast<sptr_t>(txt)); + } eol++; } } @@ -4440,41 +4598,50 @@ 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) { + SelectionPosition caretToUse = sel.Range(sel.Main()).caret; + if (sel.IsRectangular()) { + if (selt == Selection::noSel) { + caretToUse = (direction > 0) ? sel.Limits().end : sel.Limits().start; + } else { + caretToUse = sel.Rectangular().caret; + } + } + Point pt = LocationFromPosition(caretToUse); + int lineDoc = pdoc->LineFromPosition(caretToUse.Position()); 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( - Point(lastXChosen, pt.y + direction * vs.lineHeight)); + SelectionPosition posNew = SPositionFromLocation( + Point(lastXChosen, pt.y + direction * vs.lineHeight), false, false, UserVirtualSpace()); if ((direction > 0) && (subLine >= (cs.GetHeight(lineDoc) - 1 - commentLines))) { - posNew = PositionFromLocation( - Point(lastXChosen, pt.y + (commentLines + 1) * vs.lineHeight)); + posNew = SPositionFromLocation( + Point(lastXChosen, pt.y + (commentLines + 1) * vs.lineHeight), false, false, UserVirtualSpace()); } if (direction < 0) { // Line wrapping may lead to a location on the same line, so // 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; } @@ -4520,16 +4687,16 @@ 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); @@ -4539,144 +4706,182 @@ 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 ((sel.Count() == 1) && 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.LimitsForRectangularElseMain().start).Position() - 1), -1)); + } } else { - MovePositionTo(SelectionStart()); + MovePositionTo(sel.LimitsForRectangularElseMain().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.LimitsForRectangularElseMain().end).Position() + 1), 1)); + } } else { - MovePositionTo(SelectionEnd()); + MovePositionTo(sel.LimitsForRectangularElseMain().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; @@ -4685,7 +4890,7 @@ SetLastXChosen(); break; case SCI_DOCUMENTSTARTEXTEND: - MovePositionTo(0, selStream); + MovePositionTo(0, Selection::selStream); SetLastXChosen(); break; case SCI_DOCUMENTEND: @@ -4693,38 +4898,38 @@ 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; @@ -4773,21 +4978,21 @@ 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))
@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.