diff options
Diffstat (limited to 'scintilla/src')
-rw-r--r-- | scintilla/src/AutoComplete.cxx | 119 | ||||
-rw-r--r-- | scintilla/src/AutoComplete.h | 6 | ||||
-rw-r--r-- | scintilla/src/CellBuffer.cxx | 114 | ||||
-rw-r--r-- | scintilla/src/CellBuffer.h | 8 | ||||
-rw-r--r-- | scintilla/src/ContractionState.cxx | 2 | ||||
-rw-r--r-- | scintilla/src/Document.cxx | 58 | ||||
-rw-r--r-- | scintilla/src/Document.h | 13 | ||||
-rw-r--r-- | scintilla/src/Editor.cxx | 371 | ||||
-rw-r--r-- | scintilla/src/Editor.h | 58 | ||||
-rw-r--r-- | scintilla/src/LineMarker.cxx | 5 | ||||
-rw-r--r-- | scintilla/src/PositionCache.h | 4 | ||||
-rw-r--r-- | scintilla/src/RunStyles.h | 2 | ||||
-rw-r--r-- | scintilla/src/ScintillaBase.cxx | 141 | ||||
-rw-r--r-- | scintilla/src/ScintillaBase.h | 1 | ||||
-rw-r--r-- | scintilla/src/UniConversion.h | 13 | ||||
-rw-r--r-- | scintilla/src/ViewStyle.cxx | 32 | ||||
-rw-r--r-- | scintilla/src/ViewStyle.h | 12 |
17 files changed, 786 insertions, 173 deletions
diff --git a/scintilla/src/AutoComplete.cxx b/scintilla/src/AutoComplete.cxx index f0980c7..9530808 100644 --- a/scintilla/src/AutoComplete.cxx +++ b/scintilla/src/AutoComplete.cxx @@ -10,7 +10,9 @@ #include <stdio.h>
#include <assert.h>
+#include <algorithm>
#include <string>
+#include <vector>
#include "Platform.h"
@@ -36,7 +38,8 @@ AutoComplete::AutoComplete() : dropRestOfWord(false),
ignoreCaseBehaviour(SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE),
widthLBDefault(100),
- heightLBDefault(100) {
+ heightLBDefault(100),
+ autoSort(SC_ORDER_PRESORTED) {
lb = ListBox::Allocate();
stopChars[0] = '\0';
fillUpChars[0] = '\0';
@@ -101,8 +104,91 @@ char AutoComplete::GetTypesep() const { return typesep;
}
+struct Sorter {
+ AutoComplete *ac;
+ const char *list;
+ std::vector<int> indices;
+
+ Sorter(AutoComplete *ac_, const char *list_) : ac(ac_), list(list_) {
+ int i = 0;
+ while (list[i]) {
+ indices.push_back(i); // word start
+ while (list[i] != ac->GetTypesep() && list[i] != ac->GetSeparator() && list[i])
+ ++i;
+ indices.push_back(i); // word end
+ if (list[i] == ac->GetTypesep()) {
+ while (list[i] != ac->GetSeparator() && list[i])
+ ++i;
+ }
+ if (list[i] == ac->GetSeparator()) {
+ ++i;
+ // preserve trailing separator as blank entry
+ if (!list[i]) {
+ indices.push_back(i);
+ indices.push_back(i);
+ }
+ }
+ }
+ indices.push_back(i); // index of last position
+ }
+
+ bool operator()(int a, int b) {
+ int lenA = indices[a * 2 + 1] - indices[a * 2];
+ int lenB = indices[b * 2 + 1] - indices[b * 2];
+ int len = std::min(lenA, lenB);
+ int cmp;
+ if (ac->ignoreCase)
+ cmp = CompareNCaseInsensitive(list + indices[a * 2], list + indices[b * 2], len);
+ else
+ cmp = strncmp(list + indices[a * 2], list + indices[b * 2], len);
+ if (cmp == 0)
+ cmp = lenA - lenB;
+ return cmp < 0;
+ }
+};
+
void AutoComplete::SetList(const char *list) {
- lb->SetList(list, separator, typesep);
+ if (autoSort == SC_ORDER_PRESORTED) {
+ lb->SetList(list, separator, typesep);
+ sortMatrix.clear();
+ for (int i = 0; i < lb->Length(); ++i)
+ sortMatrix.push_back(i);
+ return;
+ }
+
+ Sorter IndexSort(this, list);
+ sortMatrix.clear();
+ for (int i = 0; i < (int)IndexSort.indices.size() / 2; ++i)
+ sortMatrix.push_back(i);
+ std::sort(sortMatrix.begin(), sortMatrix.end(), IndexSort);
+ if (autoSort == SC_ORDER_CUSTOM || sortMatrix.size() < 2) {
+ lb->SetList(list, separator, typesep);
+ PLATFORM_ASSERT(lb->Length() == static_cast<int>(sortMatrix.size()));
+ return;
+ }
+
+ std::string sortedList;
+ char item[maxItemLen];
+ for (size_t i = 0; i < sortMatrix.size(); ++i) {
+ int wordLen = IndexSort.indices[sortMatrix[i] * 2 + 2] - IndexSort.indices[sortMatrix[i] * 2];
+ strncpy(item, list + IndexSort.indices[sortMatrix[i] * 2], wordLen);
+ if ((i+1) == sortMatrix.size()) {
+ // Last item so remove separator if present
+ if ((wordLen > 0) && (item[wordLen-1] == separator))
+ wordLen--;
+ } else {
+ // Item before last needs a separator
+ if ((wordLen == 0) || (item[wordLen-1] != separator)) {
+ item[wordLen] = separator;
+ wordLen++;
+ }
+ }
+ item[wordLen] = '\0';
+ sortedList += item;
+ }
+ for (int i = 0; i < (int)sortMatrix.size(); ++i)
+ sortMatrix[i] = i;
+ lb->SetList(sortedList.c_str(), separator, typesep);
}
int AutoComplete::GetSelection() const {
@@ -149,7 +235,7 @@ void AutoComplete::Select(const char *word) { while ((start <= end) && (location == -1)) { // Binary searching loop
int pivot = (start + end) / 2;
char item[maxItemLen];
- lb->GetValue(pivot, item, maxItemLen);
+ lb->GetValue(sortMatrix[pivot], item, maxItemLen);
int cond;
if (ignoreCase)
cond = CompareNCaseInsensitive(word, item, lenWord);
@@ -158,7 +244,7 @@ void AutoComplete::Select(const char *word) { if (!cond) {
// Find first match
while (pivot > start) {
- lb->GetValue(pivot-1, item, maxItemLen);
+ lb->GetValue(sortMatrix[pivot-1], item, maxItemLen);
if (ignoreCase)
cond = CompareNCaseInsensitive(word, item, lenWord);
else
@@ -172,7 +258,7 @@ void AutoComplete::Select(const char *word) { && ignoreCaseBehaviour == SC_CASEINSENSITIVEBEHAVIOUR_RESPECTCASE) {
// Check for exact-case match
for (; pivot <= end; pivot++) {
- lb->GetValue(pivot, item, maxItemLen);
+ lb->GetValue(sortMatrix[pivot], item, maxItemLen);
if (!strncmp(word, item, lenWord)) {
location = pivot;
break;
@@ -187,9 +273,24 @@ void AutoComplete::Select(const char *word) { start = pivot + 1;
}
}
- if (location == -1 && autoHide)
- Cancel();
- else
- lb->Select(location);
+ if (location == -1) {
+ if (autoHide)
+ Cancel();
+ else
+ lb->Select(-1);
+ } else {
+ if (autoSort == SC_ORDER_CUSTOM) {
+ // Check for a logically earlier match
+ char item[maxItemLen];
+ for (int i = location + 1; i <= end; ++i) {
+ lb->GetValue(sortMatrix[i], item, maxItemLen);
+ if (CompareNCaseInsensitive(word, item, lenWord))
+ break;
+ if (sortMatrix[i] < sortMatrix[location] && !strncmp(word, item, lenWord))
+ location = i;
+ }
+ }
+ lb->Select(sortMatrix[location]);
+ }
}
diff --git a/scintilla/src/AutoComplete.h b/scintilla/src/AutoComplete.h index ed215ec..c6562d2 100644 --- a/scintilla/src/AutoComplete.h +++ b/scintilla/src/AutoComplete.h @@ -21,6 +21,7 @@ class AutoComplete { char separator;
char typesep; // Type seperator
enum { maxItemLen=1000 };
+ std::vector<int> sortMatrix;
public:
@@ -36,6 +37,11 @@ public: unsigned int ignoreCaseBehaviour;
int widthLBDefault;
int heightLBDefault;
+ /** SC_ORDER_PRESORTED: Assume the list is presorted; selection will fail if it is not alphabetical<br />
+ * SC_ORDER_PERFORMSORT: Sort the list alphabetically; start up performance cost for sorting<br />
+ * SC_ORDER_CUSTOM: Handle non-alphabetical entries; start up performance cost for generating a sorted lookup table
+ */
+ int autoSort;
AutoComplete();
~AutoComplete();
diff --git a/scintilla/src/CellBuffer.cxx b/scintilla/src/CellBuffer.cxx index 003710f..7c1b42c 100644 --- a/scintilla/src/CellBuffer.cxx +++ b/scintilla/src/CellBuffer.cxx @@ -16,6 +16,7 @@ #include "SplitVector.h"
#include "Partitioning.h"
#include "CellBuffer.h"
+#include "UniConversion.h"
#ifdef SCI_NAMESPACE
using namespace Scintilla;
@@ -331,6 +332,7 @@ void UndoHistory::CompletedRedoStep() { CellBuffer::CellBuffer() {
readOnly = false;
+ utf8LineEnds = 0;
collectingUndo = true;
}
@@ -458,6 +460,13 @@ void CellBuffer::Allocate(int newSize) { style.ReAllocate(newSize);
}
+void CellBuffer::SetLineEndTypes(int utf8LineEnds_) {
+ if (utf8LineEnds != utf8LineEnds_) {
+ utf8LineEnds = utf8LineEnds_;
+ ResetLineEnds();
+ }
+}
+
void CellBuffer::SetPerLine(PerLine *pl) {
lv.SetPerLine(pl);
}
@@ -501,11 +510,63 @@ void CellBuffer::RemoveLine(int line) { lv.RemoveLine(line);
}
+bool CellBuffer::UTF8LineEndOverlaps(int position) const {
+ unsigned char bytes[] = {
+ static_cast<unsigned char>(substance.ValueAt(position-2)),
+ static_cast<unsigned char>(substance.ValueAt(position-1)),
+ static_cast<unsigned char>(substance.ValueAt(position)),
+ static_cast<unsigned char>(substance.ValueAt(position+1)),
+ };
+ return UTF8IsSeparator(bytes) || UTF8IsSeparator(bytes+1) || UTF8IsNEL(bytes+1);
+}
+
+void CellBuffer::ResetLineEnds() {
+ // Reinitialize line data -- too much work to preserve
+ lv.Init();
+
+ int position = 0;
+ int length = Length();
+ int lineInsert = 1;
+ bool atLineStart = true;
+ lv.InsertText(lineInsert-1, length);
+ unsigned char chBeforePrev = 0;
+ unsigned char chPrev = 0;
+ for (int i = 0; i < length; i++) {
+ unsigned char ch = substance.ValueAt(position + i);
+ if (ch == '\r') {
+ InsertLine(lineInsert, (position + i) + 1, atLineStart);
+ lineInsert++;
+ } else if (ch == '\n') {
+ if (chPrev == '\r') {
+ // Patch up what was end of line
+ lv.SetLineStart(lineInsert - 1, (position + i) + 1);
+ } else {
+ InsertLine(lineInsert, (position + i) + 1, atLineStart);
+ lineInsert++;
+ }
+ } else if (utf8LineEnds) {
+ unsigned char back3[3] = {chBeforePrev, chPrev, ch};
+ if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) {
+ InsertLine(lineInsert, (position + i) + 1, atLineStart);
+ lineInsert++;
+ }
+ }
+ chBeforePrev = chPrev;
+ chPrev = ch;
+ }
+}
+
void CellBuffer::BasicInsertString(int position, const char *s, int insertLength) {
if (insertLength == 0)
return;
PLATFORM_ASSERT(insertLength > 0);
+ unsigned char chAfter = substance.ValueAt(position);
+ bool breakingUTF8LineEnd = false;
+ if (utf8LineEnds && UTF8IsTrailByte(chAfter)) {
+ breakingUTF8LineEnd = UTF8LineEndOverlaps(position);
+ }
+
substance.InsertFromArray(position, s, 0, insertLength);
style.InsertValue(position, insertLength, 0);
@@ -513,14 +574,17 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength bool atLineStart = lv.LineStart(lineInsert-1) == position;
// Point all the lines after the insertion point further along in the buffer
lv.InsertText(lineInsert-1, insertLength);
- char chPrev = substance.ValueAt(position - 1);
- char chAfter = substance.ValueAt(position + insertLength);
+ unsigned char chBeforePrev = substance.ValueAt(position - 2);
+ unsigned char chPrev = substance.ValueAt(position - 1);
if (chPrev == '\r' && chAfter == '\n') {
// Splitting up a crlf pair at position
InsertLine(lineInsert, position, false);
lineInsert++;
}
- char ch = ' ';
+ if (breakingUTF8LineEnd) {
+ RemoveLine(lineInsert);
+ }
+ unsigned char ch = ' ';
for (int i = 0; i < insertLength; i++) {
ch = s[i];
if (ch == '\r') {
@@ -534,7 +598,14 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength InsertLine(lineInsert, (position + i) + 1, atLineStart);
lineInsert++;
}
+ } else if (utf8LineEnds) {
+ unsigned char back3[3] = {chBeforePrev, chPrev, ch};
+ if (UTF8IsSeparator(back3) || UTF8IsNEL(back3+1)) {
+ InsertLine(lineInsert, (position + i) + 1, atLineStart);
+ lineInsert++;
+ }
}
+ chBeforePrev = chPrev;
chPrev = ch;
}
// Joining two lines where last insertion is cr and following substance starts with lf
@@ -543,6 +614,22 @@ void CellBuffer::BasicInsertString(int position, const char *s, int insertLength // End of line already in buffer so drop the newly created one
RemoveLine(lineInsert - 1);
}
+ } else if (utf8LineEnds && !UTF8IsAscii(chAfter)) {
+ // May have end of UTF-8 line end in buffer and start in insertion
+ for (int j = 0; j < UTF8SeparatorLength-1; j++) {
+ unsigned char chAt = substance.ValueAt(position + insertLength + j);
+ unsigned char back3[3] = {chBeforePrev, chPrev, chAt};
+ if (UTF8IsSeparator(back3)) {
+ InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart);
+ lineInsert++;
+ }
+ if ((j == 0) && UTF8IsNEL(back3+1)) {
+ InsertLine(lineInsert, (position + insertLength + j) + 1, atLineStart);
+ lineInsert++;
+ }
+ chBeforePrev = chPrev;
+ chPrev = chAt;
+ }
}
}
@@ -560,9 +647,9 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) { int lineRemove = lv.LineFromPosition(position) + 1;
lv.InsertText(lineRemove-1, - (deleteLength));
- char chPrev = substance.ValueAt(position - 1);
- char chBefore = chPrev;
- char chNext = substance.ValueAt(position);
+ unsigned char chPrev = substance.ValueAt(position - 1);
+ unsigned char chBefore = chPrev;
+ unsigned char chNext = substance.ValueAt(position);
bool ignoreNL = false;
if (chPrev == '\r' && chNext == '\n') {
// Move back one
@@ -570,8 +657,13 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) { lineRemove++;
ignoreNL = true; // First \n is not real deletion
}
+ if (utf8LineEnds && UTF8IsTrailByte(chNext)) {
+ if (UTF8LineEndOverlaps(position)) {
+ RemoveLine(lineRemove);
+ }
+ }
- char ch = chNext;
+ unsigned char ch = chNext;
for (int i = 0; i < deleteLength; i++) {
chNext = substance.ValueAt(position + i + 1);
if (ch == '\r') {
@@ -584,6 +676,14 @@ void CellBuffer::BasicDeleteChars(int position, int deleteLength) { } else {
RemoveLine(lineRemove);
}
+ } else if (utf8LineEnds) {
+ if (!UTF8IsAscii(ch)) {
+ unsigned char next3[3] = {ch, chNext,
+ static_cast<unsigned char>(substance.ValueAt(position + i + 2))};
+ if (UTF8IsSeparator(next3) || UTF8IsNEL(next3)) {
+ RemoveLine(lineRemove);
+ }
+ }
}
ch = chNext;
diff --git a/scintilla/src/CellBuffer.h b/scintilla/src/CellBuffer.h index 29743af..86b94cb 100644 --- a/scintilla/src/CellBuffer.h +++ b/scintilla/src/CellBuffer.h @@ -98,6 +98,9 @@ class UndoHistory { void EnsureUndoRoom();
+ // Private so UndoHistory objects can not be copied
+ UndoHistory(const UndoHistory &);
+
public:
UndoHistory();
~UndoHistory();
@@ -136,12 +139,15 @@ private: SplitVector<char> substance;
SplitVector<char> style;
bool readOnly;
+ int utf8LineEnds;
bool collectingUndo;
UndoHistory uh;
LineVector lv;
+ bool UTF8LineEndOverlaps(int position) const;
+ void ResetLineEnds();
/// Actions without undo
void BasicInsertString(int position, const char *s, int insertLength);
void BasicDeleteChars(int position, int deleteLength);
@@ -162,6 +168,8 @@ public: int Length() const;
void Allocate(int newSize);
+ int GetLineEndTypes() const { return utf8LineEnds; }
+ void SetLineEndTypes(int utf8LineEnds_);
void SetPerLine(PerLine *pl);
int Lines() const;
int LineStart(int line) const;
diff --git a/scintilla/src/ContractionState.cxx b/scintilla/src/ContractionState.cxx index 3b77beb..938e16f 100644 --- a/scintilla/src/ContractionState.cxx +++ b/scintilla/src/ContractionState.cxx @@ -66,7 +66,7 @@ int ContractionState::LinesDisplayed() const { int ContractionState::DisplayFromDoc(int lineDoc) const {
if (OneToOne()) {
- return lineDoc;
+ return (lineDoc <= linesInDocument) ? lineDoc : linesInDocument;
} else {
if (lineDoc > displayLines->Partitions())
lineDoc = displayLines->Partitions();
diff --git a/scintilla/src/Document.cxx b/scintilla/src/Document.cxx index 205de27..38b931c 100644 --- a/scintilla/src/Document.cxx +++ b/scintilla/src/Document.cxx @@ -67,6 +67,17 @@ void LexInterface::Colourise(int start, int end) { }
}
+int LexInterface::LineEndTypesSupported() {
+ if (instance) {
+ int interfaceVersion = instance->Version();
+ if (interfaceVersion >= lvSubStyles) {
+ ILexerWithSubStyles *ssinstance = static_cast<ILexerWithSubStyles *>(instance);
+ return ssinstance->LineEndTypesSupported();
+ }
+ }
+ return 0;
+}
+
Document::Document() {
refCount = 0;
pcf = NULL;
@@ -76,6 +87,7 @@ Document::Document() { eolMode = SC_EOL_LF;
#endif
dbcsCodePage = 0;
+ lineEndBitSet = SC_LINE_END_TYPE_DEFAULT;
stylingBits = 5;
stylingBitsMask = 0x1F;
stylingMask = 0;
@@ -135,16 +147,40 @@ void Document::Init() { }
}
+int Document::LineEndTypesSupported() const {
+ if ((SC_CP_UTF8 == dbcsCodePage) && pli)
+ return pli->LineEndTypesSupported();
+ else
+ return 0;
+}
+
bool Document::SetDBCSCodePage(int dbcsCodePage_) {
if (dbcsCodePage != dbcsCodePage_) {
dbcsCodePage = dbcsCodePage_;
SetCaseFolder(NULL);
+ cb.SetLineEndTypes(lineEndBitSet & LineEndTypesSupported());
return true;
} else {
return false;
}
}
+bool Document::SetLineEndTypesAllowed(int lineEndBitSet_) {
+ if (lineEndBitSet != lineEndBitSet_) {
+ lineEndBitSet = lineEndBitSet_;
+ int lineEndBitSetActive = lineEndBitSet & LineEndTypesSupported();
+ if (lineEndBitSetActive != cb.GetLineEndTypes()) {
+ ModifiedAt(0);
+ cb.SetLineEndTypes(lineEndBitSetActive);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
void Document::InsertLine(int line) {
for (int j=0; j<ldSize; j++) {
if (perLineData[j])
@@ -245,11 +281,25 @@ int SCI_METHOD Document::LineStart(int line) const { return cb.LineStart(line);
}
-int Document::LineEnd(int line) const {
+int SCI_METHOD Document::LineEnd(int line) const {
if (line == LinesTotal() - 1) {
return LineStart(line + 1);
} else {
- int position = LineStart(line + 1) - 1;
+ int position = LineStart(line + 1);
+ if (SC_CP_UTF8 == dbcsCodePage) {
+ unsigned char bytes[] = {
+ static_cast<unsigned char>(cb.CharAt(position-3)),
+ static_cast<unsigned char>(cb.CharAt(position-2)),
+ static_cast<unsigned char>(cb.CharAt(position-1)),
+ };
+ if (UTF8IsSeparator(bytes)) {
+ return position - UTF8SeparatorLength;
+ }
+ if (UTF8IsNEL(bytes+1)) {
+ return position - UTF8NELLength;
+ }
+ }
+ position--; // Back over CR or LF
// When line terminator is CR+LF, may need to go back one more
if ((position > LineStart(line)) && (cb.CharAt(position - 1) == '\r')) {
position--;
@@ -277,6 +327,10 @@ bool Document::IsLineEndPosition(int position) const { return LineEnd(LineFromPosition(position)) == position;
}
+bool Document::IsPositionInLineEnd(int position) const {
+ return position >= LineEnd(LineFromPosition(position));
+}
+
int Document::VCHomePosition(int position) const {
int line = LineFromPosition(position);
int startPosition = LineStart(line);
diff --git a/scintilla/src/Document.h b/scintilla/src/Document.h index 1125c8a..1c6a02a 100644 --- a/scintilla/src/Document.h +++ b/scintilla/src/Document.h @@ -186,6 +186,7 @@ public: virtual ~LexInterface() {
}
void Colourise(int start, int end);
+ int LineEndTypesSupported();
bool UseContainerLexing() const {
return instance == 0;
}
@@ -193,7 +194,7 @@ public: /**
*/
-class Document : PerLine, public IDocument, public ILoader {
+class Document : PerLine, public IDocumentWithLineEnd, public ILoader {
public:
/** Used to pair watcher pointer with user data. */
@@ -240,6 +241,7 @@ public: int eolMode;
/// Can also be SC_CP_UTF8 to enable UTF-8 mode
int dbcsCodePage;
+ int lineEndBitSet;
int tabInChars;
int indentInChars;
int actualIndentInChars;
@@ -256,12 +258,16 @@ public: int SCI_METHOD Release();
virtual void Init();
+ int LineEndTypesSupported() const;
bool SetDBCSCodePage(int dbcsCodePage_);
+ int GetLineEndTypesAllowed() { return cb.GetLineEndTypes(); }
+ bool SetLineEndTypesAllowed(int lineEndBitSet_);
+ int GetLineEndTypesActive() { return cb.GetLineEndTypes(); }
virtual void InsertLine(int line);
virtual void RemoveLine(int line);
int SCI_METHOD Version() const {
- return dvOriginal;
+ return dvLineEnd;
}
void SCI_METHOD SetErrorStatus(int status);
@@ -338,9 +344,10 @@ public: void DeleteAllMarks(int markerNum);
int LineFromHandle(int markerHandle);
int SCI_METHOD LineStart(int line) const;
- int LineEnd(int line) const;
+ int SCI_METHOD LineEnd(int line) const;
int LineEndPosition(int position) const;
bool IsLineEndPosition(int position) const;
+ bool IsPositionInLineEnd(int position) const;
int VCHomePosition(int position) const;
int SCI_METHOD SetLevel(int line, int level);
diff --git a/scintilla/src/Editor.cxx b/scintilla/src/Editor.cxx index ceb2fa7..ff05228 100644 --- a/scintilla/src/Editor.cxx +++ b/scintilla/src/Editor.cxx @@ -9,6 +9,7 @@ #include <string.h>
#include <stdio.h>
#include <ctype.h>
+#include <math.h>
#include <assert.h>
#include <string>
@@ -174,6 +175,7 @@ Editor::Editor() { pixmapLine = 0;
pixmapSelMargin = 0;
pixmapSelPattern = 0;
+ pixmapSelPatternOffset1 = 0;
pixmapIndentGuide = 0;
pixmapIndentGuideHighlight = 0;
@@ -249,6 +251,8 @@ void Editor::DropGraphics(bool freeObjects) { pixmapSelMargin = 0;
delete pixmapSelPattern;
pixmapSelPattern = 0;
+ delete pixmapSelPatternOffset1;
+ pixmapSelPatternOffset1 = 0;
delete pixmapIndentGuide;
pixmapIndentGuide = 0;
delete pixmapIndentGuideHighlight;
@@ -260,6 +264,8 @@ void Editor::DropGraphics(bool freeObjects) { pixmapSelMargin->Release();
if (pixmapSelPattern)
pixmapSelPattern->Release();
+ if (pixmapSelPatternOffset1)
+ pixmapSelPatternOffset1->Release();
if (pixmapIndentGuide)
pixmapIndentGuide->Release();
if (pixmapIndentGuideHighlight)
@@ -274,6 +280,8 @@ void Editor::AllocateGraphics() { pixmapSelMargin = Surface::Allocate(technology);
if (!pixmapSelPattern)
pixmapSelPattern = Surface::Allocate(technology);
+ if (!pixmapSelPatternOffset1)
+ pixmapSelPatternOffset1 = Surface::Allocate(technology);
if (!pixmapIndentGuide)
pixmapIndentGuide = Surface::Allocate(technology);
if (!pixmapIndentGuideHighlight)
@@ -307,13 +315,37 @@ void Editor::RefreshStyleData() { }
}
+Point Editor::GetVisibleOriginInMain() {
+ return Point(0,0);
+}
+
+Point Editor::DocumentPointFromView(Point ptView) {
+ Point ptDocument = ptView;
+ if (wMargin.GetID()) {
+ Point ptOrigin = GetVisibleOriginInMain();
+ ptDocument.x += ptOrigin.x;
+ ptDocument.y += ptOrigin.y;
+ } else {
+ ptDocument.x += xOffset;
+ ptDocument.y += topLine * vs.lineHeight;
+ }
+ return ptDocument;
+}
+
+int Editor::TopLineOfMain() {
+ if (wMargin.GetID())
+ return 0;
+ else
+ return topLine;
+}
+
PRectangle Editor::GetClientRectangle() {
return wMain.GetClientPosition();
}
PRectangle Editor::GetTextRectangle() {
PRectangle rc = GetClientRectangle();
- rc.left += vs.fixedColumnWidth;
+ rc.left += vs.textStart;
rc.right -= vs.rightMarginWidth;
return rc;
}
@@ -436,7 +468,7 @@ Point Editor::LocationFromPosition(SelectionPosition pos) { pt.y += vs.lineHeight;
}
}
- pt.x += vs.fixedColumnWidth - xOffset;
+ pt.x += vs.textStart - xOffset;
}
pt.x += pos.VirtualSpace() * vs.styles[ll->EndLineStyle()].spaceWidth;
return pt;
@@ -448,12 +480,12 @@ Point Editor::LocationFromPosition(int pos) { int Editor::XFromPosition(int pos) {
Point pt = LocationFromPosition(pos);
- return pt.x - vs.fixedColumnWidth + xOffset;
+ return pt.x - vs.textStart + xOffset;
}
int Editor::XFromPosition(SelectionPosition sp) {
Point pt = LocationFromPosition(sp);
- return pt.x - vs.fixedColumnWidth + xOffset;
+ return pt.x - vs.textStart + xOffset;
}
int Editor::LineFromLocation(Point pt) {
@@ -461,7 +493,7 @@ int Editor::LineFromLocation(Point pt) { }
void Editor::SetTopLine(int topLineNew) {
- if (topLine != topLineNew) {
+ if ((topLine != topLineNew) && (topLineNew >= 0)) {
topLine = topLineNew;
ContainerNeedsUpdate(SC_UPDATE_V_SCROLL);
}
@@ -474,16 +506,14 @@ SelectionPosition Editor::SPositionFromLocation(Point pt, bool canReturnInvalid, PRectangle rcClient = GetTextRectangle();
if (!rcClient.Contains(pt))
return SelectionPosition(INVALID_POSITION);
- if (pt.x < vs.fixedColumnWidth)
+ if (pt.x < vs.textStart)
return SelectionPosition(INVALID_POSITION);
if (pt.y < 0)
return SelectionPosition(INVALID_POSITION);
}
- pt.x = pt.x - vs.fixedColumnWidth + xOffset;
- int visibleLine = pt.y / vs.lineHeight + topLine;
- if (pt.y < 0) { // Division rounds towards 0
- visibleLine = (static_cast<int>(pt.y) - (vs.lineHeight - 1)) / vs.lineHeight + topLine;
- }
+ pt = DocumentPointFromView(pt);
+ pt.x = pt.x - vs.textStart;
+ int visibleLine = floor(pt.y / vs.lineHeight);
if (!canReturnInvalid && (visibleLine < 0))
visibleLine = 0;
int lineDoc = cs.DocFromDisplay(visibleLine);
@@ -622,6 +652,8 @@ void Editor::Redraw() { //Platform::DebugPrintf("Redraw all\n");
PRectangle rcClient = GetClientRectangle();
wMain.InvalidateRectangle(rcClient);
+ if (wMargin.GetID())
+ wMargin.InvalidateAll();
//wMain.InvalidateAll();
}
@@ -631,7 +663,7 @@ void Editor::RedrawSelMargin(int line, bool allAfter) { Redraw();
} else {
PRectangle rcSelMargin = GetClientRectangle();
- rcSelMargin.right = vs.fixedColumnWidth;
+ rcSelMargin.right = rcSelMargin.left + vs.fixedColumnWidth;
if (line != -1) {
int position = pdoc->LineStart(line);
PRectangle rcLine = RectangleFromRange(position, position);
@@ -651,7 +683,13 @@ void Editor::RedrawSelMargin(int line, bool allAfter) { if (!allAfter)
rcSelMargin.bottom = rcLine.bottom;
}
- wMain.InvalidateRectangle(rcSelMargin);
+ if (wMargin.GetID()) {
+ Point ptOrigin = GetVisibleOriginInMain();
+ rcSelMargin.Move(-ptOrigin.x, -ptOrigin.y);
+ wMargin.InvalidateRectangle(rcSelMargin);
+ } else {
+ wMain.InvalidateRectangle(rcSelMargin);
+ }
}
}
}
@@ -669,15 +707,12 @@ PRectangle Editor::RectangleFromRange(int start, int end) { PRectangle rcClient = GetTextRectangle();
PRectangle rc;
const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0;
- rc.left = vs.fixedColumnWidth - leftTextOverlap;
- rc.top = (minLine - topLine) * vs.lineHeight;
- if (rc.top < 0)
- rc.top = 0;
+ rc.left = vs.textStart - leftTextOverlap;
+ rc.top = (minLine - TopLineOfMain()) * vs.lineHeight;
+ if (rc.top < rcClient.top)
+ rc.top = rcClient.top;
rc.right = rcClient.right;
- rc.bottom = (maxLine - topLine + 1) * vs.lineHeight;
- // Ensure PRectangle is within 16 bit space
- rc.top = Platform::Clamp(rc.top, -32000, 32000);
- rc.bottom = Platform::Clamp(rc.bottom, -32000, 32000);
+ rc.bottom = (maxLine - TopLineOfMain() + 1) * vs.lineHeight;
return rc;
}
@@ -782,6 +817,7 @@ void Editor::SetSelection(SelectionPosition currentPos_, SelectionPosition ancho if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
+ QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetSelection(int currentPos_, int anchor_) {
@@ -808,6 +844,7 @@ void Editor::SetSelection(SelectionPosition currentPos_) { if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
+ QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetSelection(int currentPos_) {
@@ -828,6 +865,7 @@ void Editor::SetEmptySelection(SelectionPosition currentPos_) { if (highlightDelimiter.NeedsDrawing(currentLine)) {
RedrawSelMargin();
}
+ QueueIdleWork(WorkNeeded::workUpdateUI);
}
void Editor::SetEmptySelection(int currentPos_) {
@@ -924,7 +962,8 @@ int Editor::MovePositionTo(SelectionPosition newPos, Selection::selTypes selt, b // In case in need of wrapping to ensure DisplayFromDoc works.
if (currentLine >= wrapStart)
WrapLines(true, -1);
- XYScrollPosition newXY = XYScrollToMakeVisible(true, true, true);
+ XYScrollPosition newXY = XYScrollToMakeVisible(
+ SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret), xysDefault);
if (simpleCaret && (newXY.xOffset == xOffset)) {
// simple vertical scroll then invalidate
ScrollTo(newXY.topLine);
@@ -1195,17 +1234,22 @@ slop | strict | jumps | even | Caret can go to the margin | When 1 | 1 | 1 | 1 | No, kept out of UZ | moved to put caret at 3UZ of the margin
*/
-Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz) {
+Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const SelectionRange range, const XYScrollOptions options) {
PRectangle rcClient = GetTextRectangle();
- const SelectionPosition posCaret = posDrag.IsValid() ? posDrag : sel.RangeMain().caret;
- const Point pt = LocationFromPosition(posCaret);
+ Point pt = LocationFromPosition(range.caret);
+ Point ptAnchor = LocationFromPosition(range.anchor);
+ const Point ptOrigin = GetVisibleOriginInMain();
+ pt.x += ptOrigin.x;
+ pt.y += ptOrigin.y;
+ ptAnchor.x += ptOrigin.x;
+ ptAnchor.y += ptOrigin.y;
const Point ptBottomCaret(pt.x, pt.y + vs.lineHeight - 1);
- const int lineCaret = DisplayFromPosition(posCaret.Position());
XYScrollPosition newXY(xOffset, topLine);
// Vertical positioning
- if (vert && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
+ if ((options & xysVertical) && (pt.y < rcClient.top || ptBottomCaret.y >= rcClient.bottom || (caretYPolicy & CARET_STRICT) != 0)) {
+ const int lineCaret = DisplayFromPosition(range.caret.Position());
const int linesOnScreen = LinesOnScreen();
const int halfScreen = Platform::Maximum(linesOnScreen - 1, 2) / 2;
const bool bSlop = (caretYPolicy & CARET_SLOP) != 0;
@@ -1219,7 +1263,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con int yMoveT, yMoveB;
if (bStrict) {
int yMarginT, yMarginB;
- if (!useMargin) {
+ if (!(options & xysUseMargin)) {
// In drag mode, avoid moves
// otherwise, a double click will select several lines.
yMarginT = yMarginB = 0;
@@ -1289,11 +1333,23 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con }
}
}
+ if (!(range.caret == range.anchor)) {
+ const int lineAnchor = DisplayFromPosition(range.anchor.Position());
+ if (lineAnchor < lineCaret) {
+ // Shift up to show anchor or as much of range as possible
+ newXY.topLine = std::min(newXY.topLine, lineAnchor);
+ newXY.topLine = std::max(newXY.topLine, lineCaret - LinesOnScreen());
+ } else {
+ // Shift down to show anchor or as much of range as possible
+ newXY.topLine = std::max(newXY.topLine, lineAnchor - LinesOnScreen());
+ newXY.topLine = std::min(newXY.topLine, lineCaret);
+ }
+ }
newXY.topLine = Platform::Clamp(newXY.topLine, 0, MaxScrollPos());
}
// Horizontal positioning
- if (horiz && (wrapState == eWrapNone)) {
+ if ((options & xysHorizontal) && (wrapState == eWrapNone)) {
const int halfScreen = Platform::Maximum(rcClient.Width() - 4, 4) / 2;
const bool bSlop = (caretXPolicy & CARET_SLOP) != 0;
const bool bStrict = (caretXPolicy & CARET_STRICT) != 0;
@@ -1304,7 +1360,7 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con int xMoveL, xMoveR;
if (bStrict) {
int xMarginL, xMarginR;
- if (!useMargin) {
+ if (!(options & xysUseMargin)) {
// In drag mode, avoid moves unless very near of the margin
// otherwise, a simple click will select text.
xMarginL = xMarginR = 2;
@@ -1393,6 +1449,21 @@ Editor::XYScrollPosition Editor::XYScrollToMakeVisible(const bool useMargin, con newXY.xOffset += static_cast<int>(vs.aveCharWidth);
}
}
+ if (!(range.caret == range.anchor)) {
+ if (ptAnchor.x < pt.x) {
+ // Shift to left to show anchor or as much of range as possible
+ int maxOffset = ptAnchor.x + xOffset - rcClient.left - 1;
+ int minOffset = pt.x + xOffset - rcClient.right + 1;
+ newXY.xOffset = std::min(newXY.xOffset, maxOffset);
+ newXY.xOffset = std::max(newXY.xOffset, minOffset);
+ } else {
+ // Shift to right to show anchor or as much of range as possible
+ int minOffset = ptAnchor.x + xOffset - rcClient.right + 1;
+ int maxOffset = pt.x + xOffset - rcClient.left - 1;
+ newXY.xOffset = std::max(newXY.xOffset, minOffset);
+ newXY.xOffset = std::min(newXY.xOffset, maxOffset);
+ }
+ }
if (newXY.xOffset < 0) {
newXY.xOffset = 0;
}
@@ -1425,8 +1496,13 @@ void Editor::SetXYScroll(XYScrollPosition newXY) { }
}
+void Editor::ScrollRange(SelectionRange range) {
+ SetXYScroll(XYScrollToMakeVisible(range, xysDefault));
+}
+
void Editor::EnsureCaretVisible(bool useMargin, bool vert, bool horiz) {
- SetXYScroll(XYScrollToMakeVisible(useMargin, vert, horiz));
+ SetXYScroll(XYScrollToMakeVisible(SelectionRange(posDrag.IsValid() ? posDrag : sel.RangeMain().caret),
+ static_cast<XYScrollOptions>((useMargin?xysUseMargin:0)|(vert?xysVertical:0)|(horiz?xysHorizontal:0))));
}
void Editor::ShowCaretAtCurrentPosition() {
@@ -1542,8 +1618,8 @@ bool Editor::WrapLines(bool fullWrap, int priorityWrapLineStart) { int lineDocTop = cs.DocFromDisplay(topLine);
int subLineTop = topLine - cs.DisplayFromDoc(lineDocTop);
PRectangle rcTextArea = GetClientRectangle();
- rcTextArea.left = vs.fixedColumnWidth;
- rcTextArea.right -= vs.rightMarginWidth;
+ rcTextArea.left = vs.textStart;
+ rcTextArea.right -= vs.textStart;
wrapWidth = rcTextArea.Width();
RefreshStyleData();
AutoSurface surface(this);
@@ -1606,7 +1682,7 @@ void Editor::LinesJoin() { UndoGroup ug(pdoc);
bool prevNonWS = true;
for (int pos = targetStart; pos < targetEnd; pos++) {
- if (IsEOLChar(pdoc->CharAt(pos))) {
+ if (pdoc->IsPositionInLineEnd(pos)) {
targetEnd -= pdoc->LenChar(pos);
pdoc->DelChar(pos);
if (prevNonWS) {
@@ -1753,7 +1829,12 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { if (vs.fixedColumnWidth == 0)
return;
+ RefreshPixMaps(surfWindow);
+
PRectangle rcMargin = GetClientRectangle();
+ Point ptOrigin = GetVisibleOriginInMain();
+ rcMargin.Move(0, -ptOrigin.y);
+ rcMargin.left = 0;
rcMargin.right = vs.fixedColumnWidth;
if (!rc.Intersects(rcMargin))
@@ -1774,18 +1855,24 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { PRectangle rcSelMargin = rcMargin;
rcSelMargin.right = rcMargin.left;
+ if (rcSelMargin.bottom < rc.bottom)
+ rcSelMargin.bottom = rc.bottom;
- for (int margin = 0; margin < vs.margins; margin++) {
+ for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if (vs.ms[margin].width > 0) {
rcSelMargin.left = rcSelMargin.right;
rcSelMargin.right = rcSelMargin.left + vs.ms[margin].width;
if (vs.ms[margin].style != SC_MARGIN_NUMBER) {
- if (vs.ms[margin].mask & SC_MASK_FOLDERS)
+ if (vs.ms[margin].mask & SC_MASK_FOLDERS) {
// Required because of special way brush is created for selection margin
- surface->FillRectangle(rcSelMargin, *pixmapSelPattern);
- else {
+ // Ensure patterns line up when scrolling with separate margin view
+ // by choosing correctly aligned variant.
+ bool invertPhase = static_cast<int>(ptOrigin.y) & 1;
+ surface->FillRectangle(rcSelMargin,
+ invertPhase ? *pixmapSelPattern : *pixmapSelPatternOffset1);
+ } else {
ColourDesired colour;
switch (vs.ms[margin].style) {
case SC_MARGIN_BACK:
@@ -1804,9 +1891,9 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { surface->FillRectangle(rcSelMargin, vs.styles[STYLE_LINENUMBER].back);
}
- const int lineStartPaint = rcMargin.top / vs.lineHeight;
- int visibleLine = topLine + lineStartPaint;
- int yposScreen = lineStartPaint * vs.lineHeight;
+ const int lineStartPaint = (rcMargin.top + ptOrigin.y) / vs.lineHeight;
+ int visibleLine = TopLineOfMain() + lineStartPaint;
+ int yposScreen = lineStartPaint * vs.lineHeight - ptOrigin.y;
// Work out whether the top line is whitespace located after a
// lessening of fold level which implies a 'fold tail' but which should not
// be displayed until the last of a sequence of whitespace.
@@ -1837,7 +1924,7 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { int folderEnd = SubstituteMarkerIfEmpty(SC_MARKNUM_FOLDEREND,
SC_MARKNUM_FOLDER);
- while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rcMargin.bottom) {
+ while ((visibleLine < cs.LinesDisplayed()) && yposScreen < rc.bottom) {
PLATFORM_ASSERT(visibleLine < cs.LinesDisplayed());
int lineDoc = cs.DocFromDisplay(visibleLine);
@@ -1947,8 +2034,9 @@ void Editor::PaintSelMargin(Surface *surfWindow, PRectangle &rc) { rcMarker.bottom = yposScreen + vs.lineHeight;
if (vs.ms[margin].style == SC_MARGIN_NUMBER) {
if (firstSubLine) {
- char number[100];
- sprintf(number, "%d", lineDoc + 1);
+ char number[100] = "";
+ if (lineDoc >= 0)
+ sprintf(number, "%d", lineDoc + 1);
if (foldFlags & SC_FOLDFLAG_LEVELNUMBERS) {
int lev = pdoc->GetLevel(lineDoc);
sprintf(number, "%c%c %03X %03X",
@@ -2193,7 +2281,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou bool isBadUTF = isBadUTFNext;
isBadUTFNext = IsUnicodeMode() && BadUTF(ll->chars + charInLine + 1, numCharsInLine - charInLine - 1, trailBytes);
if ((ll->styles[charInLine] != ll->styles[charInLine + 1]) ||
- isControl || isControlNext || isBadUTF || isBadUTFNext) {
+ isControl || isControlNext || isBadUTF || isBadUTFNext || ((charInLine+1) >= numCharsBeforeEOL)) {
ll->positions[startseg] = 0;
if (vstyle.styles[ll->styles[charInLine]].visible) {
if (isControl) {
@@ -2213,7 +2301,7 @@ void Editor::LayoutLine(int line, Surface *surface, ViewStyle &vstyle, LineLayou ll->positions + startseg + 1);
}
lastSegItalics = false;
- } else if (isBadUTF) {
+ } else if ((isBadUTF) || (charInLine >= numCharsBeforeEOL)) {
char hexits[4];
sprintf(hexits, "x%2X", ll->chars[charInLine] & 0xff);
ll->positions[charInLine + 1] =
@@ -2504,7 +2592,15 @@ void Editor::DrawEOL(Surface *surface, ViewStyle &vsDraw, PRectangle rcLine, Lin 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]);
+ char hexits[4];
+ const char *ctrlChar;
+ unsigned char chEOL = ll->chars[eolPos];
+ if (UTF8IsAscii(chEOL)) {
+ ctrlChar = ControlCharacterString(chEOL);
+ } else {
+ sprintf(hexits, "x%2X", chEOL);
+ ctrlChar = hexits;
+ }
int styleMain = ll->styles[eolPos];
ColourDesired textBack = TextBackground(vsDraw, overrideBackground, background, eolInSelection, false, styleMain, eolPos, ll);
ColourDesired textFore = vsDraw.styles[styleMain].fore;
@@ -2989,12 +3085,6 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis textBack = vsDraw.whitespaceBackground;
surface->FillRectangle(rcSegment, textBack);
}
- if ((vsDraw.viewWhitespace != wsInvisible) ||
- (inIndentation && vsDraw.viewIndentationGuides != ivNone)) {
- if (vsDraw.whitespaceForegroundSet)
- textFore = vsDraw.whitespaceForeground;
- surface->PenColour(textFore);
- }
if (inIndentation && vsDraw.viewIndentationGuides == ivReal) {
for (int indentCount = (ll->positions[i] + epsilon) / indentWidth;
indentCount <= (ll->positions[i + 1] - epsilon) / indentWidth;
@@ -3008,6 +3098,9 @@ void Editor::DrawLine(Surface *surface, ViewStyle &vsDraw, int line, int lineVis }
if (vsDraw.viewWhitespace != wsInvisible) {
if (!inIndentation || vsDraw.viewWhitespace == wsVisibleAlways) {
+ if (vsDraw.whitespaceForegroundSet)
+ textFore = vsDraw.whitespaceForeground;
+ surface->PenColour(textFore);
PRectangle rcTab(rcSegment.left + 1, rcSegment.top + 4,
rcSegment.right - 1, rcSegment.bottom - vsDraw.maxDescent);
DrawTabArrow(surface, rcTab, rcSegment.top + vsDraw.lineHeight / 2);
@@ -3289,6 +3382,7 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { if (!pixmapSelPattern->Initialised()) {
const int patternSize = 8;
pixmapSelPattern->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
+ pixmapSelPatternOffset1->InitPixMap(patternSize, patternSize, surfaceWindow, wMain.GetID());
// This complex procedure is to reproduce the checkerboard dithered pattern used by windows
// for scroll bars and Visual Studio for its selection margin. The colour of this pattern is half
// way between the chrome colour and the chrome highlight colour making a nice transition
@@ -3315,10 +3409,12 @@ void Editor::RefreshPixMaps(Surface *surfaceWindow) { }
pixmapSelPattern->FillRectangle(rcPattern, colourFMFill);
+ pixmapSelPatternOffset1->FillRectangle(rcPattern, colourFMStripes);
for (int y = 0; y < patternSize; y++) {
for (int x = y % 2; x < patternSize; x+=2) {
PRectangle rcPixel(x, y, x+1, y+1);
pixmapSelPattern->FillRectangle(rcPixel, colourFMStripes);
+ pixmapSelPatternOffset1->FillRectangle(rcPixel, colourFMFill);
}
}
}
@@ -3446,22 +3542,20 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { StyleToPositionInView(PositionAfterArea(rcArea));
PRectangle rcClient = GetClientRectangle();
+ Point ptOrigin = GetVisibleOriginInMain();
//Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
// rcClient.left, rcClient.top, rcClient.right, rcClient.bottom);
int screenLinePaintFirst = rcArea.top / vs.lineHeight;
- int xStart = vs.fixedColumnWidth - xOffset;
+ int xStart = vs.textStart - xOffset + ptOrigin.x;
int ypos = 0;
if (!bufferedDraw)
ypos += screenLinePaintFirst * vs.lineHeight;
int yposScreen = screenLinePaintFirst * vs.lineHeight;
bool paintAbandonedByStyling = paintState == paintAbandoned;
- if (needUpdateUI) {
- NotifyUpdateUI();
- needUpdateUI = 0;
-
+ if (NotifyUpdateUI()) {
RefreshStyleData();
RefreshPixMaps(surfaceWindow);
}
@@ -3486,12 +3580,20 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { surfaceWindow->SetClip(rcArea);
if (paintState != paintAbandoned) {
- PaintSelMargin(surfaceWindow, rcArea);
-
- PRectangle rcRightMargin = rcClient;
- rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
- if (rcArea.Intersects(rcRightMargin)) {
- surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back);
+ if (vs.marginInside) {
+ PaintSelMargin(surfaceWindow, rcArea);
+ PRectangle rcRightMargin = rcClient;
+ rcRightMargin.left = rcRightMargin.right - vs.rightMarginWidth;
+ if (rcArea.Intersects(rcRightMargin)) {
+ surfaceWindow->FillRectangle(rcRightMargin, vs.styles[STYLE_DEFAULT].back);
+ }
+ } else { // Else separate view so separate paint event but leftMargin included to allow overlap
+ PRectangle rcLeftMargin = rcArea;
+ rcLeftMargin.left = 0;
+ rcLeftMargin.right = rcLeftMargin.left + vs.leftMarginWidth;
+ if (rcArea.Intersects(rcLeftMargin)) {
+ surfaceWindow->FillRectangle(rcLeftMargin, vs.styles[STYLE_DEFAULT].back);
+ }
}
}
@@ -3515,7 +3617,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { const int leftTextOverlap = ((xOffset == 0) && (vs.leftMarginWidth > 0)) ? 1 : 0;
// Do the painting
- if (rcArea.right > vs.fixedColumnWidth - leftTextOverlap) {
+ if (rcArea.right > vs.textStart - leftTextOverlap) {
Surface *surface = surfaceWindow;
if (bufferedDraw) {
@@ -3525,7 +3627,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { surface->SetUnicodeMode(IsUnicodeMode());
surface->SetDBCSMode(CodePage());
- int visibleLine = topLine + screenLinePaintFirst;
+ int visibleLine = TopLineOfMain() + screenLinePaintFirst;
SelectionPosition posCaret = sel.RangeMain().caret;
if (posDrag.IsValid())
@@ -3533,12 +3635,16 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { int lineCaret = pdoc->LineFromPosition(posCaret.Position());
PRectangle rcTextArea = rcClient;
- rcTextArea.left = vs.fixedColumnWidth;
- rcTextArea.right -= vs.rightMarginWidth;
+ if (vs.marginInside) {
+ rcTextArea.left += vs.textStart;
+ rcTextArea.right -= vs.rightMarginWidth;
+ } else {
+ rcTextArea = rcArea;
+ }
// Remove selection margin from drawing area so text will not be drawn
// on it in unbuffered mode.
- if (!bufferedDraw) {
+ if (!bufferedDraw && vs.marginInside) {
PRectangle rcClipText = rcTextArea;
rcClipText.left -= leftTextOverlap;
surfaceWindow->SetClip(rcClipText);
@@ -3632,8 +3738,8 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { DrawCarets(surface, vs, lineDoc, xStart, rcLine, ll, subLine);
if (bufferedDraw) {
- Point from(vs.fixedColumnWidth-leftTextOverlap, 0);
- PRectangle rcCopyArea(vs.fixedColumnWidth-leftTextOverlap, yposScreen,
+ Point from(vs.textStart-leftTextOverlap, 0);
+ PRectangle rcCopyArea(vs.textStart-leftTextOverlap, yposScreen,
rcClient.right - vs.rightMarginWidth, yposScreen + vs.lineHeight);
surfaceWindow->Copy(rcCopyArea, from, *pixmapLine);
}
@@ -3657,10 +3763,10 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) { // durPaint = 0.00000001;
// Right column limit indicator
- PRectangle rcBeyondEOF = rcClient;
- rcBeyondEOF.left = vs.fixedColumnWidth;
- rcBeyondEOF.right = rcBeyondEOF.right - vs.rightMarginWidth;
- rcBeyondEOF.top = (cs.LinesDisplayed() - topLine) * vs.lineHeight;
+ PRectangle rcBeyondEOF = (vs.marginInside) ? rcClient : rcArea;
+ rcBeyondEOF.left = vs.textStart;
+ rcBeyondEOF.right = rcBeyondEOF.right - ((vs.marginInside) ? vs.rightMarginWidth : 0);
+ rcBeyondEOF.top = (cs.LinesDisplayed() - TopLineOfMain()) * vs.lineHeight;
if (rcBeyondEOF.top < rcBeyondEOF.bottom) {
surfaceWindow->FillRectangle(rcBeyondEOF, vs.styles[STYLE_DEFAULT].back);
if (vs.edgeState == EDGE_LINE) {
@@ -3718,7 +3824,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { // Modify the view style for printing as do not normally want any of the transient features to be printed
// Printing supports only the line number margin.
int lineNumberIndex = -1;
- for (int margin = 0; margin < ViewStyle::margins; margin++) {
+ for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((vsPrint.ms[margin].style == SC_MARGIN_NUMBER) && (vsPrint.ms[margin].width > 0)) {
lineNumberIndex = margin;
} else {
@@ -3814,7 +3920,7 @@ long Editor::FormatRange(bool draw, Sci_RangeToFormat *pfr) { // Copy this line and its styles from the document into local arrays
// and determine the x position at which each character starts.
- LineLayout ll(8000);
+ LineLayout ll(pdoc->LineStart(lineDoc+1)-pdoc->LineStart(lineDoc)+1);
LayoutLine(lineDoc, surfaceMeasure, vsPrint, &ll, widthPrint);
ll.containsCaret = false;
@@ -3930,7 +4036,7 @@ void Editor::ChangeSize() { SetScrollBars();
if (wrapState != eWrapNone) {
PRectangle rcTextArea = GetClientRectangle();
- rcTextArea.left = vs.fixedColumnWidth;
+ rcTextArea.left = vs.textStart;
rcTextArea.right -= vs.rightMarginWidth;
if (wrapWidth != rcTextArea.Width()) {
NeedWrapping();
@@ -3995,7 +4101,7 @@ void Editor::AddCharUTF(char *s, unsigned int len, bool treatAsDBCS) { }
} else if (inOverstrike) {
if (positionInsert < pdoc->Length()) {
- if (!IsEOLChar(pdoc->CharAt(positionInsert))) {
+ if (!pdoc->IsPositionInLineEnd(positionInsert)) {
pdoc->DelChar(positionInsert);
currentSel->ClearVirtualSpace();
}
@@ -4240,7 +4346,7 @@ void Editor::Clear() { 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()))) {
+ if ((sel.Count() == 1) || !pdoc->IsPositionInLineEnd(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
@@ -4418,11 +4524,16 @@ void Editor::NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool NotifyParent(scn);
}
-void Editor::NotifyUpdateUI() {
- SCNotification scn = {0};
- scn.nmhdr.code = SCN_UPDATEUI;
- scn.updated = needUpdateUI;
- NotifyParent(scn);
+bool Editor::NotifyUpdateUI() {
+ if (needUpdateUI) {
+ SCNotification scn = {0};
+ scn.nmhdr.code = SCN_UPDATEUI;
+ scn.updated = needUpdateUI;
+ NotifyParent(scn);
+ needUpdateUI = 0;
+ return true;
+ }
+ return false;
}
void Editor::NotifyPainted() {
@@ -4445,8 +4556,8 @@ void Editor::NotifyIndicatorClick(bool click, int position, bool shift, bool ctr bool Editor::NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt) {
int marginClicked = -1;
- int x = 0;
- for (int margin = 0; margin < ViewStyle::margins; margin++) {
+ int x = vs.textStart - vs.fixedColumnWidth;
+ for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width))
marginClicked = margin;
x += vs.ms[margin].width;
@@ -4630,18 +4741,13 @@ void Editor::NotifyModified(Document *, DocModification mh, void *) { }
}
- //Platform::DebugPrintf("** %x Doc Changed\n", this);
- // TODO: could invalidate from mh.startModification to end of screen
- //InvalidateRange(mh.position, mh.position + mh.length);
if (paintState == notPainting && !CanDeferToLastStep(mh)) {
- QueueStyling(pdoc->Length());
+ QueueIdleWork(WorkNeeded::workStyle, pdoc->Length());
Redraw();
}
} else {
- //Platform::DebugPrintf("** %x Line Changed %d .. %d\n", this,
- // mh.position, mh.position + mh.length);
if (paintState == notPainting && mh.length && !CanEliminate(mh)) {
- QueueStyling(mh.position + mh.length);
+ QueueIdleWork(WorkNeeded::workStyle, mh.position + mh.length);
InvalidateRange(mh.position, mh.position + mh.length);
}
}
@@ -6121,7 +6227,8 @@ bool Editor::PointInSelMargin(Point pt) { // Really means: "Point in a margin"
if (vs.fixedColumnWidth > 0) { // There is a margin
PRectangle rcSelMargin = GetClientRectangle();
- rcSelMargin.right = vs.fixedColumnWidth - vs.leftMarginWidth;
+ rcSelMargin.right = vs.textStart - vs.leftMarginWidth;
+ rcSelMargin.left = vs.textStart - vs.fixedColumnWidth;
return rcSelMargin.Contains(pt);
} else {
return false;
@@ -6130,7 +6237,7 @@ bool Editor::PointInSelMargin(Point pt) { Window::Cursor Editor::GetMarginCursor(Point pt) {
int x = 0;
- for (int margin = 0; margin < ViewStyle::margins; margin++) {
+ for (int margin = 0; margin <= SC_MAX_MARGIN; margin++) {
if ((pt.x >= x) && (pt.x < x + vs.ms[margin].width))
return static_cast<Window::Cursor>(vs.ms[margin].cursor);
x += vs.ms[margin].width;
@@ -6511,6 +6618,8 @@ void Editor::ButtonMove(Point pt) { // Autoscroll
PRectangle rcClient = GetClientRectangle();
+ Point ptOrigin = GetVisibleOriginInMain();
+ rcClient.Move(0, -ptOrigin.y);
int lineMove = DisplayFromPosition(movePos.Position());
if (pt.y > rcClient.bottom) {
ScrollTo(lineMove - LinesOnScreen() + 1);
@@ -6710,7 +6819,7 @@ int Editor::PositionAfterArea(PRectangle rcArea) { // Style to a position within the view. If this causes a change at end of last line then
// affects later lines so style all the viewed text.
void Editor::StyleToPositionInView(Position pos) {
- int endWindow = PositionAfterArea(GetClientRectangle());
+ int endWindow = (vs.marginInside) ? (PositionAfterArea(GetClientRectangle())) : (pdoc->Length());
if (pos > endWindow)
pos = endWindow;
int styleAtEnd = pdoc->StyleAt(pos-1);
@@ -6722,20 +6831,18 @@ void Editor::StyleToPositionInView(Position pos) { }
}
-void Editor::IdleStyling() {
+void Editor::IdleWork() {
// Style the line after the modification as this allows modifications that change just the
// line of the modification to heal instead of propagating to the rest of the window.
- StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(styleNeeded.upTo) + 2));
+ if (workNeeded.items & WorkNeeded::workStyle)
+ StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(workNeeded.upTo) + 2));
- if (needUpdateUI) {
- NotifyUpdateUI();
- needUpdateUI = 0;
- }
- styleNeeded.Reset();
+ NotifyUpdateUI();
+ workNeeded.Reset();
}
-void Editor::QueueStyling(int upTo) {
- styleNeeded.NeedUpTo(upTo);
+void Editor::QueueIdleWork(WorkNeeded::workItems items, int upTo) {
+ workNeeded.Need(items, upTo);
}
bool Editor::PaintContains(PRectangle rc) {
@@ -6747,8 +6854,13 @@ bool Editor::PaintContains(PRectangle rc) { }
bool Editor::PaintContainsMargin() {
+ if (wMargin.GetID()) {
+ // With separate margin view, paint of text view
+ // never contains margin.
+ return false;
+ }
PRectangle rcSelMargin = GetClientRectangle();
- rcSelMargin.right = vs.fixedColumnWidth;
+ rcSelMargin.right = vs.textStart;
return PaintContains(rcSelMargin);
}
@@ -6833,6 +6945,8 @@ void Editor::SetDocPointer(Document *document) { braces[0] = invalidPosition;
braces[1] = invalidPosition;
+ vs.ReleaseAllExtendedStyles();
+
// Reset the contraction state to fully shown.
cs.Clear();
cs.InsertLines(0, pdoc->LinesTotal() - 1);
@@ -6944,12 +7058,17 @@ void Editor::EnsureLineVisible(int lineDoc, bool enforcePolicy) { WrapLines(true, -1);
if (!cs.GetVisible(lineDoc)) {
+ // Back up to find a non-blank line
int lookLine = lineDoc;
int lookLineLevel = pdoc->GetLevel(lookLine);
while ((lookLine > 0) && (lookLineLevel & SC_FOLDLEVELWHITEFLAG)) {
lookLineLevel = pdoc->GetLevel(--lookLine);
}
int lineParent = pdoc->GetFoldParent(lookLine);
+ if (lineParent < 0) {
+ // Backed up to a top level line, so try to find parent of initial line
+ lineParent = pdoc->GetFoldParent(lineDoc);
+ }
if (lineParent >= 0) {
if (lineDoc != lineParent)
EnsureLineVisible(lineParent, enforcePolicy);
@@ -7062,7 +7181,7 @@ void Editor::AddStyledText(char *buffer, int appendLength) { }
static bool ValidMargin(unsigned long wParam) {
- return wParam < ViewStyle::margins;
+ return wParam <= SC_MAX_MARGIN;
}
static char *CharPtrFromSPtr(sptr_t lParam) {
@@ -7420,7 +7539,7 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_LINESCROLL:
ScrollTo(topLine + lParam);
- HorizontalScrollTo(xOffset + wParam * vs.spaceWidth);
+ HorizontalScrollTo(xOffset + static_cast<int>(wParam) * vs.spaceWidth);
return 1;
case SCI_SETXOFFSET:
@@ -7456,7 +7575,8 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { return 0;
} else {
Point pt = LocationFromPosition(lParam);
- return pt.x;
+ // Convert to view-relative
+ return pt.x - vs.textStart + vs.fixedColumnWidth;
}
case SCI_POINTYFROMPOSITION:
@@ -7793,6 +7913,21 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { pdoc->eolMode = wParam;
break;
+ case SCI_SETLINEENDTYPESALLOWED:
+ if (pdoc->SetLineEndTypesAllowed(wParam)) {
+ cs.Clear();
+ cs.InsertLines(0, pdoc->LinesTotal() - 1);
+ SetAnnotationHeights(0, pdoc->LinesTotal());
+ InvalidateStyleRedraw();
+ }
+ break;
+
+ case SCI_GETLINEENDTYPESALLOWED:
+ return pdoc->GetLineEndTypesAllowed();
+
+ case SCI_GETLINEENDTYPESACTIVE:
+ return pdoc->GetLineEndTypesActive();
+
case SCI_STARTSTYLING:
pdoc->StartStyling(wParam, static_cast<char>(lParam));
break;
@@ -8059,6 +8194,8 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { verticalScrollBarVisible = wParam != 0;
SetScrollBars();
ReconfigureScrollBars();
+ if (verticalScrollBarVisible)
+ SetVerticalScrollPos();
}
break;
@@ -8089,6 +8226,9 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_SETCODEPAGE:
if (ValidCodePage(wParam)) {
if (pdoc->SetDBCSCodePage(wParam)) {
+ cs.Clear();
+ cs.InsertLines(0, pdoc->LinesTotal() - 1);
+ SetAnnotationHeights(0, pdoc->LinesTotal());
InvalidateStyleRedraw();
}
}
@@ -8438,6 +8578,10 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { EnsureLineVisible(wParam, true);
break;
+ case SCI_SCROLLRANGE:
+ ScrollRange(SelectionRange(lParam, wParam));
+ break;
+
case SCI_SEARCHANCHOR:
SearchAnchor();
break;
@@ -9152,6 +9296,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) { case SCI_ANNOTATIONGETSTYLEOFFSET:
return vs.annotationStyleOffset;
+ case SCI_RELEASEALLEXTENDEDSTYLES:
+ vs.ReleaseAllExtendedStyles();
+ break;
+
+ case SCI_ALLOCATEEXTENDEDSTYLES:
+ return vs.AllocateExtendedStyles(wParam);
+
case SCI_ADDUNDOACTION:
pdoc->AddUndoAction(wParam, lParam & UNDO_MAY_COALESCE);
break;
diff --git a/scintilla/src/Editor.h b/scintilla/src/Editor.h index 8d300d6..a6f0355 100644 --- a/scintilla/src/Editor.h +++ b/scintilla/src/Editor.h @@ -47,21 +47,30 @@ public: /**
* When platform has a way to generate an event before painting,
- * accumulate needed styling range in StyleNeeded to avoid unnecessary work.
+ * accumulate needed styling range and other work items in
+ * WorkNeeded to avoid unnecessary work inside paint handler
*/
-class StyleNeeded {
+class WorkNeeded {
public:
+ enum workItems {
+ workNone=0,
+ workStyle=1,
+ workUpdateUI=2
+ };
bool active;
+ enum workItems items;
Position upTo;
- StyleNeeded() : active(false), upTo(0) {}
+ WorkNeeded() : active(false), items(workNone), upTo(0) {}
void Reset() {
active = false;
+ items = workNone;
upTo = 0;
}
- void NeedUpTo(Position pos) {
- if (upTo < pos)
+ void Need(workItems items_, Position pos) {
+ if ((items_ & workStyle) && (upTo < pos))
upTo = pos;
+ items = static_cast<workItems>(items | items_);
}
};
@@ -95,6 +104,7 @@ public: characterSet = characterSet_;
rectangular = rectangular_;
lineCopy = lineCopy_;
+ FixSelectionForClipboard();
}
void Copy(const char *s_, int len_, int codePage_, int characterSet_, bool rectangular_, bool lineCopy_) {
delete []s;
@@ -108,10 +118,22 @@ public: characterSet = characterSet_;
rectangular = rectangular_;
lineCopy = lineCopy_;
+ FixSelectionForClipboard();
}
void Copy(const SelectionText &other) {
Copy(other.s, other.len, other.codePage, other.characterSet, other.rectangular, other.lineCopy);
}
+
+private:
+ void FixSelectionForClipboard() {
+ // Replace null characters by spaces.
+ // To avoid that the content of the clipboard is truncated in the paste operation
+ // when the clipboard contains null characters.
+ for (int i = 0; i < len - 1; ++i) {
+ if (s[i] == '\0')
+ s[i] = ' ';
+ }
+ }
};
/**
@@ -126,6 +148,7 @@ protected: // ScintillaBase subclass needs access to much of Editor /** On GTK+, Scintilla is a container widget holding two scroll bars
* whereas on Windows there is just one window with both scroll bars turned on. */
Window wMain; ///< The Scintilla parent window
+ Window wMargin; ///< May be separate when using a scroll view for wMain
/** Style resources may be expensive to allocate so are cached between uses.
* When a style attribute is changed, this cache is flushed. */
@@ -177,6 +200,7 @@ protected: // ScintillaBase subclass needs access to much of Editor Surface *pixmapLine;
Surface *pixmapSelMargin;
Surface *pixmapSelPattern;
+ Surface *pixmapSelPatternOffset1;
Surface *pixmapIndentGuide;
Surface *pixmapIndentGuideHighlight;
@@ -228,7 +252,7 @@ protected: // ScintillaBase subclass needs access to much of Editor PRectangle rcPaint;
bool paintingAllText;
bool willRedrawAll;
- StyleNeeded styleNeeded;
+ WorkNeeded workNeeded;
int modEventMask;
@@ -286,6 +310,11 @@ protected: // ScintillaBase subclass needs access to much of Editor void DropGraphics(bool freeObjects);
void AllocateGraphics();
+ // The top left visible point in main window coordinates. Will be 0,0 except for
+ // scroll views where it will be equivalent to the current scroll position.
+ virtual Point GetVisibleOriginInMain();
+ Point DocumentPointFromView(Point ptView); // Convert a point from view space to document
+ int TopLineOfMain(); // Return the line at Main's y coordinate 0
virtual PRectangle GetClientRectangle();
PRectangle GetTextRectangle();
@@ -352,10 +381,19 @@ protected: // ScintillaBase subclass needs access to much of Editor int xOffset;
int topLine;
XYScrollPosition(int xOffset_, int topLine_) : xOffset(xOffset_), topLine(topLine_) {}
+ bool operator==(const XYScrollPosition &other) const {
+ return (xOffset == other.xOffset) && (topLine == other.topLine);
+ }
};
- XYScrollPosition XYScrollToMakeVisible(const bool useMargin, const bool vert, const bool horiz);
+ enum XYScrollOptions {
+ xysUseMargin=0x1,
+ xysVertical=0x2,
+ xysHorizontal=0x4,
+ xysDefault=xysUseMargin|xysVertical|xysHorizontal};
+ XYScrollPosition XYScrollToMakeVisible(const SelectionRange range, const XYScrollOptions options);
void SetXYScroll(XYScrollPosition newXY);
void EnsureCaretVisible(bool useMargin=true, bool vert=true, bool horiz=true);
+ void ScrollRange(SelectionRange range);
void ShowCaretAtCurrentPosition();
void DropCaret();
void InvalidateCaret();
@@ -439,7 +477,7 @@ protected: // ScintillaBase subclass needs access to much of Editor void NotifyHotSpotClicked(int position, bool shift, bool ctrl, bool alt);
void NotifyHotSpotDoubleClicked(int position, bool shift, bool ctrl, bool alt);
void NotifyHotSpotReleaseClick(int position, bool shift, bool ctrl, bool alt);
- void NotifyUpdateUI();
+ bool NotifyUpdateUI();
void NotifyPainted();
void NotifyIndicatorClick(bool click, int position, bool shift, bool ctrl, bool alt);
bool NotifyMarginClick(Point pt, bool shift, bool ctrl, bool alt);
@@ -518,8 +556,8 @@ protected: // ScintillaBase subclass needs access to much of Editor int PositionAfterArea(PRectangle rcArea);
void StyleToPositionInView(Position pos);
- void IdleStyling();
- virtual void QueueStyling(int upTo);
+ virtual void IdleWork();
+ virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo=0);
virtual bool PaintContains(PRectangle rc);
bool PaintContainsMargin();
diff --git a/scintilla/src/LineMarker.cxx b/scintilla/src/LineMarker.cxx index de88f07..33690ac 100644 --- a/scintilla/src/LineMarker.cxx +++ b/scintilla/src/LineMarker.cxx @@ -6,6 +6,7 @@ // The License.txt file describes the conditions under which this software may be distributed.
#include <string.h>
+#include <math.h>
#include <vector>
#include <map>
@@ -112,8 +113,8 @@ void LineMarker::Draw(Surface *surface, PRectangle &rcWhole, Font &fontForCharac rc.bottom--;
int minDim = Platform::Minimum(rc.Width(), rc.Height());
minDim--; // Ensure does not go beyond edge
- int centreX = (rc.right + rc.left) / 2;
- int centreY = (rc.bottom + rc.top) / 2;
+ int centreX = floor((rc.right + rc.left) / 2.0);
+ int centreY = floor((rc.bottom + rc.top) / 2.0);
int dimOn2 = minDim / 2;
int dimOn4 = minDim / 4;
int blobSize = dimOn2-1;
diff --git a/scintilla/src/PositionCache.h b/scintilla/src/PositionCache.h index 232a097..1b909fd 100644 --- a/scintilla/src/PositionCache.h +++ b/scintilla/src/PositionCache.h @@ -130,6 +130,8 @@ class BreakFinder { int subBreak;
Document *pdoc;
void Insert(int val);
+ // Private so BreakFinder objects can not be copied
+ BreakFinder(const BreakFinder &);
public:
// If a whole run is longer than lengthStartSubdivision then subdivide
// into smaller runs at spaces or punctuation.
@@ -148,6 +150,8 @@ class PositionCache { size_t size;
unsigned int clock;
bool allClear;
+ // Private so PositionCache objects can not be copied
+ PositionCache(const PositionCache &);
public:
PositionCache();
~PositionCache();
diff --git a/scintilla/src/RunStyles.h b/scintilla/src/RunStyles.h index c94ca3c..25f9752 100644 --- a/scintilla/src/RunStyles.h +++ b/scintilla/src/RunStyles.h @@ -23,6 +23,8 @@ private: void RemoveRun(int run);
void RemoveRunIfEmpty(int run);
void RemoveRunIfSameAsPrevious(int run);
+ // Private so RunStyles objects can not be copied
+ RunStyles(const RunStyles &);
public:
RunStyles();
~RunStyles();
diff --git a/scintilla/src/ScintillaBase.cxx b/scintilla/src/ScintillaBase.cxx index 4a88411..c751790 100644 --- a/scintilla/src/ScintillaBase.cxx +++ b/scintilla/src/ScintillaBase.cxx @@ -193,6 +193,13 @@ void ScintillaBase::AutoCompleteDoubleClick(void *p) { sci->AutoCompleteCompleted();
}
+void ScintillaBase::AutoCompleteInsert(Position startPos, int removeLen, const char *text, int textLen) {
+ UndoGroup ug(pdoc);
+ pdoc->DeleteChars(startPos, removeLen);
+ pdoc->InsertString(startPos, text, textLen);
+ SetEmptySelection(startPos + textLen);
+}
+
void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) {
//Platform::DebugPrintf("AutoComplete %s\n", list);
ct.CallTipCancel();
@@ -202,17 +209,11 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) { const char *typeSep = strchr(list, ac.GetTypesep());
int lenInsert = typeSep ?
static_cast<int>(typeSep-list) : static_cast<int>(strlen(list));
- UndoGroup ug(pdoc);
if (ac.ignoreCase) {
- SetEmptySelection(sel.MainCaret() - lenEntered);
- pdoc->DeleteChars(sel.MainCaret(), lenEntered);
- SetEmptySelection(sel.MainCaret());
- pdoc->InsertString(sel.MainCaret(), list, lenInsert);
- SetEmptySelection(sel.MainCaret() + lenInsert);
+ // May need to convert the case before invocation, so remove lenEntered characters
+ AutoCompleteInsert(sel.MainCaret() - lenEntered, lenEntered, list, lenInsert);
} else {
- SetEmptySelection(sel.MainCaret());
- pdoc->InsertString(sel.MainCaret(), list + lenEntered, lenInsert - lenEntered);
- SetEmptySelection(sel.MainCaret() + lenInsert - lenEntered);
+ AutoCompleteInsert(sel.MainCaret(), 0, list + lenEntered, lenInsert - lenEntered);
}
ac.Cancel();
return;
@@ -234,6 +235,11 @@ void ScintillaBase::AutoCompleteStart(int lenEntered, const char *list) { Redraw();
pt = PointMainCaret();
}
+ if (wMargin.GetID()) {
+ Point ptOrigin = GetVisibleOriginInMain();
+ pt.x += ptOrigin.x;
+ pt.y += ptOrigin.y;
+ }
PRectangle rcac;
rcac.left = pt.x - ac.lb->CaretFromEdge();
if (pt.y >= rcPopupBounds.bottom - heightLB && // Wont fit below.
@@ -357,15 +363,7 @@ void ScintillaBase::AutoCompleteCompleted() { endPos = pdoc->ExtendWordSelect(endPos, 1, true);
if (endPos < firstPos)
return;
- UndoGroup ug(pdoc);
- if (endPos != firstPos) {
- pdoc->DeleteChars(firstPos, endPos - firstPos);
- }
- SetEmptySelection(ac.posStart);
- if (item != -1) {
- pdoc->InsertCString(firstPos, selected.c_str());
- SetEmptySelection(firstPos + static_cast<int>(selected.length()));
- }
+ AutoCompleteInsert(firstPos, endPos - firstPos, selected.c_str(), static_cast<int>(selected.length()));
SetLastXChosen();
}
@@ -399,6 +397,11 @@ void ScintillaBase::CallTipShow(Point pt, const char *defn) { if (ct.UseStyleCallTip()) {
ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back);
}
+ if (wMargin.GetID()) {
+ Point ptOrigin = GetVisibleOriginInMain();
+ pt.x += ptOrigin.x;
+ pt.y += ptOrigin.y;
+ }
PRectangle rc = ct.CallTipStart(sel.MainCaret(), pt,
vs.lineHeight,
defn,
@@ -473,6 +476,7 @@ class LexState : public LexInterface { const LexerModule *lexCurrent;
void SetLexerModule(const LexerModule *lex);
PropSetSimple props;
+ int interfaceVersion;
public:
int lexLanguage;
@@ -492,6 +496,15 @@ public: const char *PropGet(const char *key) const;
int PropGetInt(const char *key, int defaultValue=0) const;
int PropGetExpanded(const char *key, char *result) const;
+
+ int LineEndTypesSupported();
+ int AllocateSubStyles(int styleBase, int numberStyles);
+ int SubStylesStart(int styleBase);
+ int SubStylesLength(int styleBase);
+ void FreeSubStyles();
+ void SetIdentifiers(int style, const char *identifiers);
+ int DistanceToSecondaryStyles();
+ const char *GetSubStyleBases();
};
#ifdef SCI_NAMESPACE
@@ -501,6 +514,7 @@ public: LexState::LexState(Document *pdoc_) : LexInterface(pdoc_) {
lexCurrent = 0;
performingStyle = false;
+ interfaceVersion = lvOriginal;
lexLanguage = SCLEX_CONTAINER;
}
@@ -524,9 +538,12 @@ void LexState::SetLexerModule(const LexerModule *lex) { instance->Release();
instance = 0;
}
+ interfaceVersion = lvOriginal;
lexCurrent = lex;
- if (lexCurrent)
+ if (lexCurrent) {
instance = lexCurrent->Create();
+ interfaceVersion = instance->Version();
+ }
pdoc->LexerChanged();
}
}
@@ -631,6 +648,60 @@ int LexState::PropGetExpanded(const char *key, char *result) const { return props.GetExpanded(key, result);
}
+int LexState::LineEndTypesSupported() {
+ if (instance && (interfaceVersion >= lvSubStyles)) {
+ return static_cast<ILexerWithSubStyles *>(instance)->LineEndTypesSupported();
+ }
+ return 0;
+}
+
+int LexState::AllocateSubStyles(int styleBase, int numberStyles) {
+ if (instance && (interfaceVersion >= lvSubStyles)) {
+ return static_cast<ILexerWithSubStyles *>(instance)->AllocateSubStyles(styleBase, numberStyles);
+ }
+ return -1;
+}
+
+int LexState::SubStylesStart(int styleBase) {
+ if (instance && (interfaceVersion >= lvSubStyles)) {
+ return static_cast<ILexerWithSubStyles *>(instance)->SubStylesStart(styleBase);
+ }
+ return -1;
+}
+
+int LexState::SubStylesLength(int styleBase) {
+ if (instance && (interfaceVersion >= lvSubStyles)) {
+ return static_cast<ILexerWithSubStyles *>(instance)->SubStylesLength(styleBase);
+ }
+ return 0;
+}
+
+void LexState::FreeSubStyles() {
+ if (instance && (interfaceVersion >= lvSubStyles)) {
+ static_cast<ILexerWithSubStyles *>(instance)->FreeSubStyles();
+ }
+}
+
+void LexState::SetIdentifiers(int style, const char *identifiers) {
+ if (instance && (interfaceVersion >= lvSubStyles)) {
+ static_cast<ILexerWithSubStyles *>(instance)->SetIdentifiers(style, identifiers);
+ }
+}
+
+int LexState::DistanceToSecondaryStyles() {
+ if (instance && (interfaceVersion >= lvSubStyles)) {
+ return static_cast<ILexerWithSubStyles *>(instance)->DistanceToSecondaryStyles();
+ }
+ return 0;
+}
+
+const char *LexState::GetSubStyleBases() {
+ if (instance && (interfaceVersion >= lvSubStyles)) {
+ return static_cast<ILexerWithSubStyles *>(instance)->GetSubStyleBases();
+ }
+ return "";
+}
+
#endif
void ScintillaBase::NotifyStyleToNeeded(int endStyleNeeded) {
@@ -726,6 +797,13 @@ sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lPara case SCI_AUTOCGETCASEINSENSITIVEBEHAVIOUR:
return ac.ignoreCaseBehaviour;
+ case SCI_AUTOCSETORDER:
+ ac.autoSort = wParam;
+ break;
+
+ case SCI_AUTOCGETORDER:
+ return ac.autoSort;
+
case SCI_USERLISTSHOW:
listType = wParam;
AutoCompleteStart(0, reinterpret_cast<const char *>(lParam));
@@ -891,6 +969,31 @@ sptr_t ScintillaBase::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lPara case SCI_DESCRIBEKEYWORDSETS:
return StringResult(lParam, DocumentLexState()->DescribeWordListSets());
+ case SCI_GETLINEENDTYPESSUPPORTED:
+ return DocumentLexState()->LineEndTypesSupported();
+
+ case SCI_ALLOCATESUBSTYLES:
+ return DocumentLexState()->AllocateSubStyles(wParam, lParam);
+
+ case SCI_GETSUBSTYLESSTART:
+ return DocumentLexState()->SubStylesStart(wParam);
+
+ case SCI_GETSUBSTYLESLENGTH:
+ return DocumentLexState()->SubStylesLength(wParam);
+
+ case SCI_FREESUBSTYLES:
+ DocumentLexState()->FreeSubStyles();
+ break;
+
+ case SCI_SETIDENTIFIERS:
+ DocumentLexState()->SetIdentifiers(wParam, reinterpret_cast<const char *>(lParam));
+ break;
+
+ case SCI_DISTANCETOSECONDARYSTYLES:
+ return DocumentLexState()->DistanceToSecondaryStyles();
+
+ case SCI_GETSUBSTYLEBASES:
+ return StringResult(lParam, DocumentLexState()->GetSubStyleBases());
#endif
default:
diff --git a/scintilla/src/ScintillaBase.h b/scintilla/src/ScintillaBase.h index f34e04e..4c9271c 100644 --- a/scintilla/src/ScintillaBase.h +++ b/scintilla/src/ScintillaBase.h @@ -64,6 +64,7 @@ protected: virtual void CancelModes();
virtual int KeyCommand(unsigned int iMessage);
+ void AutoCompleteInsert(Position startPos, int removeLen, const char *text, int textLen);
void AutoCompleteStart(int lenEntered, const char *list);
void AutoCompleteCancel();
void AutoCompleteMove(int delta);
diff --git a/scintilla/src/UniConversion.h b/scintilla/src/UniConversion.h index 28b491c..1f1e537 100644 --- a/scintilla/src/UniConversion.h +++ b/scintilla/src/UniConversion.h @@ -26,3 +26,16 @@ inline bool UTF8IsAscii(int ch) { enum { UTF8MaskWidth=0x7, UTF8MaskInvalid=0x8 };
int UTF8Classify(const unsigned char *us, int len);
+
+// Line separator is U+2028 \xe2\x80\xa8
+// Paragraph separator is U+2029 \xe2\x80\xa9
+const int UTF8SeparatorLength = 3;
+inline bool UTF8IsSeparator(const unsigned char *us) {
+ return (us[0] == 0xe2) && (us[1] == 0x80) && ((us[2] == 0xa8) || (us[2] == 0xa9));
+}
+
+// NEL is U+0085 \xc2\x85
+const int UTF8NELLength = 2;
+inline bool UTF8IsNEL(const unsigned char *us) {
+ return (us[0] == 0xc2) && (us[1] == 0x85);
+}
diff --git a/scintilla/src/ViewStyle.cxx b/scintilla/src/ViewStyle.cxx index cdad268..e1eafcc 100644 --- a/scintilla/src/ViewStyle.cxx +++ b/scintilla/src/ViewStyle.cxx @@ -6,6 +6,7 @@ // The License.txt file describes the conditions under which this software may be distributed.
#include <string.h>
+#include <assert.h>
#include <vector>
#include <map>
@@ -140,6 +141,7 @@ ViewStyle::ViewStyle(const ViewStyle &source) { // Can't just copy fontname as its lifetime is relative to its owning ViewStyle
styles[sty].fontName = fontNames.Save(source.styles[sty].fontName);
}
+ nextExtendedStyle = source.nextExtendedStyle;
for (int mrk=0; mrk<=MARKER_MAX; mrk++) {
markers[mrk] = source.markers[mrk];
}
@@ -191,11 +193,13 @@ ViewStyle::ViewStyle(const ViewStyle &source) { someStylesForceCase = false;
leftMarginWidth = source.leftMarginWidth;
rightMarginWidth = source.rightMarginWidth;
- for (int i=0; i < margins; i++) {
- ms[i] = source.ms[i];
+ for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
+ ms[margin] = source.ms[margin];
}
maskInLine = source.maskInLine;
fixedColumnWidth = source.fixedColumnWidth;
+ marginInside = source.marginInside;
+ textStart = source.textStart;
zoomLevel = source.zoomLevel;
viewWhitespace = source.viewWhitespace;
whitespaceSize = source.whitespaceSize;
@@ -225,6 +229,7 @@ void ViewStyle::Init(size_t stylesSize_) { stylesSize = 0;
styles = NULL;
AllocStyles(stylesSize_);
+ nextExtendedStyle = 256;
fontNames.Clear();
ResetDefaultStyle();
@@ -303,13 +308,15 @@ void ViewStyle::Init(size_t stylesSize_) { ms[2].style = SC_MARGIN_SYMBOL;
ms[2].width = 0;
ms[2].mask = 0;
- fixedColumnWidth = leftMarginWidth;
+ marginInside = true;
+ fixedColumnWidth = marginInside ? leftMarginWidth : 0;
maskInLine = 0xffffffff;
- for (int margin=0; margin < margins; margin++) {
+ for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
fixedColumnWidth += ms[margin].width;
if (ms[margin].width > 0)
maskInLine &= ~ms[margin].mask;
}
+ textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
zoomLevel = 0;
viewWhitespace = wsInvisible;
whitespaceSize = 1;
@@ -356,6 +363,7 @@ void ViewStyle::Refresh(Surface &surface) { CreateFont(styles[j]);
}
+ assert(frFirst);
frFirst->Realise(surface, zoomLevel, technology);
for (unsigned int k=0; k<stylesSize; k++) {
@@ -383,13 +391,14 @@ void ViewStyle::Refresh(Surface &surface) { aveCharWidth = styles[STYLE_DEFAULT].aveCharWidth;
spaceWidth = styles[STYLE_DEFAULT].spaceWidth;
- fixedColumnWidth = leftMarginWidth;
+ fixedColumnWidth = marginInside ? leftMarginWidth : 0;
maskInLine = 0xffffffff;
- for (int margin=0; margin < margins; margin++) {
+ for (int margin=0; margin <= SC_MAX_MARGIN; margin++) {
fixedColumnWidth += ms[margin].width;
if (ms[margin].width > 0)
maskInLine &= ~ms[margin].mask;
}
+ textStart = marginInside ? fixedColumnWidth : leftMarginWidth;
}
void ViewStyle::AllocStyles(size_t sizeNew) {
@@ -411,6 +420,16 @@ void ViewStyle::AllocStyles(size_t sizeNew) { stylesSize = sizeNew;
}
+void ViewStyle::ReleaseAllExtendedStyles() {
+ nextExtendedStyle = 256;
+}
+
+int ViewStyle::AllocateExtendedStyles(int numberStyles) {
+ int startRange = static_cast<int>(nextExtendedStyle);
+ nextExtendedStyle += numberStyles;
+ return startRange;
+}
+
void ViewStyle::EnsureStyle(size_t index) {
if (index >= stylesSize) {
size_t sizeNew = stylesSize * 2;
@@ -469,4 +488,3 @@ void ViewStyle::CalcLargestMarkerHeight() { }
}
}
-
diff --git a/scintilla/src/ViewStyle.h b/scintilla/src/ViewStyle.h index c54448d..1830ae8 100644 --- a/scintilla/src/ViewStyle.h +++ b/scintilla/src/ViewStyle.h @@ -32,6 +32,8 @@ private: int size;
int max;
+ // Private so FontNames objects can not be copied
+ FontNames(const FontNames &);
public:
FontNames();
~FontNames();
@@ -65,6 +67,7 @@ public: FontRealised *frFirst;
size_t stylesSize;
Style *styles;
+ size_t nextExtendedStyle;
LineMarker markers[MARKER_MAX + 1];
int largestMarkerHeight;
Indicator indicators[INDIC_MAX + 1];
@@ -101,12 +104,13 @@ public: bool hotspotUnderline;
bool hotspotSingleLine;
/// Margins are ordered: Line Numbers, Selection Margin, Spacing Margin
- enum { margins=5 };
int leftMarginWidth; ///< Spacing margin on left of text
int rightMarginWidth; ///< Spacing margin on right of text
int maskInLine; ///< Mask for markers to be put into text because there is nowhere for them to go in margin
- MarginStyle ms[margins];
- int fixedColumnWidth;
+ MarginStyle ms[SC_MAX_MARGIN+1];
+ int fixedColumnWidth; ///< Total width of margins
+ bool marginInside; ///< true: margin included in text view, false: separate views
+ int textStart; ///< Starting x position of text within the view
int zoomLevel;
WhiteSpaceVisibility viewWhitespace;
int whitespaceSize;
@@ -142,6 +146,8 @@ public: void CreateFont(const FontSpecification &fs);
void Refresh(Surface &surface);
void AllocStyles(size_t sizeNew);
+ void ReleaseAllExtendedStyles();
+ int AllocateExtendedStyles(int numberStyles);
void EnsureStyle(size_t index);
void ResetDefaultStyle();
void ClearStyles();
|