summaryrefslogtreecommitdiff
path: root/indra/llui
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llui')
-rw-r--r--indra/llui/llcombobox.cpp17
-rw-r--r--indra/llui/llcombobox.h5
-rw-r--r--indra/llui/llkeywords.cpp402
-rw-r--r--indra/llui/llkeywords.h40
-rw-r--r--indra/llui/llscrolllistctrl.cpp13
-rw-r--r--indra/llui/llscrolllistctrl.h3
6 files changed, 382 insertions, 98 deletions
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index ae676251ff..ad6ab9dc4c 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -251,11 +251,26 @@ void LLComboBox::resetDirty()
}
}
-bool LLComboBox::itemExists(const std::string& name)
+bool LLComboBox::itemExists(const std::string& name) const
{
return mList->getItemByLabel(name);
}
+bool LLComboBox::valueExists(const std::string& value) const
+{
+ return mList->getItemByValue(value);
+}
+
+LLScrollListItem* LLComboBox::findItemByValue(const std::string& value) const
+{
+ return mList->getItemByValue(value);
+}
+
+std::vector<LLScrollListItem*> LLComboBox::getAllData() const
+{
+ return mList->getAllData();
+}
+
// add item "name" to menu
LLScrollListItem* LLComboBox::add(const std::string& name, EAddPosition pos, bool enabled)
{
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index d6ea1202d3..52a2165f1b 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -142,7 +142,10 @@ public:
LLScrollListItem* addSeparator(EAddPosition pos = ADD_BOTTOM);
bool remove( S32 index ); // remove item by index, return true if found and removed
void removeall() { clearRows(); }
- bool itemExists(const std::string& name);
+ bool itemExists(const std::string& name) const;
+ bool valueExists(const std::string& value) const;
+ LLScrollListItem* findItemByValue(const std::string& value) const;
+ std::vector<LLScrollListItem*> getAllData() const;
void sortByName(bool ascending = true); // Sort the entries in the combobox by name
diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp
index 2bea8fb4ed..b1f1fb77f3 100644
--- a/indra/llui/llkeywords.cpp
+++ b/indra/llui/llkeywords.cpp
@@ -33,38 +33,20 @@
#include "llsdserialize.h"
#include "lltexteditor.h"
#include "llstl.h"
+#include "llcontrol.h"
+
+extern LLControlGroup gSavedSettings;
inline bool LLKeywordToken::isHead(const llwchar* s) const
{
- // strncmp is much faster than string compare
- bool res = true;
- const llwchar* t = mToken.c_str();
- auto len = mToken.size();
- for (S32 i=0; i<len; i++)
- {
- if (s[i] != t[i])
- {
- res = false;
- break;
- }
- }
- return res;
+ size_t bytes = mToken.size() * sizeof(llwchar);
+ return std::memcmp(s, mToken.c_str(), bytes) == 0;
}
inline bool LLKeywordToken::isTail(const llwchar* s) const
{
- bool res = true;
- const llwchar* t = mDelimiter.c_str();
- auto len = mDelimiter.size();
- for (S32 i=0; i<len; i++)
- {
- if (s[i] != t[i])
- {
- res = false;
- break;
- }
- }
- return res;
+ size_t len_bytes = mDelimiter.size() * sizeof(llwchar);
+ return std::memcmp(s, mDelimiter.c_str(), len_bytes) == 0;
}
LLKeywords::LLKeywords()
@@ -80,6 +62,8 @@ LLKeywords::~LLKeywords()
mLineTokenList.clear();
std::for_each(mDelimiterTokenList.begin(), mDelimiterTokenList.end(), DeletePointer());
mDelimiterTokenList.clear();
+ mLineTokenByFirstChar.clear();
+ mDelimiterTokenByFirstChar.clear();
}
// Add the token as described
@@ -114,14 +98,29 @@ void LLKeywords::addToken(LLKeywordToken::ETokenType type,
break;
case LLKeywordToken::TT_LINE:
- mLineTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null));
+ {
+ LLKeywordToken* token = new LLKeywordToken(type, color, key, tool_tip, LLWStringUtil::null);
+ mLineTokenList.push_front(token);
+ if (!key.empty())
+ {
+ mLineTokenByFirstChar[key[0]].push_front(token);
+ }
break;
+ }
case LLKeywordToken::TT_TWO_SIDED_DELIMITER:
case LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS:
case LLKeywordToken::TT_ONE_SIDED_DELIMITER:
- mDelimiterTokenList.push_front(new LLKeywordToken(type, color, key, tool_tip, delimiter));
+ case LLKeywordToken::TT_LONG_BRACKET:
+ {
+ LLKeywordToken* token = new LLKeywordToken(type, color, key, tool_tip, delimiter);
+ mDelimiterTokenList.push_front(token);
+ if (!key.empty())
+ {
+ mDelimiterTokenByFirstChar[key[0]].push_front(token);
+ }
break;
+ }
default:
llassert(0);
@@ -219,9 +218,10 @@ LLUIColor LLKeywords::getColorGroup(std::string_view key_in) const
return LLUIColorTable::instance().getColor(color_group);
}
-void LLKeywords::initialize(LLSD SyntaxXML)
+void LLKeywords::initialize(LLSD SyntaxXML, bool luau_language)
{
mSyntax = SyntaxXML;
+ mLuauLanguage = luau_language;
mLoaded = true;
}
@@ -234,13 +234,30 @@ void LLKeywords::processTokens()
// Add 'standard' stuff: Quotes, Comments, Strings, Labels, etc. before processing the LLSD
std::string delimiter;
- addToken(LLKeywordToken::TT_LABEL, "@", getColorGroup("misc-flow-label"), "Label\nTarget for jump statement", delimiter );
- addToken(LLKeywordToken::TT_ONE_SIDED_DELIMITER, "//", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (single-line)\nNon-functional commentary or disabled code", delimiter );
- addToken(LLKeywordToken::TT_TWO_SIDED_DELIMITER, "/*", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (multi-line)\nNon-functional commentary or disabled code", "*/" );
- addToken(LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS, "\"", LLUIColorTable::instance().getColor("SyntaxLslStringLiteral"), "String literal", "\"" );
+ addToken(LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS, "\"", LLUIColorTable::instance().getColor("SyntaxLslStringLiteral"), "String literal", "\"");
+
+ if (mLuauLanguage)
+ {
+ addToken(LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS, "\'", LLUIColorTable::instance().getColor("SyntaxLslStringLiteral"), "String literal", "\'");
+ // TODO: Might be nice to add a special case for this so we can still highlight expressions in `{}`s
+ addToken(LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS, "`", LLUIColorTable::instance().getColor("SyntaxLslStringLiteral"), "String literal", "`");
+ // Add Lua-style comments
+ addToken(LLKeywordToken::TT_ONE_SIDED_DELIMITER, "--", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (Lua-style single-line)\nNon-functional commentary or disabled code", delimiter);
+ // Add Lua multi-line comments (long brackets)
+ addToken(LLKeywordToken::TT_LONG_BRACKET, "--[", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (Lua-style multi-line)\nNon-functional commentary or disabled code", delimiter);
+ // Add Lua multi-line strings (long brackets)
+ addToken(LLKeywordToken::TT_LONG_BRACKET, "[", LLUIColorTable::instance().getColor("SyntaxLslStringLiteral"), "String literal (Lua-style multi-line)", delimiter);
+ }
+ else
+ {
+ addToken(LLKeywordToken::TT_LABEL, "@", getColorGroup("misc-flow-label"), "Label\nTarget for jump statement", delimiter);
+ // Add LSL-style comments
+ addToken(LLKeywordToken::TT_ONE_SIDED_DELIMITER, "//", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (single-line)\nNon-functional commentary or disabled code", delimiter);
+ addToken(LLKeywordToken::TT_TWO_SIDED_DELIMITER, "/*", LLUIColorTable::instance().getColor("SyntaxLslComment"), "Comment (multi-line)\nNon-functional commentary or disabled code", "*/");
+ }
LLSD::map_iterator itr = mSyntax.beginMap();
- for ( ; itr != mSyntax.endMap(); ++itr)
+ for (; itr != mSyntax.endMap(); ++itr)
{
if (itr->first == "llsd-lsl-syntax-version")
{
@@ -258,6 +275,7 @@ void LLKeywords::processTokens()
}
}
}
+
LL_INFOS("SyntaxLSL") << "Finished processing tokens." << LL_ENDL;
}
@@ -346,8 +364,11 @@ void LLKeywords::processTokensGroup(const LLSD& tokens, std::string_view group)
break;
case LLKeywordToken::TT_FUNCTION:
tooltip = getAttribute("return") + " " + outer_itr->first + "(" + getArguments(arguments) + ");";
- tooltip.append("\nEnergy: ");
- tooltip.append(getAttribute("energy").empty() ? "0.0" : getAttribute("energy"));
+ if (std::stod(getAttribute("energy")) >= 0)
+ {
+ tooltip.append("\nEnergy: ");
+ tooltip.append(getAttribute("energy").empty() ? "0.0" : getAttribute("energy"));
+ }
if (!getAttribute("sleep").empty())
{
tooltip += ", Sleep: " + getAttribute("sleep");
@@ -476,34 +497,29 @@ bool LLKeywords::WStringMapIndex::operator<(const LLKeywords::WStringMapIndex &o
}
LLTrace::BlockTimerStatHandle FTM_SYNTAX_COLORING("Syntax Coloring");
+constexpr size_t AVERAGE_SEGMENT_LENGTH = 8;
-// 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);
- seg_list->clear();
+ ops.clear();
- if( wtext.empty() )
+ if (wtext.empty())
{
return;
}
-
- S32 text_len = static_cast<S32>(wtext.size()) + 1;
-
- seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) );
+ // Heuristic to reduce reallocation churn on large scripts.
+ ops.reserve(wtext.size() / AVERAGE_SEGMENT_LENGTH);
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' )
{
@@ -526,24 +542,25 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
// Line start tokens
{
bool line_done = false;
- for (token_list_t::iterator iter = mLineTokenList.begin();
- iter != mLineTokenList.end(); ++iter)
+ auto line_token_it = mLineTokenByFirstChar.find(*cur);
+ if (line_token_it != mLineTokenByFirstChar.end())
{
- LLKeywordToken* cur_token = *iter;
- if( cur_token->isHead( cur ) )
+ for (auto* cur_token : line_token_it->second)
{
- S32 seg_start = (S32)(cur - base);
- while( *cur && *cur != '\n' )
+ if( cur_token->isHead( cur ) )
{
- // skip the rest of the line
- cur++;
- }
- S32 seg_end = (S32)(cur - base);
+ S32 seg_start = (S32)(cur - base);
+ while( *cur && *cur != '\n' )
+ {
+ // skip the rest of the line
+ cur++;
+ }
+ 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);
- line_done = true; // to break out of second loop.
- break;
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, cur_token});
+ line_done = true; // to break out of second loop.
+ break;
+ }
}
}
@@ -560,20 +577,32 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
cur++;
}
+ // Check if syntax highlighting is disabled
+ if (disable_syntax_highlighting)
+ {
+ while (*cur && *cur != '\n')
+ {
+ ++cur;
+ }
+ continue; // skip processing any further syntax highlighting
+ }
+
while( *cur && *cur != '\n' )
{
// Check against delimiters
{
S32 seg_start = 0;
LLKeywordToken* cur_delimiter = NULL;
- for (token_list_t::iterator iter = mDelimiterTokenList.begin();
- iter != mDelimiterTokenList.end(); ++iter)
+ auto delimiter_it = mDelimiterTokenByFirstChar.find(*cur);
+ if (delimiter_it != mDelimiterTokenByFirstChar.end())
{
- LLKeywordToken* delimiter = *iter;
- if( delimiter->isHead( cur ) )
+ for (auto* delimiter : delimiter_it->second)
{
- cur_delimiter = delimiter;
- break;
+ if( delimiter->isHead( cur ) )
+ {
+ cur_delimiter = delimiter;
+ break;
+ }
}
}
@@ -583,10 +612,79 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
S32 seg_end = 0;
seg_start = (S32)(cur - base);
- cur += cur_delimiter->getLengthHead();
LLKeywordToken::ETokenType type = cur_delimiter->getType();
- if( type == LLKeywordToken::TT_TWO_SIDED_DELIMITER || type == LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS )
+
+ // Handle Lua long brackets specially - need to verify full pattern
+ if (type == LLKeywordToken::TT_LONG_BRACKET)
+ {
+ const llwchar* p = cur + cur_delimiter->getLengthHead(); // after --[ or [
+
+ // Count equals signs
+ S32 level = 0;
+ while (*p == '=')
+ {
+ level++;
+ p++;
+ }
+
+ // Must have second [
+ if (*p == '[')
+ {
+ p++; // skip the second [
+
+ // Build the closing pattern: ] + level equals + ]
+ // Search for it in the remaining text
+ while (*p)
+ {
+ if (*p == ']')
+ {
+ // Check if this is our closing bracket
+ const llwchar* close_check = p + 1;
+ S32 close_equals = 0;
+ while (*close_check == '=')
+ {
+ close_equals++;
+ close_check++;
+ }
+ if (close_equals == level && *close_check == ']')
+ {
+ // Found the matching close
+ seg_end = (S32)(close_check + 1 - base);
+ cur = close_check + 1;
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, cur_delimiter});
+ break;
+ }
+ }
+ p++;
+ }
+
+ if (!*p)
+ {
+ // No closing found, highlight to end of file
+ seg_end = static_cast<S32>(wtext.size());
+ cur = base + seg_end;
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, cur_delimiter});
+ }
+ continue;
+ }
+ else
+ {
+ // Not a valid long bracket (e.g., --[abc), skip this delimiter
+ cur_delimiter = NULL;
+ }
+ }
+
+ if (!cur_delimiter)
+ {
+ // Long bracket validation failed, continue to next character
+ cur++;
+ continue;
+ }
+
+ cur += cur_delimiter->getLengthHead();
+
+ if(type == LLKeywordToken::TT_TWO_SIDED_DELIMITER || type == LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS)
{
while( *cur && !cur_delimiter->isTail(cur))
{
@@ -627,7 +725,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
if( *cur )
{
- cur += cur_delimiter->getLengthHead();
+ cur += cur_delimiter->getLengthTail();
seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead() + cur_delimiter->getLengthTail();
}
else
@@ -648,12 +746,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);
- /*
- LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_delimiter->getColor(), seg_start, seg_end, editor );
- text_segment->setToken( cur_delimiter );
- insertSegment( seg_list, text_segment, text_len, defaultColor, 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;
@@ -662,34 +755,77 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
// check against words
llwchar prev = cur > base ? *(cur-1) : 0;
- if( !iswalnum( prev ) && (prev != '_') )
+ if (!iswalnum(prev) && prev != '_' && prev != '.')
{
- const llwchar* p = cur;
- while( iswalnum( *p ) || (*p == '_') )
+ const llwchar* word_start = cur;
+ S32 namespace_dots = 0;
+ const llwchar* last_dot = nullptr;
+
+ // Find the full extent of the word, potentially including namespace dots
+ while (iswalnum(*cur) || *cur == '_' || (mLuauLanguage && *cur == '.' && iswalnum(*(cur+1))))
{
- p++;
+ if (mLuauLanguage && *cur == '.')
+ {
+ namespace_dots++;
+ last_dot = cur;
+ }
+ cur++;
}
- S32 seg_len = (S32)(p - cur);
- if( seg_len > 0 )
+
+ S32 seg_len = (S32)(cur - word_start);
+ if (seg_len > 0)
{
- WStringMapIndex word( cur, seg_len );
- word_token_map_t::iterator map_iter = mWordTokenMap.find(word);
- if( map_iter != mWordTokenMap.end() )
+ S32 seg_start = (S32)(word_start - base);
+ S32 seg_end = seg_start + seg_len;
+
+ // First try to match the whole token (including dots for Lua namespaces)
+ 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)
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_end, map_iter->second});
+ }
+ else if (namespace_dots > 0 && mLuauLanguage)
{
- LLKeywordToken* cur_token = map_iter->second;
- S32 seg_start = (S32)(cur - base);
- S32 seg_end = seg_start + seg_len;
+ // If using Lua and we have namespace dots but didn't match the whole token,
+ // check if we have a match for just the namespace prefix (e.g., "ll")
+ if (last_dot > word_start)
+ {
+ // Get the namespace prefix (part before the first dot)
+ S32 prefix_len = (S32)(last_dot - word_start);
+ map_iter = mWordTokenMap.find(WStringMapIndex(word_start, prefix_len));
- // LL_INFOS("SyntaxLSL") << "Seg: [" << word.c_str() << "]" << LL_ENDL;
+ if (map_iter != mWordTokenMap.end())
+ {
+ // Found a match for the namespace prefix, highlight just that part
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start, seg_start + prefix_len, map_iter->second});
- insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor);
+ // Now try to match the function part (after the dot)
+ const llwchar* func_part = last_dot + 1;
+ S32 func_len = (S32)(cur - func_part);
+
+ if (func_len > 0)
+ {
+ // Look for complete function matches
+ map_iter = mWordTokenMap.find(WStringMapIndex(func_part, func_len));
+
+ if (map_iter != mWordTokenMap.end())
+ {
+ // Found a match for the function part.
+ // Start must be after the dot (seg_start + prefix_len + 1),
+ // not at seg_start, to avoid overlapping with the prefix segment.
+ ops.push_back({SegmentOp::OP_TOKEN, seg_start + prefix_len + 1, seg_end, map_iter->second});
+ }
+ }
+ }
+ }
}
- cur += seg_len;
- continue;
+ continue; // Continue to next token regardless of match
}
}
- if( *cur && *cur != '\n' )
+ if (*cur && *cur != '\n')
{
cur++;
}
@@ -697,6 +833,84 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
}
}
+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 true;
+ }
+
+ 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.
+ 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 ) );
+ }
+
+ 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 (; 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);
+ 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);
+ }
+ }
+
+ 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
+// 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);
diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h
index 53b5435324..9d9c8f964c 100644
--- a/indra/llui/llkeywords.h
+++ b/indra/llui/llkeywords.h
@@ -36,6 +36,8 @@
#include <map>
#include <list>
#include <deque>
+#include <vector>
+#include <cstddef>
#include "llpointer.h"
class LLTextSegment;
@@ -53,6 +55,7 @@ public:
* - TT_ONE_SIDED_DELIMITER are for open-ended delimiters which are terminated by EOL.
* - TT_TWO_SIDED_DELIMITER are for delimiters that end with a different delimiter than they open with.
* - TT_DOUBLE_QUOTATION_MARKS are for delimiting areas using the same delimiter to open and close.
+ * - TT_LONG_BRACKET are for Lua tokens that use brackets with counted equals signs.
*/
typedef enum e_token_type
{
@@ -62,6 +65,7 @@ public:
TT_TWO_SIDED_DELIMITER,
TT_ONE_SIDED_DELIMITER,
TT_DOUBLE_QUOTATION_MARKS,
+ TT_LONG_BRACKET, // Lua long brackets: --[=*[ or [=*[
// Following constants are more specific versions of the preceding ones
TT_CONSTANT, // WORD
TT_CONTROL, // WORD
@@ -82,6 +86,10 @@ public:
{
}
+ ~LLKeywordToken()
+ {
+ }
+
S32 getLengthHead() const { return static_cast<S32>(mToken.size()); }
S32 getLengthTail() const { return static_cast<S32>(mDelimiter.size()); }
bool isHead(const llwchar* s) const;
@@ -118,7 +126,33 @@ public:
const LLWString& text,
class LLTextEditor& editor,
LLStyleConstSP style);
- void initialize(LLSD SyntaxXML);
+ struct SegmentOp
+ {
+ enum EOpType
+ {
+ OP_LINE_BREAK,
+ OP_TOKEN
+ };
+ EOpType type;
+ S32 start;
+ S32 end;
+ LLKeywordToken* token;
+ };
+ typedef std::vector<SegmentOp> segment_ops_t;
+ void collectSegmentOps(segment_ops_t& ops, const LLWString& text, bool disable_syntax_highlighting) const;
+ void applySegmentOps(std::vector<LLTextSegmentPtr> *seg_list,
+ const LLWString& text,
+ 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();
// Add the token as described
@@ -189,10 +223,14 @@ protected:
bool mLoaded;
LLSD mSyntax;
+ bool mLuauLanguage;
word_token_map_t mWordTokenMap;
typedef std::deque<LLKeywordToken*> token_list_t;
token_list_t mLineTokenList;
token_list_t mDelimiterTokenList;
+ typedef std::map<llwchar, token_list_t> token_by_first_char_map_t;
+ token_by_first_char_map_t mLineTokenByFirstChar;
+ token_by_first_char_map_t mDelimiterTokenByFirstChar;
typedef std::unordered_map<std::string, std::string, ll::string_hash, std::equal_to<>> element_attributes_t;
typedef element_attributes_t::const_iterator attribute_iterator_t;
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 558ce6a7fd..662fe97689 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -1281,6 +1281,19 @@ LLScrollListItem* LLScrollListCtrl::getItemByLabel(const std::string& label, boo
return NULL;
}
+LLScrollListItem* LLScrollListCtrl::getItemByValue(const std::string& value)
+{
+ for (LLScrollListItem* item : mItemList)
+ {
+ if (item->getValue().asString() == value)
+ {
+ return item;
+ }
+ }
+
+ return NULL;
+}
+
LLScrollListItem* LLScrollListCtrl::getItemByIndex(S32 index)
{
if (index >= 0 && index < (S32)mItemList.size())
diff --git a/indra/llui/llscrolllistctrl.h b/indra/llui/llscrolllistctrl.h
index d3735c5052..b8d63972a5 100644
--- a/indra/llui/llscrolllistctrl.h
+++ b/indra/llui/llscrolllistctrl.h
@@ -262,7 +262,8 @@ public:
bool selectItemByLabel(const std::string& item, bool case_sensitive = true, S32 column = 0); // false if item not found
bool selectItemByPrefix(const std::string& target, bool case_sensitive = true, S32 column = -1);
bool selectItemByPrefix(const LLWString& target, bool case_sensitive = true, S32 column = -1);
- LLScrollListItem* getItemByLabel(const std::string& item, bool case_sensitive = true, S32 column = 0);
+ LLScrollListItem* getItemByLabel(const std::string& label, bool case_sensitive = true, S32 column = 0);
+ LLScrollListItem* getItemByValue(const std::string& value);
LLScrollListItem* getItemByIndex(S32 index);
std::string getSelectedItemLabel(S32 column = 0) const;
LLSD getSelectedValue();