diff options
| author | 2023-04-30 18:30:36 -0400 | |
|---|---|---|
| committer | 2023-04-30 18:30:36 -0400 | |
| commit | 3565aad630864ecdbe53fdaa501ea708555b3c7c (patch) | |
| tree | c743e4ad0bad39ebdb2f514c7cc52d34a257ebbe /SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp | |
| parent | 1fdc150116cad39aae5c5da407c3312b47a59e3a (diff) | |
New upstream version 3.4.4+dfsg.upstream/3.4.4+dfsg
Diffstat (limited to 'SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp')
| -rw-r--r-- | SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp | 157 |
1 files changed, 91 insertions, 66 deletions
diff --git a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp index f88fa85..5305f24 100644 --- a/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp +++ b/SQLiteStudio3/coreSQLiteStudio/plugins/scriptingqt.cpp @@ -1,42 +1,39 @@ #include "scriptingqt.h" -#include "common/unused.h" #include "common/global.h" #include "scriptingqtdbproxy.h" -#include <QScriptEngine> +#include "services/notifymanager.h" +#include <QJSEngine> #include <QMutex> #include <QMutexLocker> #include <QDebug> -static QScriptValue scriptingQtDebug(QScriptContext *context, QScriptEngine *engine) +ScriptingQt::ScriptingQt() { - UNUSED(engine); - QStringList args; - for (int i = 0; i < context->argumentCount(); i++) - args << context->argument(i).toString(); - - qDebug() << "[ScriptingQt]" << args; - return QScriptValue(); + managedMainContextsMutex = new QMutex(); } -ScriptingQt::ScriptingQt() +ScriptingQt::~ScriptingQt() { - mainEngineMutex = new QMutex(); + safe_delete(managedMainContextsMutex); } -ScriptingQt::~ScriptingQt() +QJSValueList ScriptingQt::toValueList(QJSEngine* engine, const QList<QVariant>& values) { - safe_delete(mainEngineMutex); + QJSValueList result; + for (const QVariant& value : values) + result << engine->toScriptValue(value); + + return result; } QString ScriptingQt::getLanguage() const { - return QStringLiteral("QtScript"); + return QStringLiteral("JavaScript"); } ScriptingPlugin::Context* ScriptingQt::createContext() { ContextQt* ctx = new ContextQt; - ctx->engine->pushContext(); contexts << ctx; return ctx; } @@ -56,60 +53,54 @@ void ScriptingQt::resetContext(ScriptingPlugin::Context* context) ContextQt* ctx = getContext(context); if (!ctx) return; - - ctx->engine->popContext(); - ctx->engine->pushContext(); } -QVariant ScriptingQt::evaluate(const QString& code, const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage) +QVariant ScriptingQt::evaluate(const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking, QString* errorMessage) { - QMutexLocker locker(mainEngineMutex); - - // Enter a new context - QScriptContext* engineContext = mainContext->engine->pushContext(); - // Call the function - QVariant result = evaluate(mainContext, engineContext, code, args, db, locking); + ContextQt* context = getMainContext(); + QVariant result = evaluate(context, code, funcInfo, args, db, locking); // Handle errors - if (!mainContext->error.isEmpty()) - *errorMessage = mainContext->error; - - // Leave the context to reset "this". - mainContext->engine->popContext(); + if (!context->error.isEmpty()) + *errorMessage = context->error; return result; } -QVariant ScriptingQt::evaluate(ScriptingPlugin::Context* context, const QString& code, const QList<QVariant>& args, Db* db, bool locking) +QVariant ScriptingQt::evaluate(ScriptingPlugin::Context* context, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking) { ContextQt* ctx = getContext(context); if (!ctx) return QVariant(); - return evaluate(ctx, ctx->engine->currentContext(), code, args, db, locking); + return evaluate(ctx, code, funcInfo, args, db, locking); } -QVariant ScriptingQt::evaluate(ContextQt* ctx, QScriptContext* engineContext, const QString& code, const QList<QVariant>& args, Db* db, bool locking) +QVariant ScriptingQt::evaluate(ContextQt* ctx, const QString& code, const FunctionInfo& funcInfo, const QList<QVariant>& args, Db* db, bool locking) { // Define function to call - QScriptValue functionValue = getFunctionValue(ctx, code); + QJSValue functionValue = getFunctionValue(ctx, code, funcInfo); // Db for this evaluation ctx->dbProxy->setDb(db); ctx->dbProxy->setUseDbLocking(locking); // Call the function - QScriptValue result; + QJSValue result; if (args.size() > 0) - result = functionValue.call(engineContext->activationObject(), ctx->engine->toScriptValue(args)); + result = functionValue.call(toValueList(ctx->engine, args)); else - result = functionValue.call(engineContext->activationObject()); + result = functionValue.call(); // Handle errors ctx->error.clear(); - if (ctx->engine->hasUncaughtException()) - ctx->error = ctx->engine->uncaughtException().toString(); + if (result.isError()) + { + ctx->error = QString("Uncaught exception at line %1: %2").arg( + result.property("lineNumber").toString(), + result.toString()); + } ctx->dbProxy->setDb(nullptr); ctx->dbProxy->setUseDbLocking(false); @@ -117,6 +108,20 @@ QVariant ScriptingQt::evaluate(ContextQt* ctx, QScriptContext* engineContext, co return convertVariant(result.toVariant()); } +ScriptingQt::ContextQt* ScriptingQt::getMainContext() +{ + if (mainContext.hasLocalData()) + return mainContext.localData(); + + ContextQt* context = new ContextQt(); + mainContext.setLocalData(context); + + QMutexLocker locker(managedMainContextsMutex); + managedMainContexts << context; + + return context; +} + QVariant ScriptingQt::convertVariant(const QVariant& value, bool wrapStrings) { switch (value.type()) @@ -148,7 +153,7 @@ QVariant ScriptingQt::convertVariant(const QVariant& value, bool wrapStrings) case QVariant::List: { QStringList list; - for (const QVariant& var : value.toList()) + for (QVariant& var : value.toList()) list << convertVariant(var, true).toString(); return "[" + list.join(", ") + "]"; @@ -176,7 +181,7 @@ void ScriptingQt::setVariable(ScriptingPlugin::Context* context, const QString& if (!ctx) return; - ctx->engine->globalObject().setProperty(name, ctx->engine->newVariant(value)); + ctx->engine->globalObject().setProperty(name, ctx->engine->toScriptValue(value)); } QVariant ScriptingQt::getVariable(ScriptingPlugin::Context* context, const QString& name) @@ -185,7 +190,7 @@ QVariant ScriptingQt::getVariable(ScriptingPlugin::Context* context, const QStri if (!ctx) return QVariant(); - QScriptValue value = ctx->engine->globalObject().property(name); + QJSValue value = ctx->engine->globalObject().property(name); return convertVariant(value.toVariant()); } @@ -214,20 +219,28 @@ QString ScriptingQt::getIconPath() const bool ScriptingQt::init() { - QMutexLocker locker(mainEngineMutex); - mainContext = new ContextQt; return true; } void ScriptingQt::deinit() { - for (Context* ctx : contexts) + for (Context*& ctx : contexts) delete ctx; contexts.clear(); - QMutexLocker locker(mainEngineMutex); - safe_delete(mainContext); + QMutexLocker locker(managedMainContextsMutex); + for (ContextQt*& ctx : managedMainContexts) + { +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + ctx->engine->setInterrupted(true); +#else + // FIXME No way to cleanly interrupt QJSEngine before Qt 5.14 +#endif + delete ctx; + } + + managedMainContexts.clear(); } ScriptingQt::ContextQt* ScriptingQt::getContext(ScriptingPlugin::Context* context) const @@ -239,31 +252,30 @@ ScriptingQt::ContextQt* ScriptingQt::getContext(ScriptingPlugin::Context* contex return ctx; } -QScriptValue ScriptingQt::getFunctionValue(ContextQt* ctx, const QString& code) +QJSValue ScriptingQt::getFunctionValue(ContextQt* ctx, const QString& code, const FunctionInfo& funcInfo) { - static const QString fnDef = QStringLiteral("(function () {%1\n})"); + static const QString fnDef = QStringLiteral("(function (%1) {%2\n})"); - QScriptProgram* prog = nullptr; - if (!ctx->scriptCache.contains(code)) - { - prog = new QScriptProgram(fnDef.arg(code)); - ctx->scriptCache.insert(code, prog); - } - else - { - prog = ctx->scriptCache[code]; - } - return ctx->engine->evaluate(*prog); + QString fullCode = fnDef.arg(funcInfo.getArguments().join(", "), code); + QJSValue* func = ctx->scriptCache[fullCode]; + if (func) + return *func; + + func = new QJSValue(ctx->engine->evaluate(fullCode)); + ctx->scriptCache.insert(fullCode, func); + return *func; } ScriptingQt::ContextQt::ContextQt() { - engine = new QScriptEngine(); + engine = new QJSEngine(); + engine->installExtensions(QJSEngine::ConsoleExtension); - dbProxy = new ScriptingQtDbProxy(); - dbProxyScriptValue = engine->newQObject(dbProxy, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater); + dbProxy = new ScriptingQtDbProxy(engine); + dbProxyScriptValue = engine->newQObject(dbProxy); + console = new ScriptingQtConsole(engine); - engine->globalObject().setProperty("debug", engine->newFunction(scriptingQtDebug)); + engine->globalObject().setProperty("console", engine->newQObject(console)); engine->globalObject().setProperty("db", dbProxyScriptValue); scriptCache.setMaxCost(cacheSize); @@ -271,6 +283,19 @@ ScriptingQt::ContextQt::ContextQt() ScriptingQt::ContextQt::~ContextQt() { - safe_delete(engine); + safe_delete(console); safe_delete(dbProxy); + safe_delete(engine); +} + +ScriptingQtConsole::ScriptingQtConsole(QJSEngine* engine) : + QObject(), engine(engine) +{ +} + +QJSValue ScriptingQtConsole::log(const QJSValue& value) +{ + static_qstring(tpl, "[JS] %1"); + NOTIFY_MANAGER->info(tpl.arg(ScriptingQt::convertVariant(value.toVariant()).toString())); + return QJSValue(); } |
