diff options
| -rw-r--r-- | indra/llui/llkeywords.cpp | 52 | ||||
| -rw-r--r-- | indra/llui/llkeywords.h | 8 | ||||
| -rw-r--r-- | indra/newview/llscripteditor.cpp | 132 | ||||
| -rw-r--r-- | indra/newview/llscripteditor.h | 28 |
4 files changed, 204 insertions, 16 deletions
diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index 0ada54df06..8c34e4ab9c 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -828,29 +828,41 @@ void LLKeywords::collectSegmentOps(segment_ops_t& ops, const LLWString& wtext, b } } -void LLKeywords::applySegmentOps(std::vector<LLTextSegmentPtr> *seg_list, - const LLWString& wtext, - const segment_ops_t& ops, - LLTextEditor& editor, - LLStyleConstSP style) +bool LLKeywords::applySegmentOpsRange(std::vector<LLTextSegmentPtr> *seg_list, + const LLWString& wtext, + const segment_ops_t& ops, + size_t& op_index, + size_t max_ops, + LLTextEditor& editor, + LLStyleConstSP style) { if (wtext.empty()) { - return; + return true; } - // Clear the segment list - seg_list->clear(); - // Reserve capacity for segments based on an estimated average of 8 characters per segment. - constexpr size_t AVERAGE_SEGMENT_LENGTH = 8; - seg_list->reserve(wtext.size() / AVERAGE_SEGMENT_LENGTH); + if (op_index == 0) + { + // Clear the segment list + seg_list->clear(); + // Reserve capacity for segments based on an estimated average of 8 characters per segment. + constexpr size_t AVERAGE_SEGMENT_LENGTH = 8; + seg_list->reserve(wtext.size() / AVERAGE_SEGMENT_LENGTH); - S32 text_len = static_cast<S32>(wtext.size()) + 1; + S32 text_len = static_cast<S32>(wtext.size()) + 1; + seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) ); + } - seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) ); + S32 text_len = static_cast<S32>(wtext.size()) + 1; + size_t end_index = op_index + max_ops; + if (end_index > ops.size()) + { + end_index = ops.size(); + } - for (const auto& op : ops) + for (; op_index < end_index; ++op_index) { + const auto& op = ops[op_index]; if (op.type == SegmentOp::OP_LINE_BREAK) { LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, op.start); @@ -862,6 +874,18 @@ void LLKeywords::applySegmentOps(std::vector<LLTextSegmentPtr> *seg_list, insertSegments(wtext, *seg_list, op.token, text_len, op.start, op.end, style, editor); } } + + return op_index >= ops.size(); +} + +void LLKeywords::applySegmentOps(std::vector<LLTextSegmentPtr> *seg_list, + const LLWString& wtext, + const segment_ops_t& ops, + LLTextEditor& editor, + LLStyleConstSP style) +{ + size_t op_index = 0; + applySegmentOpsRange(seg_list, wtext, ops, op_index, ops.size(), editor, style); } // Walk through a string, applying the rules specified by the keyword token list and diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h index b8689a0e88..70fc2c20d5 100644 --- a/indra/llui/llkeywords.h +++ b/indra/llui/llkeywords.h @@ -37,6 +37,7 @@ #include <list> #include <deque> #include <vector> +#include <cstddef> #include "llpointer.h" class LLTextSegment; @@ -144,6 +145,13 @@ public: const segment_ops_t& ops, class LLTextEditor& editor, LLStyleConstSP style); + bool applySegmentOpsRange(std::vector<LLTextSegmentPtr> *seg_list, + const LLWString& text, + const segment_ops_t& ops, + size_t& op_index, + size_t max_ops, + class LLTextEditor& editor, + LLStyleConstSP style); void initialize(LLSD SyntaxXML, bool luau_language = false); void processTokens(); diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp index 871210ea6d..93244107ca 100644 --- a/indra/newview/llscripteditor.cpp +++ b/indra/newview/llscripteditor.cpp @@ -32,6 +32,7 @@ #include "lllocalcliprect.h" #include "llviewercontrol.h" #include "llworkerthread.h" +#include <algorithm> #include <utility> static LLWorkerThread& getSyntaxWorkerThread() @@ -186,7 +187,12 @@ private: return; } - mEditor->applySyntaxSegments(result.text, result.ops); + mEditor->queueSyntaxApply(std::move(result.text), + std::move(result.ops), + result.text_generation, + result.keywords_generation, + result.disable_highlight, + result.keywords); } LLScriptEditor* mEditor; @@ -219,7 +225,14 @@ LLScriptEditor::LLScriptEditor(const Params& p) mLastQueuedKeywordsGeneration(0), mLastQueuedDisableHighlight(false), mLastQueuedKeywords(nullptr), - mSyntaxWorker(nullptr) + mSyntaxWorker(nullptr), + mSyntaxApplyState(SyntaxApplyState::Idle), + mPendingApplyOpIndex(0), + mPendingApplySegmentIndex(0), + mPendingApplyTextGeneration(-1), + mPendingApplyKeywordsGeneration(0), + mPendingApplyDisableHighlight(false), + mPendingApplyKeywords(nullptr) { if (mShowLineNumbers) { @@ -339,6 +352,7 @@ void LLScriptEditor::loadKeywords() LL_PROFILE_ZONE_SCOPED; ensureSyntaxWorker(); mSyntaxWorker->waitForIdle(true); + resetPendingSyntaxApply(); getKeywords().processTokens(); ++mKeywordsGeneration; @@ -367,6 +381,7 @@ void LLScriptEditor::updateSegments() { queueSyntaxParse(); } + processPendingSyntaxApply(); } LLTextBase::updateSegments(); @@ -410,6 +425,119 @@ void LLScriptEditor::queueSyntaxParse() mSyntaxWorker->queueRequest(request); } +void LLScriptEditor::queueSyntaxApply(LLWString text, + LLKeywords::segment_ops_t ops, + S32 text_generation, + U32 keywords_generation, + bool disable_highlight, + LLKeywords* keywords) +{ + if (text_generation != getTextGeneration() + || keywords_generation != mKeywordsGeneration + || keywords != &getKeywords()) + { + return; + } + + resetPendingSyntaxApply(); + + constexpr size_t kImmediateOpsThreshold = 500; + if (ops.size() <= kImmediateOpsThreshold) + { + applySyntaxSegments(text, ops); + return; + } + + mPendingApplyText = std::move(text); + mPendingApplyOps = std::move(ops); + mPendingApplyTextGeneration = text_generation; + mPendingApplyKeywordsGeneration = keywords_generation; + mPendingApplyDisableHighlight = disable_highlight; + mPendingApplyKeywords = keywords; + mPendingApplyOpIndex = 0; + mPendingApplySegmentIndex = 0; + mPendingApplySegments.clear(); + mPendingApplySegmentSet.clear(); + mPendingApplyStyle = new LLStyle(LLStyle::Params().font(getScriptFont()).color(mDefaultColor.get())); + mSyntaxApplyState = SyntaxApplyState::Building; +} + +void LLScriptEditor::processPendingSyntaxApply() +{ + if (mSyntaxApplyState == SyntaxApplyState::Idle) + { + return; + } + + static LLCachedControl<bool> sDisableSyntaxHighlighting(gSavedSettings, "ScriptEditorDisableSyntaxHighlight", false); + if (mPendingApplyTextGeneration != getTextGeneration() + || mPendingApplyKeywordsGeneration != mKeywordsGeneration + || mPendingApplyKeywords != &getKeywords() + || mPendingApplyDisableHighlight != sDisableSyntaxHighlighting) + { + resetPendingSyntaxApply(); + return; + } + + constexpr size_t kOpsPerSlice = 250; + constexpr size_t kSegmentsPerSlice = 250; + + if (mSyntaxApplyState == SyntaxApplyState::Building) + { + if (mPendingApplyStyle.isNull()) + { + mPendingApplyStyle = new LLStyle(LLStyle::Params().font(getScriptFont()).color(mDefaultColor.get())); + } + bool done = getKeywords().applySegmentOpsRange(&mPendingApplySegments, + mPendingApplyText, + mPendingApplyOps, + mPendingApplyOpIndex, + kOpsPerSlice, + *this, + mPendingApplyStyle); + if (done) + { + mSyntaxApplyState = SyntaxApplyState::Inserting; + } + return; + } + + size_t end_index = std::min(mPendingApplySegmentIndex + kSegmentsPerSlice, mPendingApplySegments.size()); + for (; mPendingApplySegmentIndex < end_index; ++mPendingApplySegmentIndex) + { + LLTextSegmentPtr segment = mPendingApplySegments[mPendingApplySegmentIndex]; + segment->linkToDocument(this); + mPendingApplySegmentSet.insert(segment); + } + + if (mPendingApplySegmentIndex >= mPendingApplySegments.size()) + { + S32 saved_scroll_index = mScrollIndex; + segment_set_t old_segments; + old_segments.swap(mSegments); + mSegments.swap(mPendingApplySegmentSet); + mScrollIndex = saved_scroll_index; + needsReflow(0); + resetPendingSyntaxApply(); + } +} + +void LLScriptEditor::resetPendingSyntaxApply() +{ + mSyntaxApplyState = SyntaxApplyState::Idle; + mPendingApplyText.clear(); + mPendingApplyOps.clear(); + mPendingApplySegments.clear(); + mPendingApplySegmentSet.clear(); + mPendingApplyOpIndex = 0; + mPendingApplySegmentIndex = 0; + mPendingApplyStyle = LLStyleConstSP(); + mPendingApplyTextGeneration = -1; + mPendingApplyKeywordsGeneration = 0; + mPendingApplyDisableHighlight = false; + mPendingApplyKeywords = nullptr; +} + void LLScriptEditor::applySyntaxSegments(const LLWString& text, const LLKeywords::segment_ops_t& ops) { LLStyleConstSP style = new LLStyle(LLStyle::Params().font(getScriptFont()).color(mDefaultColor.get())); diff --git a/indra/newview/llscripteditor.h b/indra/newview/llscripteditor.h index 1ca26fbcc9..dcbfdf3085 100644 --- a/indra/newview/llscripteditor.h +++ b/indra/newview/llscripteditor.h @@ -29,6 +29,7 @@ #define LL_SCRIPTEDITOR_H #include "lltexteditor.h" +#include <cstddef> class LLScriptEditor : public LLTextEditor { @@ -64,14 +65,29 @@ public: protected: friend class LLUICtrlFactory; + friend class LLScriptEditorSyntaxWorker; LLScriptEditor(const Params& p); private: + enum class SyntaxApplyState + { + Idle, + Building, + Inserting + }; void drawLineNumbers(); void updateSegments() override; void drawSelectionBackground() override; void ensureSyntaxWorker(); void queueSyntaxParse(); + void queueSyntaxApply(LLWString text, + LLKeywords::segment_ops_t ops, + S32 text_generation, + U32 keywords_generation, + bool disable_highlight, + LLKeywords* keywords); + void processPendingSyntaxApply(); + void resetPendingSyntaxApply(); LLKeywords mKeywordsLua; LLKeywords mKeywordsLSL; @@ -85,6 +101,18 @@ private: bool mLastQueuedDisableHighlight; LLKeywords* mLastQueuedKeywords; class LLScriptEditorSyntaxWorker* mSyntaxWorker; + SyntaxApplyState mSyntaxApplyState; + LLWString mPendingApplyText; + LLKeywords::segment_ops_t mPendingApplyOps; + segment_vec_t mPendingApplySegments; + segment_set_t mPendingApplySegmentSet; + size_t mPendingApplyOpIndex; + size_t mPendingApplySegmentIndex; + LLStyleConstSP mPendingApplyStyle; + S32 mPendingApplyTextGeneration; + U32 mPendingApplyKeywordsGeneration; + bool mPendingApplyDisableHighlight; + LLKeywords* mPendingApplyKeywords; }; #endif // LL_SCRIPTEDITOR_H |
