aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Document.cxx28
-rw-r--r--src/Document.h2
-rw-r--r--src/Editor.cxx80
-rw-r--r--src/Editor.h6
4 files changed, 111 insertions, 5 deletions
diff --git a/src/Document.cxx b/src/Document.cxx
index 9201e162f..65c63c138 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -109,6 +109,7 @@ Document::Document() {
useTabs = true;
tabIndents = true;
backspaceUnindents = false;
+ durationStyleOneLine = 0.00001;
matchesValid = false;
regex = 0;
@@ -1892,6 +1893,33 @@ void Document::EnsureStyledTo(int pos) {
}
}
+void Document::StyleToAdjustingLineDuration(int pos) {
+ // Place bounds on the duration used to avoid glitches spiking it
+ // and so causing slow styling or non-responsive scrolling
+ const double minDurationOneLine = 0.000001;
+ const double maxDurationOneLine = 0.0001;
+
+ // Alpha value for exponential smoothing.
+ // Most recent value contributes 25% to smoothed value.
+ const double alpha = 0.25;
+
+ const Sci_Position lineFirst = LineFromPosition(GetEndStyled());
+ ElapsedTime etStyling;
+ EnsureStyledTo(pos);
+ const double durationStyling = etStyling.Duration();
+ const Sci_Position lineLast = LineFromPosition(GetEndStyled());
+ if (lineLast >= lineFirst + 8) {
+ // Only adjust for styling multiple lines to avoid instability
+ const double durationOneLine = durationStyling / (lineLast - lineFirst);
+ durationStyleOneLine = alpha * durationOneLine + (1.0 - alpha) * durationStyleOneLine;
+ if (durationStyleOneLine < minDurationOneLine) {
+ durationStyleOneLine = minDurationOneLine;
+ } else if (durationStyleOneLine > maxDurationOneLine) {
+ durationStyleOneLine = maxDurationOneLine;
+ }
+ }
+}
+
void Document::LexerChanged() {
// Tell the watchers the lexer has changed.
for (std::vector<WatcherWithUserData>::iterator it = watchers.begin(); it != watchers.end(); ++it) {
diff --git a/src/Document.h b/src/Document.h
index ea8ddfbed..71a45879e 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -246,6 +246,7 @@ public:
bool useTabs;
bool tabIndents;
bool backspaceUnindents;
+ double durationStyleOneLine;
DecorationList decorations;
@@ -400,6 +401,7 @@ public:
bool SCI_METHOD SetStyles(Sci_Position length, const char *styles);
int GetEndStyled() const { return endStyled; }
void EnsureStyledTo(int pos);
+ void StyleToAdjustingLineDuration(int pos);
void LexerChanged();
int GetStyleClock() const { return styleClock; }
void IncrementStyleClock();
diff --git a/src/Editor.cxx b/src/Editor.cxx
index 6141b0628..a86f8c96e 100644
--- a/src/Editor.cxx
+++ b/src/Editor.cxx
@@ -173,6 +173,8 @@ Editor::Editor() {
paintAbandonedByStyling = false;
paintingAllText = false;
willRedrawAll = false;
+ idleStyling = SC_IDLESTYLING_NONE;
+ needIdleStyling = false;
modEventMask = SC_MODEVENTMASKALL;
@@ -919,7 +921,7 @@ void Editor::ScrollTo(int line, bool moveThumb) {
SetTopLine(topLineNew);
// Optimize by styling the view as this will invalidate any needed area
// which could abort the initial paint if discovered later.
- StyleToPositionInView(PositionAfterArea(GetClientRectangle()));
+ StyleAreaBounded(GetClientRectangle(), true);
#ifndef UNDER_CE
// Perform redraw rather than scroll if many lines would be redrawn anyway.
if (performBlit) {
@@ -1692,7 +1694,7 @@ void Editor::Paint(Surface *surfaceWindow, PRectangle rcArea) {
paintAbandonedByStyling = false;
- StyleToPositionInView(PositionAfterArea(rcArea));
+ StyleAreaBounded(rcArea, false);
PRectangle rcClient = GetClientRectangle();
//Platform::DebugPrintf("Client: (%3d,%3d) ... (%3d,%3d) %d\n",
@@ -4893,6 +4895,8 @@ bool Editor::Idle() {
// No more wrapping
if (!wrapPending.NeedsWrap())
wrappingDone = true;
+ } else if (needIdleStyling) {
+ IdleStyling();
}
// Add more idle things to do here, but make sure idleDone is
@@ -4900,7 +4904,7 @@ bool Editor::Idle() {
// false will stop calling this idle function until SetIdle() is
// called again.
- idleDone = wrappingDone; // && thatDone && theOtherThingDone...
+ idleDone = wrappingDone && !needIdleStyling; // && thatDone && theOtherThingDone...
return !idleDone;
}
@@ -5003,12 +5007,71 @@ void Editor::StyleToPositionInView(Position pos) {
}
}
+int Editor::PositionAfterMaxStyling(int posMax, bool scrolling) const {
+ if ((idleStyling == SC_IDLESTYLING_NONE) || (idleStyling == SC_IDLESTYLING_AFTERVISIBLE)) {
+ // Both states do not limit styling
+ return posMax;
+ }
+
+ // Try to keep time taken by styling reasonable so interaction remains smooth.
+ // When scrolling, allow less time to ensure responsive
+ const double secondsAllowed = scrolling ? 0.005 : 0.02;
+
+ const int linesToStyle = Platform::Clamp(static_cast<int>(secondsAllowed / pdoc->durationStyleOneLine),
+ 10, 0x10000);
+ const int stylingMaxLine = std::min(
+ static_cast<int>(pdoc->LineFromPosition(pdoc->GetEndStyled()) + linesToStyle),
+ pdoc->LinesTotal());
+ return std::min(static_cast<int>(pdoc->LineStart(stylingMaxLine)), posMax);
+}
+
+void Editor::StartIdleStyling(bool truncatedLastStyling) {
+ if ((idleStyling == SC_IDLESTYLING_ALL) || (idleStyling == SC_IDLESTYLING_AFTERVISIBLE)) {
+ if (pdoc->GetEndStyled() < pdoc->Length()) {
+ // Style remainder of document in idle time
+ needIdleStyling = true;
+ }
+ } else if (truncatedLastStyling) {
+ needIdleStyling = true;
+ }
+
+ if (needIdleStyling) {
+ SetIdle(true);
+ }
+}
+
+// Style for an area but bound the amount of styling to remain responsive
+void Editor::StyleAreaBounded(PRectangle rcArea, bool scrolling) {
+ const int posAfterArea = PositionAfterArea(rcArea);
+ const int posAfterMax = PositionAfterMaxStyling(posAfterArea, scrolling);
+ if (posAfterMax < posAfterArea) {
+ // Idle styling may be performed before current visible area
+ // Style a bit now then style further in idle time
+ pdoc->StyleToAdjustingLineDuration(posAfterMax);
+ } else {
+ // Can style all wanted now.
+ StyleToPositionInView(posAfterArea);
+ }
+ StartIdleStyling(posAfterMax < posAfterArea);
+}
+
+void Editor::IdleStyling() {
+ const int posAfterArea = PositionAfterArea(GetClientRectangle());
+ const int endGoal = (idleStyling >= SC_IDLESTYLING_AFTERVISIBLE) ?
+ pdoc->Length() : posAfterArea;
+ const int posAfterMax = PositionAfterMaxStyling(endGoal, false);
+ pdoc->StyleToAdjustingLineDuration(posAfterMax);
+ if (pdoc->GetEndStyled() >= endGoal) {
+ needIdleStyling = false;
+ }
+}
+
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.
- if (workNeeded.items & WorkNeeded::workStyle)
+ if (workNeeded.items & WorkNeeded::workStyle) {
StyleToPositionInView(pdoc->LineStart(pdoc->LineFromPosition(workNeeded.upTo) + 2));
-
+ }
NotifyUpdateUI();
workNeeded.Reset();
}
@@ -6400,6 +6463,13 @@ sptr_t Editor::WndProc(unsigned int iMessage, uptr_t wParam, sptr_t lParam) {
case SCI_ISRANGEWORD:
return pdoc->IsWordAt(static_cast<int>(wParam), static_cast<int>(lParam));
+
+ case SCI_SETIDLESTYLING:
+ idleStyling = static_cast<int>(wParam);
+ break;
+
+ case SCI_GETIDLESTYLING:
+ return idleStyling;
case SCI_SETWRAPMODE:
if (vs.SetWrapState(static_cast<int>(wParam))) {
diff --git a/src/Editor.h b/src/Editor.h
index 7b88cbab0..0d788b5a8 100644
--- a/src/Editor.h
+++ b/src/Editor.h
@@ -234,6 +234,8 @@ protected: // ScintillaBase subclass needs access to much of Editor
bool paintingAllText;
bool willRedrawAll;
WorkNeeded workNeeded;
+ int idleStyling;
+ bool needIdleStyling;
int modEventMask;
@@ -525,6 +527,10 @@ protected: // ScintillaBase subclass needs access to much of Editor
int PositionAfterArea(PRectangle rcArea) const;
void StyleToPositionInView(Position pos);
+ int PositionAfterMaxStyling(int posMax, bool scrolling) const;
+ void StartIdleStyling(bool truncatedLastStyling);
+ void StyleAreaBounded(PRectangle rcArea, bool scrolling);
+ void IdleStyling();
virtual void IdleWork();
virtual void QueueIdleWork(WorkNeeded::workItems items, int upTo=0);