Skip to content

SLua editor: Better strings and logs for external editors #3860

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions indra/llui/llkeywords.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,8 @@ void LLKeywords::processTokens()

if (mLuauLanguage)
{
addToken(LLKeywordToken::TT_DOUBLE_QUOTATION_MARKS, "\'", LLUIColorTable::instance().getColor("SyntaxLslStringLiteral"), "String literal", "\'");
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
Expand Down Expand Up @@ -595,10 +597,8 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW

std::string text_to_search(wtext.begin() + seg_start, wtext.end());

for (token_list_t::iterator iter = mRegexTokenList.begin();
iter != mRegexTokenList.end(); ++iter)
for (LLKeywordToken* regex_token : mRegexTokenList)
{
LLKeywordToken* regex_token = *iter;
std::string start_pattern(regex_token->getToken().begin(), regex_token->getToken().end());
std::string end_pattern(regex_token->getDelimiter().begin(), regex_token->getDelimiter().end());

Expand Down
119 changes: 109 additions & 10 deletions indra/newview/llpreviewscript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "llslider.h"
#include "lltooldraganddrop.h"
#include "llfilesystem.h"
#include "lllogchat.h"

#include "llagent.h"
#include "llmenugl.h"
Expand Down Expand Up @@ -415,7 +416,6 @@ LLScriptEdCore::LLScriptEdCore(
mLastHelpToken(NULL),
mLiveHelpHistorySize(0),
mEnableSave(false),
mLiveFile(NULL),
mLive(live),
mContainer(container),
mHasScriptData(false),
Expand Down Expand Up @@ -447,7 +447,6 @@ LLScriptEdCore::~LLScriptEdCore()
}
}

delete mLiveFile;
if (mSyntaxIDConnection.connected())
{
mSyntaxIDConnection.disconnect();
Expand Down Expand Up @@ -730,13 +729,13 @@ bool LLScriptEdCore::writeToFile(const std::string& filename)
void LLScriptEdCore::sync()
{
// Sync with external editor.
if (mLiveFile)
if (mContainer->mLiveFile)
{
std::string tmp_file = mLiveFile->filename();
std::string tmp_file = mContainer->mLiveFile->filename();
llstat s;
if (LLFile::stat(tmp_file, &s) == 0) // file exists
{
mLiveFile->ignoreNextUpdate();
mContainer->mLiveFile->ignoreNextUpdate();
writeToFile(tmp_file);
}
}
Expand Down Expand Up @@ -1121,7 +1120,11 @@ void LLScriptEdCore::doSave( bool close_after_save )

void LLScriptEdCore::openInExternalEditor()
{
delete mLiveFile; // deletes file
if (mContainer->mLiveFile)
{
// If already open in an external editor, just return
return;
}

// Generate a suitable filename
std::string script_name = mScriptName;
Expand All @@ -1144,8 +1147,8 @@ void LLScriptEdCore::openInExternalEditor()
}

// Start watching file changes.
mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1));
mLiveFile->addToEventTimer();
mContainer->mLiveFile = new LLLiveLSLFile(filename, boost::bind(&LLScriptEdContainer::onExternalChange, mContainer, _1));
mContainer->mLiveFile->addToEventTimer();

// Open it in external editor.
{
Expand Down Expand Up @@ -1420,8 +1423,8 @@ void LLLiveLSLEditor::updateExperiencePanel()
{
mExperienceEnabled->setToolTip(getString("experience_enabled"));
mExperienceEnabled->setEnabled(getIsModifiable());
mExperiences->setVisible(true);
mExperienceEnabled->set(true);
mExperiences->setVisible(true);
mViewProfileButton->setToolTip(getString("show_experience_profile"));
buildExperienceList();
}
Expand Down Expand Up @@ -1541,10 +1544,21 @@ void LLLiveLSLEditor::receiveExperienceIds(LLSD result, LLHandle<LLLiveLSLEditor

LLScriptEdContainer::LLScriptEdContainer(const LLSD& key) :
LLPreview(key)
, mScriptEd(NULL)
, mScriptEd(nullptr)
, mLiveFile(nullptr)
, mLiveLogFile(nullptr)
{
}

LLScriptEdContainer::~LLScriptEdContainer()
{
delete mLiveFile;
mLiveFile = nullptr;

delete mLiveLogFile;
mLiveLogFile = nullptr;
}

std::string LLScriptEdContainer::getTmpFileName(const std::string& script_name)
{
// Take script inventory item id (within the object inventory)
Expand All @@ -1569,6 +1583,60 @@ std::string LLScriptEdContainer::getTmpFileName(const std::string& script_name)
}
}

std::string LLScriptEdContainer::getErrorLogFileName(const std::string& script_path)
{
if (script_path.empty())
{
return std::string();
}

return script_path + ".log";
}

bool LLScriptEdContainer::logErrorsToFile(const LLSD& compile_errors)
{
if (!isOpenInExternalEditor())
{
return false;
}

std::string script_path = getTmpFileName(mScriptEd->mScriptName);
std::string log_path = getErrorLogFileName(script_path);

llofstream file(log_path.c_str());
if (!file.is_open())
{
LL_WARNS() << "Unable to open error log file: " << log_path << LL_ENDL;
return false;
}

// Write timestamp
std::string timestamp = LLLogChat::timestamp2LogString(0, true);
file << "// " << timestamp << "\n\n";

// Write errors
for (LLSD::array_const_iterator line = compile_errors.beginArray();
line < compile_errors.endArray();
line++)
{
std::string error_message = line->asString();
LLStringUtil::stripNonprintable(error_message);
file << error_message << "\n";
}

file.close();

// Create a log file handler if we don't already have one,
// this is needed to delete the temporary log file properly
if (!mLiveLogFile && !log_path.empty())
{
// Empty callback since we don't need to react to file changes
mLiveLogFile = new LLLiveLSLFile(log_path, [](const std::string& filename) { return true; });
}

return true;
}

bool LLScriptEdContainer::onExternalChange(const std::string& filename)
{
if (!mScriptEd->loadScriptText(filename))
Expand Down Expand Up @@ -1692,6 +1760,15 @@ void LLPreviewLSL::callbackLSLCompileSucceeded()
LL_INFOS() << "LSL Bytecode saved" << LL_ENDL;
mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful"));
mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete"));

if (isOpenInExternalEditor())
{
LLSD success_msg;
success_msg.append(LLTrans::getString("CompileSuccessful"));
success_msg.append(LLTrans::getString("SaveComplete"));
logErrorsToFile(success_msg);
}

closeIfNeeded();
}

Expand All @@ -1711,6 +1788,12 @@ void LLPreviewLSL::callbackLSLCompileFailed(const LLSD& compile_errors)
row["columns"][0]["font"] = "OCRA";
mScriptEd->mErrorList->addElement(row);
}

if (isOpenInExternalEditor())
{
logErrorsToFile(compile_errors);
}

mScriptEd->selectFirstError();
closeIfNeeded();
}
Expand Down Expand Up @@ -2042,6 +2125,15 @@ void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
LL_DEBUGS() << "LSL Bytecode saved" << LL_ENDL;
mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful"));
mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete"));

if (isOpenInExternalEditor())
{
LLSD success_msg;
success_msg.append(LLTrans::getString("CompileSuccessful"));
success_msg.append(LLTrans::getString("SaveComplete"));
logErrorsToFile(success_msg);
}

mRunningCheckbox->set(is_script_running);
mIsSaving = false;
closeIfNeeded();
Expand All @@ -2051,6 +2143,7 @@ void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id,
void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors)
{
LL_DEBUGS() << "Compile failed!" << LL_ENDL;

for(LLSD::array_const_iterator line = compile_errors.beginArray();
line < compile_errors.endArray();
line++)
Expand All @@ -2063,6 +2156,12 @@ void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors)
row["columns"][0]["font"] = "OCRA";
mScriptEd->mErrorList->addElement(row);
}

if (isOpenInExternalEditor())
{
logErrorsToFile(compile_errors);
}

mScriptEd->selectFirstError();
mIsSaving = false;
closeIfNeeded();
Expand Down
8 changes: 6 additions & 2 deletions indra/newview/llpreviewscript.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,6 @@ class LLScriptEdCore : public LLPanel
S32 mLiveHelpHistorySize;
bool mEnableSave;
bool mHasScriptData;
LLLiveLSLFile* mLiveFile;
LLUUID mAssociatedExperience;
bool mScriptRemoved;
bool mSaveDialogShown;
Expand All @@ -215,16 +214,21 @@ class LLScriptEdContainer : public LLPreview

public:
LLScriptEdContainer(const LLSD& key);
LLScriptEdContainer(const LLSD& key, const bool live);
virtual ~LLScriptEdContainer();

bool handleKeyHere(KEY key, MASK mask);

protected:
std::string getTmpFileName(const std::string& script_name);
std::string getErrorLogFileName(const std::string& script_path);
bool onExternalChange(const std::string& filename);
virtual void saveIfNeeded(bool sync = true) = 0;
bool logErrorsToFile(const LLSD& compile_errors);
bool isOpenInExternalEditor() const { return mLiveFile != nullptr; }

LLScriptEdCore* mScriptEd;
LLLiveLSLFile* mLiveFile = nullptr;
LLLiveLSLFile* mLiveLogFile = nullptr;
};

// Used to view and edit an LSL script from your inventory.
Expand Down