feat: 完善脚本的宏支持;

This commit is contained in:
寂静的羽夏 2025-02-11 21:19:05 +08:00
parent 06f48375cf
commit 80691396f3
26 changed files with 2290 additions and 1591 deletions

View File

@ -777,19 +777,6 @@ bool QEditor::save(const QString &fn) {
return true;
}
/*!
\internal
*/
void QEditor::checkClipboard() {
// LOOKS LIKE THIS FUNCTION NEVER GETS CALLED DESPITE THE CONNECTION...
// const QMimeData *d = QApplication::clipboard()->mimeData();
// qDebug("checking clipboard : %s", d);
// QCE_ENABLE_ACTION("paste", d && d->hasText())
}
/*!
\internal
*/

View File

@ -310,7 +310,6 @@ signals:
void inputTimeOuted();
public slots:
void checkClipboard();
void reconnectWatcher();
void fileChanged(const QString &f);

View File

@ -88,8 +88,6 @@ set(ANGEL_SCRIPT_ADDON
${ANGEL_SCRIPT_ADDON_ROOT}/scriptany/scriptany.h
${ANGEL_SCRIPT_ADDON_ROOT}/scriptarray/scriptarray.cpp
${ANGEL_SCRIPT_ADDON_ROOT}/scriptarray/scriptarray.h
${ANGEL_SCRIPT_ADDON_ROOT}/scriptfile/scriptfile.cpp
${ANGEL_SCRIPT_ADDON_ROOT}/scriptfile/scriptfile.h
${ANGEL_SCRIPT_ADDON_ROOT}/scriptgrid/scriptgrid.cpp
${ANGEL_SCRIPT_ADDON_ROOT}/scriptgrid/scriptgrid.h
${ANGEL_SCRIPT_ADDON_ROOT}/scripthandle/scripthandle.cpp
@ -334,7 +332,10 @@ set(SCRIPT_ADDON_SRC
src/scriptaddon/scriptregex.cpp
src/scriptaddon/scriptcolor.h
src/scriptaddon/scriptcolor.cpp
src/scriptaddon/scriptjson.h src/scriptaddon/scriptjson.cpp)
src/scriptaddon/scriptjson.h
src/scriptaddon/scriptjson.cpp
src/scriptaddon/scriptfile.cpp
src/scriptaddon/scriptfile.h)
set(CODEEDIT_WIDGET
src/qcodeeditwidget/qgotolinepanel.h

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -68,9 +68,8 @@ AppManager::AppManager(int &argc, char *argv[])
throw CrashCode::GenericCallNotSupported;
}
Logger::instance();
auto &set = SettingManager::instance();
Logger::instance();
QFont font(set.appFontFamily(), set.appfontSize());
setFont(font);

View File

@ -99,6 +99,10 @@ void AsCompletion::complete(const QDocumentCursor &c, const QString &trigger) {
off = cur.columnNumber();
}
} else {
// TODO: PRs are welcomed !!!
// If this software is well-known or brings me lots of
// financial support, I will implement it myself.
// parse current code
// auto codes = c.document()->text(true, false);
// parser.parse(codes, this->editor()->fileName());

View File

@ -20,6 +20,13 @@
#include <QDir>
#include <QFileInfo>
Q_GLOBAL_STATIC_WITH_ARGS(
QStringList, DEFAULT_MARCO,
({"__AS_ARRAY__", "__AS_ANY__", "__AS_GRID__", "__AS_HANDLE__",
"__AS_MATH__", "__AS_WEAKREF__", "__AS_COROUTINE__", "__WING_FILE__",
"__WING_STRING__", "__WING_COLOR__", "__WING_JSON__", "__WING_REGEX__",
"__WING_DICTIONARY__"}));
AsPreprocesser::AsPreprocesser(asIScriptEngine *engine) : engine(engine) {
Q_ASSERT(engine);
@ -28,6 +35,8 @@ AsPreprocesser::AsPreprocesser(asIScriptEngine *engine) : engine(engine) {
pragmaCallback = nullptr;
pragmaParam = nullptr;
definedWords = *DEFAULT_MARCO;
}
AsPreprocesser::~AsPreprocesser() { void ClearAll(); }

View File

@ -124,9 +124,9 @@ protected:
PRAGMACALLBACK_t pragmaCallback;
void *pragmaParam;
QVector<QString> includedScripts;
QStringList includedScripts;
QVector<QString> definedWords;
QStringList definedWords;
};
#endif // ASPREPROCESSER_H

View File

@ -1,3 +1,20 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef CLICKCALLBACK_H
#define CLICKCALLBACK_H

View File

@ -55,7 +55,7 @@ QAsCodeParser::SymbolTable QAsCodeParser::parse(const QByteArray &codes) {
fn.name = v.name;
fn.nameInSrc = v.nameInSrc;
fn.content = v.args;
fn.ns = v.ns;
// fn.ns = v.ns;
fn.typeStr = v.ret;
ret.insert(p->first, fn);
}
@ -71,7 +71,7 @@ QAsCodeParser::SymbolTable QAsCodeParser::parseIntell(qsizetype offset,
SymbolTable ret;
auto pend = _symtable.lowerBound(offset);
for (auto p = _symtable.cbegin(); p != pend; p++) {
for (auto p = _symtable.begin(); p != pend; p++) {
ret.insert(p.key(), p.value());
}
@ -80,7 +80,7 @@ QAsCodeParser::SymbolTable QAsCodeParser::parseIntell(qsizetype offset,
// you can extend it with more features
// PRS are welcomed.
auto pend = m_segs.lowerBound(offset);
for (auto p = m_segs.cbegin(); p != pend; ++p) {
for (auto p = m_segs.begin(); p != pend; ++p) {
auto v = p.value();
Symbol fn;
@ -88,7 +88,7 @@ QAsCodeParser::SymbolTable QAsCodeParser::parseIntell(qsizetype offset,
fn.name = v.name;
fn.nameInSrc = v.nameInSrc;
fn.content = v.args;
fn.ns = v.ns;
// fn.ns = v.ns;
fn.typeStr = v.ret;
ret.insert(p.key(), fn);
}
@ -192,7 +192,7 @@ QAsCodeParser::Symbol QAsCodeParser::ParseFunctionDefinition() {
se.name = getSymbolString(id);
se.nameInSrc = id.pos;
se.content = params;
se.ns = getRealNamespace(ns);
// se.ns = getRealNamespace(ns);
// Parse an optional 'const' after the function definition (used for
// object methods)
@ -1481,11 +1481,11 @@ QByteArray QAsCodeParser::getSymbolString(const sToken &t) {
}
QByteArrayList QAsCodeParser::getRealNamespace(const QByteArrayList &ns) {
if (ns.isEmpty()) {
return _curns + ns;
} else {
return ns;
}
// if (ns.isEmpty()) {
// return _curns + ns;
// } else {
return ns;
// }
}
void QAsCodeParser::ParseNamespace() {
@ -1496,15 +1496,14 @@ void QAsCodeParser::ParseNamespace() {
RewindErrorTo(&t1);
}
auto iden = ParseIdentifier();
ParseIdentifier();
if (isSyntaxError)
return;
GetToken(&t1);
while (t1.type == ttScope) {
ParseIdentifier();
// NOTE
auto id = ParseIdentifier();
if (isSyntaxError)
return;
@ -1518,8 +1517,6 @@ void QAsCodeParser::ParseNamespace() {
sToken start = t1;
_curns.append(QByteArray(t1.pos, t1.length));
ParseScript(true);
if (!isSyntaxError) {
@ -1538,8 +1535,6 @@ QAsCodeParser::CodeSegment QAsCodeParser::ParseFunction(bool isMethod) {
sToken t1;
GetToken(&t1);
auto tstart = t1;
if (!isMethod) {
// A global function can be marked as shared and external
while (t1.type == ttIdentifier) {
@ -1624,14 +1619,14 @@ QAsCodeParser::CodeSegment QAsCodeParser::ParseFunction(bool isMethod) {
RewindTo(&t1);
if (t1.type == ttEndStatement) {
ParseToken(ttEndStatement);
fn.ns = _curns;
// fn.ns = _curns;
return fn;
}
// We should just find the end of the statement block here. The statements
// will be parsed on request by the compiler once it starts the compilation.
SuperficiallyParseStatementBlock();
fn.ns = _curns;
// fn.ns = _curns;
fn.code = code.mid(t1.pos, sourcePos - t1.pos);
fn.valid = true;
return fn;
@ -1639,7 +1634,6 @@ QAsCodeParser::CodeSegment QAsCodeParser::ParseFunction(bool isMethod) {
QAsCodeParser::Symbol QAsCodeParser::ParseFuncDef() {
Symbol sym;
size_t eoff;
// Allow keywords 'external' and 'shared' before 'interface'
sToken t1;
@ -1718,6 +1712,7 @@ void QAsCodeParser::ParseClass() {
auto cls = ParseIdentifier();
clssym.name = getSymbolString(cls);
clssym.nameInSrc = cls.pos;
clssym.type = SymbolType::Class;
// External shared declarations are ended with ';'
GetToken(&t);
@ -1789,6 +1784,8 @@ void QAsCodeParser::ParseClass() {
RewindErrorTo(&t);
return;
}
_symtable.insert(cls.pos, clssym);
}
void QAsCodeParser::ParseMixin() {
@ -1877,7 +1874,7 @@ void QAsCodeParser::ParseInitList() {
void QAsCodeParser::ParseInterface() {
Symbol sym;
size_t eoff;
sToken t;
// Allow keywords 'external' and 'shared' before 'interface'
@ -2149,7 +2146,7 @@ void QAsCodeParser::ParseEnumeration() {
sym.name = getSymbolString(token);
sym.nameInSrc = token.pos;
sym.type = SymbolType::Enum;
sym.ns = _curns;
// sym.ns = _curns;
// External shared declarations are ended with ';'
GetToken(&token);
@ -2254,7 +2251,7 @@ void QAsCodeParser::ParseTypedef() {
st.name = getSymbolString(r);
sym.content.append(st);
sym.ns = _curns;
// sym.ns = _curns;
_symtable.insert(eoff, sym);
}
@ -3251,6 +3248,7 @@ bool QAsCodeParser::IsAssignOperator(int tokenType) {
}
bool QAsCodeParser::DoesTypeExist(const QString &t) {
Q_UNUSED(t);
// TODO: don't check
return true;
}

View File

@ -51,15 +51,14 @@ public:
Invalid,
FnDecl,
Import,
Value, // a common value
Variable, // a variable
Enum, // an enum
Class, // a class type
Namespace, // a namespace
Function, // a function
TypeDef, // a typedef
FnDef, // a funcdef
Property, // a property
Value, // a common value
Variable, // a variable
Enum, // an enum
Class, // a class type
Function, // a function
TypeDef, // a typedef
FnDef, // a funcdef
Property, // a property
};
enum class Visiblity { Public, Private, Protected };
@ -68,7 +67,7 @@ public:
struct CodeSegment {
bool valid = false;
QByteArrayList ns;
// QByteArrayList ns;
QByteArray ret;
QByteArray name;
qsizetype nameInSrc = -1;
@ -86,7 +85,7 @@ public:
Visiblity vis = Visiblity::Public;
QList<Symbol> content;
QByteArrayList ns; // namespaces
// QByteArrayList ns; // namespaces
QMap<qsizetype, CodeSegment> codesegs; // used in class
// size_t scope = 0; // 0 for all
@ -231,7 +230,6 @@ private:
asCScriptEngine *engine;
QByteArrayList _curns; // current namespaces
// size_t _curscope = 0;
SymbolTable _symtable;

View File

@ -34,6 +34,7 @@
#include "define.h"
#include "plugin/pluginsystem.h"
#include "scriptaddon/scriptcolor.h"
#include "scriptaddon/scriptfile.h"
#include "scriptaddon/scriptjson.h"
#include "scriptaddon/scriptqstring.h"
#include "scriptaddon/scriptregex.h"
@ -136,22 +137,9 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
}
r = engine->RegisterGlobalFunction(
"int exec(const string &in exe, const string &in params)",
asFUNCTIONPR(execSystemCmd, (const std::string &, const std::string &),
int),
asCALL_CDECL);
Q_ASSERT(r >= 0);
if (r < 0) {
return false;
}
r = engine->RegisterGlobalFunction(
"int exec(const string &in exe, const string &in params, "
"string &out output)",
asFUNCTIONPR(execSystemCmd,
(const std::string &, const std::string &, std::string &),
int),
asCALL_CDECL);
"int exec(string &out output, const string &in exe, "
"const string &in params = \"\", int timeout = 3000)",
asFUNCTION(execSystemCmd), asCALL_CDECL);
Q_ASSERT(r >= 0);
if (r < 0) {
return false;
@ -246,23 +234,27 @@ bool ScriptMachine::isType(asITypeInfo *tinfo, RegisteredType type) {
return tinfo->DerivesFrom(t) || tinfo->Implements(t);
}
int ScriptMachine::execSystemCmd(const std::string &exe,
const std::string &params, std::string &out) {
int ScriptMachine::execSystemCmd(QString &out, const QString &exe,
const QString &params, int timeout) {
if (Utilities::isRoot()) {
auto ctx = asGetActiveContext();
if (ctx) {
auto err = tr("ExecNotAllowedInRoot");
ctx->SetException(err.toUtf8());
}
return -1;
}
QProcess ps;
ps.setProgram(QString::fromStdString(exe));
ps.setArguments(QProcess::splitCommand(QString::fromStdString(params)));
ps.setProgram(exe);
ps.setArguments(QProcess::splitCommand(params));
ps.start();
ps.waitForFinished(-1);
auto r = ps.readAllStandardOutput();
out = r.toStdString();
return ps.exitCode();
}
int ScriptMachine::execSystemCmd(const std::string &exe,
const std::string &params) {
return QProcess::execute(
QString::fromStdString(exe),
QProcess::splitCommand(QString::fromStdString(params)));
if (ps.waitForFinished(timeout)) {
out = ps.readAllStandardOutput();
return ps.exitCode();
} else {
ps.kill();
return -1;
}
}
bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
@ -272,6 +264,9 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
setDebugMode(isInDebug);
asBuilder builder(_engine);
for (auto &m : PluginSystem::instance().scriptMarcos()) {
builder.DefineWord(m);
}
// Set the pragma callback so we can detect
builder.SetPragmaCallback(&ScriptMachine::pragmaCallback, this);
@ -315,11 +310,11 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
return false;
}
if (isInDebug) {
// Let the debugger hold an engine pointer that can be used by the
// callbacks
_debugger->setEngine(_engine);
// Let the debugger hold an engine pointer that can be used by the
// callbacks
_debugger->setEngine(_engine);
if (isInDebug) {
// Allow the user to initialize the debugging before moving on
MessageInfo info;
info.message = tr("Debugging, waiting for commands.");
@ -382,6 +377,10 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
r = 0;
}
MessageInfo info;
info.message = tr("The script exited with ") + QString::number(r);
emit onOutput(MessageType::Info, info);
// Return the context after retrieving the return value
_ctxMgr->DoneWithContext(ctx);
@ -569,7 +568,7 @@ int ScriptMachine::includeCallback(const QString &include, bool quotedInclude,
if (isAbsolute) {
inc = include;
} else {
auto pwd = QDir(QFileInfo(from).filePath());
auto pwd = QFileInfo(from).absoluteDir();
inc = pwd.absoluteFilePath(include);
}
} else {
@ -1612,6 +1611,7 @@ void ScriptMachine::registerEngineAddon(asIScriptEngine *engine) {
RegisterScriptHandle(engine);
RegisterColor(engine);
RegisterQJson(engine);
RegisterScriptFile(engine);
registerExceptionRoutines(engine);
registerEngineAssert(engine);
}

View File

@ -135,10 +135,8 @@ private:
bool isType(asITypeInfo *tinfo, RegisteredType type);
static int execSystemCmd(const std::string &exe, const std::string &params,
std::string &out);
static int execSystemCmd(const std::string &exe, const std::string &params);
static int execSystemCmd(QString &out, const QString &exe,
const QString &params, int timeout);
private:
static void messageCallback(const asSMessageInfo *msg, void *param);

View File

@ -109,10 +109,6 @@ void SettingManager::load() {
Q_ASSERT(defaultFontSize > 0);
HANDLE_CONFIG;
if (!CONFIG.isWritable()) {
Logger::warning(tr("ConfigUnableSave"));
}
READ_CONFIG_INT(m_themeID, SKIN_THEME, 0);
m_themeID = qBound(0, m_themeID,
QMetaEnum::fromType<SkinManager::Theme>().keyCount());
@ -214,6 +210,13 @@ void SettingManager::setLogCount(qsizetype newLogCount) {
m_logCount = newLogCount;
}
void SettingManager::checkWriteableAndWarn() {
HANDLE_CONFIG;
if (!CONFIG.isWritable()) {
Logger::warning(tr("ConfigUnableSave"));
}
}
bool SettingManager::checkUpdate() const { return m_checkUpdate; }
void SettingManager::setCheckUpdate(bool newCheckUpdate) {

View File

@ -173,6 +173,9 @@ public:
qsizetype logCount() const;
void setLogCount(qsizetype newLogCount);
public:
void checkWriteableAndWarn();
signals:
void sigEditorfontSizeChanged(int v);
void sigDecodeStrlimitChanged(int v);

View File

@ -86,6 +86,10 @@ QString WingAngelAPI::retranslate(const QString &str) {
return QApplication::tr(str.toLatin1());
}
QStringList WingAngelAPI::registerScriptMarcos() const {
return {"EXEC_BASE", "AS_ARRAY_EXT", "AS_DICTIONARY_EXT"};
}
WingHex::IWingPlugin::RegisteredEvents WingAngelAPI::registeredEvents() const {
RegisteredEvents evs;
evs.setFlag(RegisteredEvent::PluginFileOpened);

View File

@ -49,6 +49,8 @@ public:
virtual QString retranslate(const QString &str) override;
virtual QStringList registerScriptMarcos() const override;
private:
virtual void eventPluginFile(PluginFileEvent e, FileType type,
const QString &newfileName, int handle,
@ -167,6 +169,7 @@ private:
static double QModelIndex_dataDouble(const QModelIndex &idx);
private:
// for EXEC_BASE marco
WING_SERVICE bool execScriptCode(const WingHex::SenderInfo &sender,
const QString &code);
WING_SERVICE bool execScript(const WingHex::SenderInfo &sender,

View File

@ -13,5 +13,4 @@ The following components are all third-party components used by the software. Th
* [QConsoleWidget](https://github.com/gapost/qconsolewidget) (MIT, **FORK** -> AGPL-3.0)
* [QColorPicker](https://github.com/arsdever/qcolorpicker) (MIT)
* [QtJsonModel](https://github.com/dridk/QJsonmodel) (MIT)
* [nlohmann/json](https://github.com/nlohmann/json) (MIT)
* [Qt](https://www.qt.io/) (LGPL)

View File

@ -446,32 +446,29 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
bool needAdjustFile = !QFile::exists(fileName);
bool needAdjustWs = false;
ScopeGuard guard(
[] {},
[&] {
if (Utilities::isRoot()) {
// a trick off when root under linux OS
// When new file created, change file's permission to 666.
auto adjustPermission = [&]() {
if (Utilities::isRoot()) {
// a trick off when root under linux OS
// When new file created, change file's permission to 666.
// Because you cannot open it when you use it in common user
// after saving under root user.
// Because you cannot open it when you use it in common user
// after saving under root user.
// It's a workaround and not eligent for permission system
// It's a workaround and not eligent for permission system
if (needAdjustFile) {
if (Utilities::isFileOwnerRoot(fileName)) {
Utilities::fixUpFilePermissions(fileName);
}
}
if (needAdjustWs) {
if (Utilities::isFileOwnerRoot(workSpaceName)) {
Utilities::fixUpFilePermissions(workSpaceName);
}
if (needAdjustFile) {
if (Utilities::isFileOwnerRoot(fileName)) {
Utilities::fixUpFilePermissions(fileName);
}
}
});
if (needAdjustWs) {
if (Utilities::isFileOwnerRoot(workSpaceName)) {
Utilities::fixUpFilePermissions(workSpaceName);
}
}
}
};
#endif
if (isNewFile()) {
@ -535,7 +532,9 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
m_docType = DocumentType::File;
doc->setDocSaved();
}
#ifdef Q_OS_LINUX
adjustPermission();
#endif
return ErrFile::Success;
}
}
@ -545,7 +544,9 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
doc->setDocSaved();
}
}
#ifdef Q_OS_LINUX
adjustPermission();
#endif
return ErrFile::Success;
}

View File

@ -209,6 +209,9 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
log.setLogLevel(Logger::Level(set.logLevel()));
connect(&log, &Logger::log, m_logbrowser, &QTextBrowser::append);
// check config writable
set.checkWriteableAndWarn();
// launch plugin system
if (splash)
splash->setInfoText(tr("SetupPluginSystem"));

View File

@ -550,6 +550,9 @@ public:
return {};
}
// Note: must be valid identifier
virtual QStringList registerScriptMarcos() const { return {}; }
public:
virtual void eventSelectionChanged(const QByteArrayList &selections,
bool isPreview) {

View File

@ -58,6 +58,8 @@ void PluginSystem::initCheckingEngine() {
void PluginSystem::finalizeCheckingEngine() { _engine->ShutDownAndRelease(); }
QStringList PluginSystem::scriptMarcos() const { return _scriptMarcos; }
const QList<IWingPlugin *> &PluginSystem::plugins() const {
return _loadedplgs;
}
@ -234,17 +236,11 @@ PluginSystem::PluginStatus
PluginSystem::checkPluginMetadata(const PluginInfo &meta, bool isPlg) {
constexpr auto puid_limit = 36; // same as uuid length, so enough
if (meta.id.isEmpty() && meta.id.length() > puid_limit) {
if (meta.id.length() > puid_limit) {
return PluginStatus::InvalidID;
}
if (meta.id.front().isDigit()) {
return PluginStatus::InvalidID;
}
auto r = std::find_if(meta.id.begin(), meta.id.end(), [](const QChar &ch) {
return !ch.isLetterOrNumber() && ch != '_';
});
if (r != meta.id.end()) {
if (!isValidIdentifier(meta.id)) {
return PluginStatus::InvalidID;
}
@ -264,6 +260,23 @@ PluginSystem::checkPluginMetadata(const PluginInfo &meta, bool isPlg) {
return PluginStatus::Valid;
}
bool PluginSystem::isValidIdentifier(const QString &str) {
if (str.isEmpty()) {
return false;
}
auto pch = str.cbegin();
if (pch->isDigit()) {
return false;
}
pch++;
for (; pch != str.cend(); pch++) {
if (!pch->isLetterOrNumber() && *pch != '_') {
return false;
}
}
return true;
}
bool PluginSystem::checkPluginCanOpenedFile(IWingPlugin *plg) {
if (plg == nullptr) {
return false;
@ -836,6 +849,27 @@ void PluginSystem::registerEnums(IWingPlugin *plg) {
_angelplg->registerScriptEnums(id, passedEnums);
}
void PluginSystem::registerMarcos(IWingPlugin *plg) {
Q_ASSERT(plg);
auto id = getPUID(plg).toUpper();
auto sep = QStringLiteral("_");
_scriptMarcos.append(sep + id + sep);
QStringList invalidMarco;
for (auto &m : plg->registerScriptMarcos()) {
if (isValidIdentifier(m)) {
_scriptMarcos.append(sep + id + sep + m + sep);
} else {
invalidMarco.append(m);
}
}
if (!invalidMarco.isEmpty()) {
Logger::warning(tr("InvalidMarcosRegister:") + invalidMarco.join(", "));
}
}
void PluginSystem::registerEvents(IWingPlugin *plg) {
Q_ASSERT(plg);
auto evs = plg->registeredEvents();
@ -1193,6 +1227,7 @@ void PluginSystem::loadPlugin(IWingPlugin *p, PluginInfo &meta,
registerFns(p);
registerEnums(p);
registerMarcos(p);
registerEvents(p);
connectInterface(p);

View File

@ -160,6 +160,8 @@ public:
IWingDevice *ext2Device(const QString &ext);
QStringList scriptMarcos() const;
public:
PluginInfo getPluginInfo(IWingPluginBase *plg) const;
@ -205,12 +207,15 @@ private:
PluginStatus checkPluginMetadata(const PluginInfo &meta, bool isPlg);
static bool isValidIdentifier(const QString &str);
void retranslateMetadata(IWingPluginBase *plg, PluginInfo &meta);
private:
void registerFns(IWingPlugin *plg);
void registerUnSafeFns(IWingPlugin *plg);
void registerEnums(IWingPlugin *plg);
void registerMarcos(IWingPlugin *plg);
void registerEvents(IWingPlugin *plg);
static QString getScriptFnSig(const QString &fnName,
@ -390,6 +395,8 @@ private:
WingAngelAPI *_angelplg = nullptr;
asCScriptEngine *_engine = nullptr;
QStringList _scriptMarcos;
QReadWriteLock _rwlock;
};

View File

@ -0,0 +1,514 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#include "scriptfile.h"
BEGIN_AS_NAMESPACE
CScriptFile *ScriptFile_Factory() { return new CScriptFile(); }
void ScriptFile_Factory_Generic(asIScriptGeneric *gen) {
*(CScriptFile **)gen->GetAddressOfReturnLocation() = ScriptFile_Factory();
}
void ScriptFile_AddRef_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
file->AddRef();
}
void ScriptFile_Release_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
file->Release();
}
void ScriptFile_Open_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
QString *f = (QString *)gen->GetArgAddress(0);
auto r = file->Open(*f);
gen->SetReturnByte(r);
}
void ScriptFile_Close_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
auto r = file->Close();
gen->SetReturnByte(r);
}
void ScriptFile_GetSize_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
qint64 r = file->GetSize();
gen->SetReturnQWord(r);
}
void ScriptFile_ReadString_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
int len = gen->GetArgDWord(0);
auto str = file->ReadString(len);
gen->SetReturnObject(&str);
}
void ScriptFile_ReadLine_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
auto str = file->ReadLine();
gen->SetReturnObject(&str);
}
void ScriptFile_ReadInt_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
asUINT bytes = *(asUINT *)gen->GetAddressOfArg(0);
*(asINT64 *)gen->GetAddressOfReturnLocation() = file->ReadInt(bytes);
}
void ScriptFile_ReadUInt_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
asUINT bytes = *(asUINT *)gen->GetAddressOfArg(0);
*(asQWORD *)gen->GetAddressOfReturnLocation() = file->ReadUInt(bytes);
}
void ScriptFile_ReadFloat_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
*(float *)gen->GetAddressOfReturnLocation() = file->ReadFloat();
}
void ScriptFile_ReadDouble_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
*(double *)gen->GetAddressOfReturnLocation() = file->ReadDouble();
}
void ScriptFile_IsEOF_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
bool r = file->IsEOF();
gen->SetReturnByte(r);
}
void ScriptFile_GetPos_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
gen->SetReturnDWord(file->GetPos());
}
void ScriptFile_SetPos_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
auto pos = qint64(gen->GetArgQWord(0));
gen->SetReturnByte(file->SetPos(pos));
}
void ScriptFile_MovePos_Generic(asIScriptGeneric *gen) {
CScriptFile *file = (CScriptFile *)gen->GetObject();
auto delta = qint64(gen->GetArgQWord(0));
gen->SetReturnByte(file->MovePos(delta));
}
void RegisterScriptFile_Native(asIScriptEngine *engine) {
int r;
r = engine->RegisterObjectType("file", 0, asOBJ_REF);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("file", asBEHAVE_FACTORY, "file @f()",
asFUNCTION(ScriptFile_Factory),
asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("file", asBEHAVE_ADDREF, "void f()",
asMETHOD(CScriptFile, AddRef),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("file", asBEHAVE_RELEASE, "void f()",
asMETHOD(CScriptFile, Release),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool open(const string &in)",
asMETHOD(CScriptFile, Open),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"file", "bool close()", asMETHOD(CScriptFile, Close), asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "int64 getSize() const",
asMETHOD(CScriptFile, GetSize),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool isEndOfFile() const",
asMETHOD(CScriptFile, IsEOF),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "string readString(uint)",
asMETHOD(CScriptFile, ReadString),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "string readLine()",
asMETHOD(CScriptFile, ReadLine),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "int64 readInt(uint)",
asMETHOD(CScriptFile, ReadInt),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "uint64 readUInt(uint)",
asMETHOD(CScriptFile, ReadUInt),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "float readFloat()",
asMETHOD(CScriptFile, ReadFloat),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "double readDouble()",
asMETHOD(CScriptFile, ReadDouble),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "int getPos() const",
asMETHOD(CScriptFile, GetPos),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool setPos(int64)",
asMETHOD(CScriptFile, SetPos),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool movePos(int64)",
asMETHOD(CScriptFile, MovePos),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty(
"file", "bool mostSignificantByteFirst",
asOFFSET(CScriptFile, mostSignificantByteFirst));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
}
void RegisterScriptFile_Generic(asIScriptEngine *engine) {
int r;
r = engine->RegisterObjectType("file", 0, asOBJ_REF);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("file", asBEHAVE_FACTORY, "file @f()",
asFUNCTION(ScriptFile_Factory_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("file", asBEHAVE_ADDREF, "void f()",
asFUNCTION(ScriptFile_AddRef_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("file", asBEHAVE_RELEASE, "void f()",
asFUNCTION(ScriptFile_Release_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool open(const string &in)",
asFUNCTION(ScriptFile_Open_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool close()",
asFUNCTION(ScriptFile_Close_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "int64 getSize() const",
asFUNCTION(ScriptFile_GetSize_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool isEndOfFile() const",
asFUNCTION(ScriptFile_IsEOF_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "string readString(uint)",
asFUNCTION(ScriptFile_ReadString_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "string readLine()",
asFUNCTION(ScriptFile_ReadLine_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "int64 readInt(uint)",
asFUNCTION(ScriptFile_ReadInt_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "uint64 readUInt(uint)",
asFUNCTION(ScriptFile_ReadUInt_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "float readFloat()",
asFUNCTION(ScriptFile_ReadFloat_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "double readDouble()",
asFUNCTION(ScriptFile_ReadDouble_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "int getPos() const",
asFUNCTION(ScriptFile_GetPos_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool setPos(int64)",
asFUNCTION(ScriptFile_SetPos_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("file", "bool movePos(int64)",
asFUNCTION(ScriptFile_MovePos_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectProperty(
"file", "bool mostSignificantByteFirst",
asOFFSET(CScriptFile, mostSignificantByteFirst));
Q_ASSERT(r >= 0);
Q_UNUSED(r);
}
void RegisterScriptFile(asIScriptEngine *engine) {
if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY"))
RegisterScriptFile_Generic(engine);
else
RegisterScriptFile_Native(engine);
}
CScriptFile::CScriptFile() {
refCount = 1;
mostSignificantByteFirst = false;
}
CScriptFile::~CScriptFile() { Close(); }
void CScriptFile::AddRef() const { asAtomicInc(refCount); }
void CScriptFile::Release() const {
if (asAtomicDec(refCount) == 0)
delete this;
}
bool CScriptFile::Open(const QString &filename) {
// Close the previously opened file handle
if (file.isOpen())
Close();
file.setFileName(filename);
return file.open(QFile::ReadOnly);
}
bool CScriptFile::Close() {
if (!file.isOpen())
return false;
file.close();
file.setFileName({});
return true;
}
asINT64 CScriptFile::GetSize() const {
if (!file.isOpen())
return -1;
return file.size();
}
int CScriptFile::GetPos() const {
if (!file.isOpen())
return -1;
return file.pos();
}
bool CScriptFile::SetPos(asINT64 pos) {
if (!file.isOpen())
return false;
return file.seek(pos);
}
bool CScriptFile::MovePos(asINT64 delta) {
if (!file.isOpen())
return false;
return file.seek(file.pos() + delta);
}
QString CScriptFile::ReadString(unsigned int length) {
if (!file.isOpen())
return {};
return QString::fromUtf8(file.read(length));
}
QString CScriptFile::ReadLine() {
if (!file.isOpen())
return {};
return QString::fromUtf8(file.readLine());
}
asINT64 CScriptFile::ReadInt(asUINT bytes) {
if (!file.isOpen())
return 0;
if (bytes > 8)
bytes = 8;
if (bytes == 0)
return 0;
char buf[8];
size_t r = file.read(buf, 8);
if (r == 0)
return 0;
asINT64 val = 0;
if (mostSignificantByteFirst) {
unsigned int n = 0;
for (; n < bytes; n++)
val |= asQWORD(buf[n]) << ((bytes - n - 1) * 8);
// Check the most significant byte to determine if the rest
// of the qword must be filled to give a negative value
if (buf[0] & 0x80)
for (; n < 8; n++)
val |= asQWORD(0xFF) << (n * 8);
} else {
unsigned int n = 0;
for (; n < bytes; n++)
val |= asQWORD(buf[n]) << (n * 8);
// Check the most significant byte to determine if the rest
// of the qword must be filled to give a negative value
if (buf[bytes - 1] & 0x80)
for (; n < 8; n++)
val |= asQWORD(0xFF) << (n * 8);
}
return val;
}
asQWORD CScriptFile::ReadUInt(asUINT bytes) {
if (!file.isOpen())
return 0;
if (bytes > 8)
bytes = 8;
if (bytes == 0)
return 0;
char buf[8];
size_t r = file.read(buf, 8);
if (r == 0)
return 0;
asQWORD val = 0;
if (mostSignificantByteFirst) {
unsigned int n = 0;
for (; n < bytes; n++)
val |= asQWORD(buf[n]) << ((bytes - n - 1) * 8);
} else {
unsigned int n = 0;
for (; n < bytes; n++)
val |= asQWORD(buf[n]) << (n * 8);
}
return val;
}
float CScriptFile::ReadFloat() {
if (!file.isOpen())
return 0;
char buf[4];
size_t r = file.read(buf, 4);
if (r == 0)
return 0;
union conv {
asUINT val;
float fp;
} value = {0};
if (mostSignificantByteFirst) {
unsigned int n = 0;
for (; n < 4; n++)
value.val |= asUINT(buf[n]) << ((3 - n) * 8);
} else {
unsigned int n = 0;
for (; n < 4; n++)
value.val |= asUINT(buf[n]) << (n * 8);
}
return value.fp;
}
double CScriptFile::ReadDouble() {
if (!file.isOpen())
return 0;
char buf[8];
size_t r = file.read(buf, 8);
if (r == 0)
return 0;
union conv {
asQWORD val;
double fp;
} value = {0};
if (mostSignificantByteFirst) {
unsigned int n = 0;
for (; n < 8; n++)
value.val |= asQWORD(buf[n]) << ((7 - n) * 8);
} else {
unsigned int n = 0;
for (; n < 8; n++)
value.val |= asQWORD(buf[n]) << (n * 8);
}
return value.fp;
}
bool CScriptFile::IsEOF() const {
if (!file.isOpen())
return true;
return file.atEnd();
}
END_AS_NAMESPACE

View File

@ -0,0 +1,84 @@
/*==============================================================================
** Copyright (C) 2024-2027 WingSummer
**
** This program is free software: you can redistribute it and/or modify it under
** the terms of the GNU Affero General Public License as published by the Free
** Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
** details.
**
** You should have received a copy of the GNU Affero General Public License
** along with this program. If not, see <https://www.gnu.org/licenses/>.
** =============================================================================
*/
#ifndef SCRIPTFILE_H
#define SCRIPTFILE_H
//---------------------------
// Declaration
//
#ifndef ANGELSCRIPT_H
// Avoid having to inform include path if header is already include before
#include <angelscript.h>
#endif
#include <QFile>
#include <QString>
BEGIN_AS_NAMESPACE
class CScriptFile {
public:
CScriptFile();
void AddRef() const;
void Release() const;
bool Open(const QString &filename);
bool Close();
asINT64 GetSize() const;
bool IsEOF() const;
// Reading
QString ReadString(unsigned int length);
QString ReadLine();
asINT64 ReadInt(asUINT bytes);
asQWORD ReadUInt(asUINT bytes);
float ReadFloat();
double ReadDouble();
// Cursor
int GetPos() const;
bool SetPos(asINT64 pos);
bool MovePos(asINT64 delta);
// Big-endian = most significant byte first
bool mostSignificantByteFirst;
protected:
~CScriptFile();
mutable int refCount;
QFile file;
};
// This function will determine the configuration of the engine
// and use one of the two functions below to register the file type
void RegisterScriptFile(asIScriptEngine *engine);
// Call this function to register the file type
// using native calling conventions
void RegisterScriptFile_Native(asIScriptEngine *engine);
// Use this one instead if native calling conventions
// are not supported on the target platform
void RegisterScriptFile_Generic(asIScriptEngine *engine);
END_AS_NAMESPACE
#endif