summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2025-03-14 16:08:42 +0200
committerGitHub <noreply@github.com>2025-03-14 16:08:42 +0200
commite2333b4d312301206f80f60e9c2f0258bc8e6235 (patch)
treef85fc4db056330c8cfb63d4e3045b77db182facd
parent7aad509d19c75277519dbcf119c3ba2e1f8a9c7c (diff)
parentda0a819d64514cad17cf306c3ebe2ac79db8283a (diff)
Merge pull request #3701 from secondlife/marchcat/lua_editor
Lua editor: WIP updates
-rw-r--r--indra/llui/llkeywords.cpp92
-rw-r--r--indra/newview/app_settings/keywords_lua_default.xml7
-rw-r--r--indra/newview/llpreviewscript.cpp71
-rw-r--r--indra/newview/llpreviewscript.h33
-rw-r--r--indra/newview/llscripteditor.cpp8
-rw-r--r--indra/newview/llscripteditor.h3
-rw-r--r--indra/newview/skins/default/xui/en/panel_script_ed.xml10
7 files changed, 132 insertions, 92 deletions
diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp
index a81cd8affb..7064e270a4 100644
--- a/indra/llui/llkeywords.cpp
+++ b/indra/llui/llkeywords.cpp
@@ -359,8 +359,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");
@@ -675,35 +678,86 @@ 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 == '_')
- || (mLuauLanguage && *p == '.') ) // Allow dots in Lua to pass the functions. For example, "ll.Say()" instead of "llSay()" in LSL
+ 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)
+ WStringMapIndex whole_token(word_start, seg_len);
+ word_token_map_t::iterator map_iter = mWordTokenMap.find(whole_token);
+
+ if (map_iter != mWordTokenMap.end())
{
+ // Found a match for the complete token (including any namespace)
LLKeywordToken* cur_token = map_iter->second;
- S32 seg_start = (S32)(cur - base);
- S32 seg_end = seg_start + seg_len;
+ insertSegments(wtext, *seg_list, cur_token, text_len, seg_start, seg_end, style, editor);
+ }
+ else if (namespace_dots > 0 && mLuauLanguage)
+ {
+ // 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);
+ WStringMapIndex prefix_token(word_start, prefix_len);
+ map_iter = mWordTokenMap.find(prefix_token);
+
+ 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);
- // LL_INFOS("SyntaxLSL") << "Seg: [" << word.c_str() << "]" << LL_ENDL;
+ // Now try to match the function part (after the dot)
+ const llwchar* func_part = last_dot + 1;
+ S32 func_len = (S32)(cur - func_part);
- insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor);
+ if (func_len > 0)
+ {
+ // Look for complete function matches
+ WStringMapIndex func_token(func_part, func_len);
+ map_iter = mWordTokenMap.find(func_token);
+
+ 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
+ }
+ }
+ }
+ }
}
- cur += seg_len;
- continue;
+ continue; // Continue to next token regardless of match
}
}
- if( *cur && *cur != '\n' )
+ if (*cur && *cur != '\n')
{
cur++;
}
diff --git a/indra/newview/app_settings/keywords_lua_default.xml b/indra/newview/app_settings/keywords_lua_default.xml
index d667e05501..d4b3d3476b 100644
--- a/indra/newview/app_settings/keywords_lua_default.xml
+++ b/indra/newview/app_settings/keywords_lua_default.xml
@@ -7454,6 +7454,13 @@
</map>
<key>functions</key><!-- TODO: Adjust functions to match the new format -->
<map>
+ <key>ll</key>
+ <map>
+ <key>energy</key>
+ <real>-1.0</real>
+ <key>tooltip</key>
+ <string>ll namespace.</string>
+ </map>
<key>ll.Abs</key>
<map>
<key>energy</key>
diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp
index 28988f9564..98c28ffadc 100644
--- a/indra/newview/llpreviewscript.cpp
+++ b/indra/newview/llpreviewscript.cpp
@@ -90,20 +90,8 @@
#include "lltoggleablemenu.h"
#include "llmenubutton.h"
#include "llinventoryfunctions.h"
+#include <regex>
-const std::string HELLO_LSL =
- "default\n"
- "{\n"
- " state_entry()\n"
- " {\n"
- " llSay(0, \"Hello, Avatar!\");\n"
- " }\n"
- "\n"
- " touch_start(integer total_number)\n"
- " {\n"
- " llSay(0, \"Touched.\");\n"
- " }\n"
- "}\n";
const std::string HELP_LSL_PORTAL_TOPIC = "LSL_Portal";
const std::string DEFAULT_SCRIPT_NAME = "New Script"; // *TODO:Translate?
@@ -142,6 +130,19 @@ static bool have_lua_enabled(const LLUUID& object_id)
return false;
}
+// TEMPORARY: Quick check to see if the code is Lua
+// since we don't have another way to determine the language yet
+static bool is_lua_script(const std::string& code)
+{
+ // Check for LSL's signature "default" state pattern
+ std::regex lsl_pattern("\\s*default\\s*\\{");
+ if (std::regex_search(code, lsl_pattern))
+ return false;
+
+ // "default" state not found, assuming it's Lua
+ return true;
+}
+
/// ---------------------------------------------------------------------------
/// LLLiveLSLFile
/// ---------------------------------------------------------------------------
@@ -396,9 +397,9 @@ LLScriptEdCore::LLScriptEdCore(
LLScriptEdContainer* container,
const std::string& sample,
const LLHandle<LLFloater>& floater_handle,
- void (*load_callback)(void*),
- void (*save_callback)(void*, bool),
- void (*search_replace_callback) (void* userdata),
+ script_ed_callback_t load_callback,
+ save_callback_t save_callback,
+ script_ed_callback_t search_replace_callback,
void* userdata,
bool live,
S32 bottom_pad)
@@ -1617,7 +1618,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata)
self->mScriptEd = new LLScriptEdCore(
self,
- HELLO_LSL,
+ std::string(),
self->getHandle(),
LLPreviewLSL::onLoad,
LLPreviewLSL::onSave,
@@ -1758,12 +1759,6 @@ void LLPreviewLSL::loadAsset()
getChildView("lock")->setVisible( !is_modifiable);
mScriptEd->getChildView("Insert...")->setEnabled(is_modifiable);
}
- else
- {
- mScriptEd->setScriptText(std::string(HELLO_LSL), true);
- mScriptEd->setEnableEditing(true);
- mAssetStatus = PREVIEW_ASSET_LOADED;
- }
}
@@ -1942,6 +1937,12 @@ void LLPreviewLSL::onLoadComplete(const LLUUID& asset_uuid, LLAssetType::EType t
preview->mScriptEd->setEnableEditing(is_modifiable);
preview->mScriptEd->setAssetID(asset_uuid);
preview->mAssetStatus = PREVIEW_ASSET_LOADED;
+
+ // Temporary hack to determine if the script is LSL or SLua when loaded from the inventory.
+ bool is_lua = is_lua_script(std::string(buffer.begin(), buffer.end()));
+ preview->mScriptEd->mEditor->setLuauLanguage(is_lua);
+ preview->mScriptEd->mCompileTarget->setValue(is_lua ? "luau" : "lsl-luau");
+ preview->mScriptEd->processKeywords(is_lua);
}
else
{
@@ -1979,7 +1980,7 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata)
self->mScriptEd = new LLScriptEdCore(
self,
- HELLO_LSL,
+ std::string(),
self->getHandle(),
&LLLiveLSLEditor::onLoad,
&LLLiveLSLEditor::onSave,
@@ -2007,7 +2008,7 @@ LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) :
bool LLLiveLSLEditor::postBuild()
{
- mResetButton = getChild<LLButton>("reset");
+ mResetButton = getChild<LLButton>("Reset");
mResetButton->setClickedCallback([&](LLUICtrl*, const LLSD&) { onReset(); });
mRunningCheckbox = getChild<LLCheckBoxCtrl>("running");
@@ -2153,26 +2154,6 @@ void LLLiveLSLEditor::loadAsset()
*/
}
}
- else
- {
- mScriptEd->setScriptText(std::string(HELLO_LSL), true);
- mScriptEd->enableSave(false);
- LLPermissions perm;
- perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, gAgent.getGroupID());
- perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, PERM_MOVE | PERM_TRANSFER);
- mItem = new LLViewerInventoryItem(mItemUUID,
- mObjectUUID,
- perm,
- LLUUID::null,
- LLAssetType::AT_LSL_TEXT,
- LLInventoryType::IT_LSL,
- DEFAULT_SCRIPT_NAME,
- DEFAULT_SCRIPT_DESC,
- LLSaleInfo::DEFAULT,
- LLInventoryItemFlags::II_FLAGS_NONE,
- time_corrected());
- mAssetStatus = PREVIEW_ASSET_LOADED;
- }
requestExperiences();
}
diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h
index 430ca4cc76..117be03fc6 100644
--- a/indra/newview/llpreviewscript.h
+++ b/indra/newview/llpreviewscript.h
@@ -82,15 +82,19 @@ class LLScriptEdCore : public LLPanel
friend class LLScriptEdContainer;
friend class LLFloaterGotoLine;
+public:
+ typedef boost::function<void(void*)> script_ed_callback_t;
+ typedef boost::function<void(void*, bool)> save_callback_t;
+
protected:
// Supposed to be invoked only by the container.
LLScriptEdCore(
LLScriptEdContainer* container,
const std::string& sample,
const LLHandle<LLFloater>& floater_handle,
- void (*load_callback)(void* userdata),
- void (*save_callback)(void* userdata, bool close_after_save),
- void (*search_replace_callback)(void* userdata),
+ script_ed_callback_t load_callback,
+ save_callback_t save_callback,
+ script_ed_callback_t search_replace_callback,
void* userdata,
bool live,
S32 bottom_pad = 0); // pad below bottom row of buttons
@@ -139,11 +143,11 @@ public:
LLUUID getAssociatedExperience()const;
void setAssociatedExperience( const LLUUID& experience_id );
- void setScriptName(const std::string& name){mScriptName = name;};
+ void setScriptName(const std::string& name) { mScriptName = name; }
- void setItemRemoved(bool script_removed){mScriptRemoved = script_removed;};
+ void setItemRemoved(bool script_removed) { mScriptRemoved = script_removed; }
- void setAssetID( const LLUUID& asset_id){ mAssetID = asset_id; };
+ void setAssetID(const LLUUID& asset_id) { mAssetID = asset_id; }
LLUUID getAssetID() { return mAssetID; }
bool isFontSizeChecked(const LLSD &userdata);
@@ -152,16 +156,15 @@ public:
virtual bool handleKeyHere(KEY key, MASK mask);
void selectAll() { mEditor->selectAll(); }
+ void enableSave(bool b) { mEnableSave = b; }
+ bool hasChanged();
+
private:
void onBtnDynamicHelp();
void onBtnUndoChanges();
- bool hasChanged();
-
void selectFirstError();
- void enableSave(bool b) {mEnableSave = b;}
-
protected:
void deleteBridges();
void setHelpPage(const std::string& help_string);
@@ -176,9 +179,9 @@ private:
std::string mSampleText;
std::string mScriptName;
LLScriptEditor* mEditor;
- void (*mLoadCallback)(void* userdata);
- void (*mSaveCallback)(void* userdata, bool close_after_save);
- void (*mSearchReplaceCallback) (void* userdata);
+ script_ed_callback_t mLoadCallback;
+ save_callback_t mSaveCallback;
+ script_ed_callback_t mSearchReplaceCallback;
void* mUserdata;
LLComboBox *mFunctions;
bool mForceClose;
@@ -204,7 +207,6 @@ private:
public:
boost::signals2::connection mSyntaxIDConnection;
-
};
class LLScriptEdContainer : public LLPreview
@@ -269,10 +271,8 @@ protected:
S32 mPendingUploads;
LLScriptMovedObserver* mItemObserver;
-
};
-
// Used to view and edit an LSL script that is attached to an object.
class LLLiveLSLEditor : public LLScriptEdContainer
{
@@ -280,7 +280,6 @@ class LLLiveLSLEditor : public LLScriptEdContainer
public:
LLLiveLSLEditor(const LLSD& key);
-
static void processScriptRunningReply(LLMessageSystem* msg, void**);
virtual void callbackLSLCompileSucceeded(const LLUUID& task_id,
diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp
index 0edaf43753..2a9dd73936 100644
--- a/indra/newview/llscripteditor.cpp
+++ b/indra/newview/llscripteditor.cpp
@@ -45,7 +45,8 @@ LLScriptEditor::Params::Params()
LLScriptEditor::LLScriptEditor(const Params& p)
: LLTextEditor(p)
, mShowLineNumbers(p.show_line_numbers),
- mUseDefaultFontSize(p.default_font_size)
+ mUseDefaultFontSize(p.default_font_size),
+ mLuauLanguage(false)
{
if (mShowLineNumbers)
{
@@ -200,12 +201,12 @@ void LLScriptEditor::clearSegments()
LLKeywords::keyword_iterator_t LLScriptEditor::keywordsBegin()
{
- return mLuauLanguage ? mKeywordsLua.begin() : mKeywordsLSL.begin();
+ return getKeywords().begin();
}
LLKeywords::keyword_iterator_t LLScriptEditor::keywordsEnd()
{
- return mLuauLanguage ? mKeywordsLua.end() : mKeywordsLSL.end();
+ return getKeywords().end();
}
LLKeywords& LLScriptEditor::getKeywords()
@@ -237,7 +238,6 @@ void LLScriptEditor::drawSelectionBackground()
++rect_it)
{
LLRect selection_rect = *rect_it;
- selection_rect = *rect_it;
selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom);
gl_rect_2d(selection_rect, selection_color);
}
diff --git a/indra/newview/llscripteditor.h b/indra/newview/llscripteditor.h
index ad61405917..ba44d77ea0 100644
--- a/indra/newview/llscripteditor.h
+++ b/indra/newview/llscripteditor.h
@@ -54,6 +54,7 @@ public:
LLKeywords::keyword_iterator_t keywordsEnd();
LLKeywords& getKeywords();
bool getIsLuauLanguage() { return mLuauLanguage; }
+ void setLuauLanguage(bool luau_language) { mLuauLanguage = luau_language; }
static std::string getScriptFontSize();
LLFontGL* getScriptFont();
@@ -67,8 +68,6 @@ private:
void drawLineNumbers();
/* virtual */ void updateSegments();
/* virtual */ void drawSelectionBackground();
- void loadKeywords(const std::string& filename_keywords,
- const std::string& filename_colors);
LLKeywords mKeywordsLua;
LLKeywords mKeywordsLSL;
diff --git a/indra/newview/skins/default/xui/en/panel_script_ed.xml b/indra/newview/skins/default/xui/en/panel_script_ed.xml
index 3f1aeeb626..2ccf379b8d 100644
--- a/indra/newview/skins/default/xui/en/panel_script_ed.xml
+++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml
@@ -250,13 +250,13 @@
name="compile_target_mono"
value="mono" />
<combo_box.item
- label="Lua"
- name="compile_target_luau"
- value="luau" />
- <combo_box.item
- label="LSL/Luau"
+ label="LSL: 2025 VM"
name="compile_target_lsl_luau"
value="lsl-luau" />
+ <combo_box.item
+ label="SLua"
+ name="compile_target_luau"
+ value="luau" />
</combo_box>
<text
name="compile_target_label"