chore: update the file

This commit is contained in:
x-tools-author 2025-09-15 14:32:00 +08:00
parent 02f575b7a0
commit b4a5f19807
9 changed files with 172 additions and 25 deletions

View File

@ -59,6 +59,7 @@ message(STATUS "[xTools]CMAKE_CXX_COMPILER_VERSION: ${CMAKE_CXX_COMPILER_VERSION
# Qt module
list(APPEND X_QT_COMPONENTS Gui)
list(APPEND X_QT_COMPONENTS Svg)
list(APPEND X_QT_COMPONENTS Qml)
list(APPEND X_QT_COMPONENTS Core)
list(APPEND X_QT_COMPONENTS Widgets)
list(APPEND X_QT_COMPONENTS Network)
@ -84,6 +85,7 @@ if(QT_VERSION VERSION_GREATER_EQUAL "6.10.0")
endif()
list(APPEND X_LIBS Qt${QT_VERSION_MAJOR}::Network)
list(APPEND X_LIBS Qt${QT_VERSION_MAJOR}::Svg)
list(APPEND X_LIBS Qt${QT_VERSION_MAJOR}::Qml)
list(APPEND X_LIBS Qt${QT_VERSION_MAJOR}::Widgets)
# --------------------------------------------------------------------------------------------------
@ -212,7 +214,7 @@ x_add_executable(xTools ${X_SOURCES})
target_link_libraries(xTools PRIVATE ${X_LIBS})
x_output_env(xTools)
x_deploy_qt(xTools)
x_deploy_lua(xTools)
x_deploy_resources(xTools)
# xTools modules
x_generate_module_translations(common ${CMAKE_CURRENT_SOURCE_DIR}/src/common ON)
x_generate_module_translations(device ${CMAKE_CURRENT_SOURCE_DIR}/src/device ON)

View File

@ -154,3 +154,16 @@ function(x_install_3rd_library target_name dir_name)
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/3rd/${dir_name}
COMMENT "Deploy 3rd libraries")
endfunction()
function(x_deploy_resources TARGET)
set(dst_dir $<TARGET_FILE_DIR:${TARGET}>/scripts)
if(APPLE)
set(dst_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/../Resources/scripts)
endif()
make_directory(${dst_dir})
add_custom_command(
TARGET ${TARGET}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res/scripts ${dst_dir}
COMMENT "Copy lua scripts to output dir")
endfunction()

View File

@ -81,16 +81,3 @@ if(MSVC AND X_ENABLE_LUA_APP)
# cmake-format: on
endif()
endif()
function(x_deploy_lua TARGET)
set(dst_dir $<TARGET_FILE_DIR:${TARGET}>/scripts)
if(APPLE)
set(dst_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/../Resources/scripts)
endif()
make_directory(${dst_dir})
add_custom_command(
TARGET ${TARGET}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/res/scripts ${dst_dir}
COMMENT "Copy lua scripts to output dir")
endfunction()

View File

@ -20,8 +20,6 @@ ScriptBase::ScriptBase(QWidget *parent)
, ui(new Ui::ScriptBase)
{
ui->setupUi(this);
ui->toolButtonRun->setCheckable(true);
connect(ui->comboBoxFile,
qOverload<int>(&QComboBox::currentIndexChanged),
this,
@ -136,11 +134,10 @@ void ScriptBase::onScriptComboBoxCurrentIndexChanged()
void ScriptBase::onRunButtonClicked(bool checked)
{
ui->toolButtonRun->setEnabled(false);
if (checked) {
startRunner();
} else {
if (m_runner) {
stopRunner();
} else {
startRunner();
}
}
@ -150,9 +147,13 @@ void ScriptBase::onNewButtonClicked()
tr("New Script"),
tr("Please input the script name:"),
QLineEdit::Normal,
QString("NewScript") + QString(".") + scriptSuffix(),
QString("NewScript"),
nullptr,
Qt::WindowCloseButtonHint);
if (txt.isEmpty()) {
return;
}
if (!txt.endsWith('.' + scriptSuffix())) {
txt += '.' + scriptSuffix();
}
@ -243,6 +244,8 @@ void ScriptBase::onRunnerStarted()
void ScriptBase::onRunnerFinished()
{
stopRunner();
ui->toolButtonRun->setEnabled(true);
updateUiEnabled(false);

View File

@ -8,10 +8,132 @@
**************************************************************************************************/
#include "scriptrunnerjs.h"
#include <QDebug>
#include <QEventLoop>
#include <QFile>
#include <QTimer>
ScriptRunnerJs::ScriptRunnerJs(QObject *parent)
: ScriptRunner(parent)
{}
ScriptRunnerJs::~ScriptRunnerJs() {}
void ScriptRunnerJs::run() {}
void ScriptRunnerJs::onBytesRead(const QByteArray &data)
{
if (data.isEmpty()) {
return;
}
if (m_engine == nullptr) {
return;
}
QJSValue jsFunc = m_engine->globalObject().property("onBytesRead");
if (jsFunc.isCallable()) {
QJSValueList args;
args << QString::fromUtf8(data);
QJSValue result = jsFunc.call(args);
if (result.isError()) {
QString errorMsg = tr("Uncaught exception at line %1: %2")
.arg(result.property("lineNumber").toInt())
.arg(result.toString());
emit logOutput(errorMsg);
}
}
}
void ScriptRunnerJs::xWriteBytes(const QJSValue &value)
{
if (value.isString()) {
emit invokeWrite(value.toString().toUtf8());
} else if (value.isArray()) {
QJSValue lengthValue = value.property("length");
if (lengthValue.isNumber()) {
int length = lengthValue.toInt();
QByteArray byteArray;
byteArray.reserve(length);
for (int i = 0; i < length; ++i) {
QJSValue element = value.property(i);
if (element.isNumber()) {
int byte = element.toInt();
if (byte < 0 || byte > 255) {
emit logOutput(tr("Array element at index %1 is out of byte range: %2")
.arg(i)
.arg(byte));
return;
}
byteArray.append(static_cast<char>(byte));
} else {
emit logOutput(tr("Array element at index %1 is not a number").arg(i));
return;
}
}
emit invokeWrite(byteArray);
} else {
emit logOutput(tr("The 'length' property of the array is not a number"));
}
} else {
emit logOutput(tr("xWriteBytes expects a string or an array of bytes"));
}
}
bool ScriptRunnerJs::xIsInterruptionRequested()
{
return isInterruptionRequested();
}
void ScriptRunnerJs::xSleep(int ms)
{
if (ms <= 0) {
ms = 10;
}
QEventLoop loop;
QTimer timer;
timer.setSingleShot(true);
connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
timer.start(ms);
loop.exec();
}
void ScriptRunnerJs::xPrint(const QString &text)
{
emit logOutput(text);
}
void ScriptRunnerJs::run()
{
QFile scriptFile(m_scriptFile);
if (!scriptFile.open(QIODevice::ReadOnly)) {
emit logOutput(tr("Cannot open script file: %1").arg(m_scriptFile));
return;
}
QString script = QString::fromUtf8(scriptFile.readAll());
scriptFile.close();
m_engine = new QJSEngine();
m_engine->installExtensions(QJSEngine::AllExtensions);
QJSValue obj = m_engine->newQObject(this);
m_engine->globalObject().setProperty("jsRunner", obj);
QStringList exceptionStack;
QJSValue result = m_engine->evaluate(script, m_scriptFile, 1, &exceptionStack);
if (result.isError()) {
QString errorMsg = tr("Uncaught exception at line %1: %2")
.arg(result.property("lineNumber").toInt())
.arg(result.toString());
emit logOutput(errorMsg);
if (!exceptionStack.isEmpty()) {
emit logOutput(tr("Stack trace:"));
for (const QString &line : qAsConst(exceptionStack)) {
emit logOutput(line);
}
}
} else {
emit logOutput(tr("Script executed successfully."));
}
m_engine->deleteLater();
m_engine = nullptr;
}

View File

@ -8,6 +8,9 @@
**************************************************************************************************/
#pragma once
#include <QJsEngine>
#include <QJsValue>
#include "scriptrunner.h"
class ScriptRunnerJs : public ScriptRunner
@ -17,6 +20,16 @@ public:
explicit ScriptRunnerJs(QObject *parent = nullptr);
~ScriptRunnerJs();
void onBytesRead(const QByteArray &data) override;
Q_INVOKABLE void xWriteBytes(const QJSValue &value);
Q_INVOKABLE bool xIsInterruptionRequested();
Q_INVOKABLE void xSleep(int ms);
Q_INVOKABLE void xPrint(const QString &text);
protected:
void run() override;
private:
QJSEngine *m_engine{nullptr};
};

View File

@ -60,7 +60,6 @@ void ScriptRunnerLua::run()
lua_pop(m_lua, 1); // Remove error message from the stack
}
exec();
lua_close(m_lua);
m_lua = nullptr;
}

View File

@ -39,6 +39,12 @@ void ScriptsManager::load(const QJsonObject &obj)
ScriptsManagerParameterKeys keys;
m_lua->load(obj.value(keys.lua).toObject(QJsonObject()));
m_js->load(obj.value(keys.js).toObject(QJsonObject()));
int index = obj.value(keys.tabIndex).toInt(0);
if (index < 0 || index >= ui->tabWidget->count()) {
index = 0;
}
ui->tabWidget->setCurrentIndex(index);
}
QJsonObject ScriptsManager::save()
@ -47,6 +53,7 @@ QJsonObject ScriptsManager::save()
QJsonObject obj;
obj.insert(keys.lua, m_lua->save());
obj.insert(keys.js, m_js->save());
obj.insert(keys.tabIndex, ui->tabWidget->currentIndex());
return obj;
}

View File

@ -18,8 +18,9 @@ class ScriptsManager;
struct ScriptsManagerParameterKeys
{
const QString lua = QStringLiteral("lua");
const QString js = QStringLiteral("js");
const QString tabIndex{"tabIndex"};
const QString lua{"lua"};
const QString js{"js"};
};
class ScriptLua;