summaryrefslogtreecommitdiff
path: root/indra/llui/llkeywords.cpp
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2026-01-12 05:23:33 +0200
committerAndrey Lihatskiy <alihatskiy@productengine.com>2026-01-15 06:04:31 +0200
commit5fa0910d6176f610de45548d8558fb53f00a0eda (patch)
tree10eafada9751ce6eee53de299e024ddb699e82e0 /indra/llui/llkeywords.cpp
parentb44bab80b54bf9beacedc231a3e736cf7377fab4 (diff)
#5278 Move syntax tokenization off UI thread; apply results on main thread
Diffstat (limited to 'indra/llui/llkeywords.cpp')
-rw-r--r--indra/llui/llkeywords.cpp109
1 files changed, 69 insertions, 40 deletions
diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp
index 2168ba2382..0ada54df06 100644
--- a/indra/llui/llkeywords.cpp
+++ b/indra/llui/llkeywords.cpp
@@ -498,41 +498,25 @@ bool LLKeywords::WStringMapIndex::operator<(const LLKeywords::WStringMapIndex &o
LLTrace::BlockTimerStatHandle FTM_SYNTAX_COLORING("Syntax Coloring");
-// Walk through a string, applying the rules specified by the keyword token list and
-// create a list of color segments.
-void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLWString& wtext, LLTextEditor& editor, LLStyleConstSP style)
+void LLKeywords::collectSegmentOps(segment_ops_t& ops, const LLWString& wtext, bool disable_syntax_highlighting) const
{
- LL_RECORD_BLOCK_TIME(FTM_SYNTAX_COLORING);
+ ops.clear();
- if( wtext.empty() )
+ if (wtext.empty())
{
return;
}
- // 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;
-
- seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) );
-
- static LLCachedControl<bool> sDisableSyntaxHighlighting(gSavedSettings, "ScriptEditorDisableSyntaxHighlight", false);
- const bool disable_syntax_highlighting = sDisableSyntaxHighlighting;
-
const llwchar* base = wtext.c_str();
const llwchar* cur = base;
+
while( *cur )
{
if( *cur == '\n' || cur == base )
{
if( *cur == '\n' )
{
- LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, (S32)(cur - base));
- text_segment->setToken( 0 );
- insertSegment( *seg_list, text_segment, text_len, style, editor);
+ ops.push_back({SegmentOp::OP_LINE_BREAK, (S32)(cur - base), 0, nullptr});
cur++;
if( !*cur || *cur == '\n' )
{
@@ -570,8 +554,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
}
S32 seg_end = (S32)(cur - base);
- //create segments from seg_start to seg_end
- insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor);
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, cur_token});
line_done = true; // to break out of second loop.
break;
}
@@ -646,7 +629,6 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
if (*p == '[')
{
p++; // skip the second [
- const llwchar* content_start = p;
// Build the closing pattern: ] + level equals + ]
// Search for it in the remaining text
@@ -667,7 +649,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
// Found the matching close
seg_end = (S32)(close_check + 1 - base);
cur = close_check + 1;
- insertSegments(wtext, *seg_list, cur_delimiter, text_len, seg_start, seg_end, style, editor);
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, cur_delimiter});
break;
}
}
@@ -677,9 +659,9 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
if (!*p)
{
// No closing found, highlight to end of file
- seg_end = text_len - 1;
+ seg_end = static_cast<S32>(wtext.size());
cur = base + seg_end;
- insertSegments(wtext, *seg_list, cur_delimiter, text_len, seg_start, seg_end, style, editor);
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, cur_delimiter});
}
continue;
}
@@ -761,7 +743,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead();
}
- insertSegments(wtext, *seg_list, cur_delimiter, text_len, seg_start, seg_end, style, editor);
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, cur_delimiter});
// Note: we don't increment cur, since the end of one delimited seg may be immediately
// followed by the start of another one.
continue;
@@ -794,13 +776,12 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
S32 seg_end = seg_start + seg_len;
// First try to match the whole token (including dots for Lua namespaces)
- word_token_map_t::iterator map_iter = mWordTokenMap.find(WStringMapIndex(word_start, seg_len));
+ word_token_map_t::const_iterator map_iter = mWordTokenMap.find(WStringMapIndex(word_start, seg_len));
if (map_iter != mWordTokenMap.end())
{
// Found a match for the complete token (including any namespace)
- LLKeywordToken* cur_token = map_iter->second;
- insertSegments(wtext, *seg_list, cur_token, text_len, seg_start, seg_end, style, editor);
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, map_iter->second});
}
else if (namespace_dots > 0 && mLuauLanguage)
{
@@ -815,8 +796,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
if (map_iter != mWordTokenMap.end())
{
// Found a match for the namespace prefix, highlight just that part
- LLKeywordToken* cur_token = map_iter->second;
- insertSegments(wtext, *seg_list, cur_token, text_len, seg_start, seg_start + prefix_len, style, editor);
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_start + prefix_len, map_iter->second});
// Now try to match the function part (after the dot)
const llwchar* func_part = last_dot + 1;
@@ -830,13 +810,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
if (map_iter != mWordTokenMap.end())
{
// Found a match for the function part
- LLKeywordToken* cur_token = map_iter->second;
- insertSegments(wtext, *seg_list, cur_token, text_len, seg_start, seg_end, style, editor);
- }
- else
- {
- // No token found, continue without incrementing cur
- // since we already advanced it while collecting the word
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, map_iter->second});
}
}
}
@@ -854,6 +828,61 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
}
}
+void LLKeywords::applySegmentOps(std::vector<LLTextSegmentPtr> *seg_list,
+ const LLWString& wtext,
+ const segment_ops_t& ops,
+ LLTextEditor& editor,
+ LLStyleConstSP style)
+{
+ if (wtext.empty())
+ {
+ return;
+ }
+
+ // 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;
+
+ seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) );
+
+ for (const auto& op : ops)
+ {
+ if (op.type == SegmentOp::OP_LINE_BREAK)
+ {
+ LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, op.start);
+ text_segment->setToken( 0 );
+ insertSegment( *seg_list, text_segment, text_len, style, editor);
+ }
+ else
+ {
+ insertSegments(wtext, *seg_list, op.token, text_len, op.start, op.end, style, editor);
+ }
+ }
+}
+
+// Walk through a string, applying the rules specified by the keyword token list and
+// create a list of color segments.
+void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLWString& wtext, LLTextEditor& editor, LLStyleConstSP style)
+{
+ LL_RECORD_BLOCK_TIME(FTM_SYNTAX_COLORING);
+
+ if( wtext.empty() )
+ {
+ return;
+ }
+
+ static LLCachedControl<bool> sDisableSyntaxHighlighting(gSavedSettings, "ScriptEditorDisableSyntaxHighlight", false);
+ const bool disable_syntax_highlighting = sDisableSyntaxHighlighting;
+
+ segment_ops_t ops;
+ collectSegmentOps(ops, wtext, disable_syntax_highlighting);
+ applySegmentOps(seg_list, wtext, ops, editor, style);
+}
+
void LLKeywords::insertSegments(const LLWString& wtext, std::vector<LLTextSegmentPtr>& seg_list, LLKeywordToken* cur_token, S32 text_len, S32 seg_start, S32 seg_end, LLStyleConstSP style, LLTextEditor& editor )
{
std::string::size_type pos = wtext.find('\n',seg_start);