feat: 脚本引擎单例化;更合理的格式化参数;
This commit is contained in:
parent
7597663d76
commit
d6680e3f11
|
@ -15,7 +15,6 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
|
|||
if(MSVC)
|
||||
string(APPEND CMAKE_CXX_FLAGS " /utf-8")
|
||||
string(APPEND CMAKE_C_FLAGS " /utf-8")
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit fac4d08fd0473a94d99c143c6ba6b1f9e0bd7636
|
||||
Subproject commit ce639ebfcec47a7c74233b4bab50017cb34e615b
|
|
@ -42,7 +42,7 @@ option(WINGHEX_USE_FRAMELESS "Use borderless windows to ensure UI uniformity"
|
|||
if(WIN32)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED AxContainer)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED AxContainer)
|
||||
add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DNOMINMAX)
|
||||
endif()
|
||||
|
||||
if(${QT_VERSION_MAJOR} EQUAL 5)
|
||||
|
@ -239,8 +239,6 @@ set(CLASS_SRC
|
|||
src/class/settingmanager.cpp
|
||||
src/class/asdebugger.h
|
||||
src/class/asdebugger.cpp
|
||||
src/class/scriptconsolemachine.h
|
||||
src/class/scriptconsolemachine.cpp
|
||||
src/class/angelobjstring.h
|
||||
src/class/angelobjstring.cpp
|
||||
src/class/scripteditortheme.h
|
||||
|
@ -319,8 +317,6 @@ set(MODEL_SRC
|
|||
src/model/checksummodel.cpp
|
||||
src/model/qjsontablemodel.h
|
||||
src/model/qjsontablemodel.cpp
|
||||
src/model/scriptobjmodel.h
|
||||
src/model/scriptobjmodel.cpp
|
||||
src/model/dbgcallstackmodel.h
|
||||
src/model/dbgcallstackmodel.cpp
|
||||
src/model/dbgvarshowmodel.h
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -24,33 +24,14 @@
|
|||
|
||||
asBuilder::asBuilder(asIScriptEngine *engine) : AsPreprocesser(engine) {}
|
||||
|
||||
asBuilder::~asBuilder() {
|
||||
if (module) {
|
||||
module->Discard();
|
||||
}
|
||||
}
|
||||
|
||||
int asBuilder::StartNewModule(const char *moduleName) {
|
||||
if (module) {
|
||||
module->Discard();
|
||||
}
|
||||
|
||||
module = engine->GetModule(moduleName, asGM_ALWAYS_CREATE);
|
||||
if (module == nullptr)
|
||||
return -1;
|
||||
|
||||
clearAll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
asIScriptModule *asBuilder::GetModule() { return module; }
|
||||
|
||||
int asBuilder::Build() {
|
||||
int asBuilder::build(asIScriptModule *module) {
|
||||
Q_ASSERT(module);
|
||||
if (module == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
module->ResetGlobalVars();
|
||||
|
||||
for (auto &mod : modifiedScripts) {
|
||||
module->AddScriptSection(mod.section.toUtf8(), mod.script.data(),
|
||||
mod.script.size());
|
||||
|
|
|
@ -27,19 +27,10 @@
|
|||
class asBuilder : public AsPreprocesser {
|
||||
public:
|
||||
explicit asBuilder(asIScriptEngine *engine);
|
||||
virtual ~asBuilder();
|
||||
|
||||
// Start a new module
|
||||
virtual int StartNewModule(const char *moduleName);
|
||||
|
||||
// Build the added script sections
|
||||
virtual int Build();
|
||||
|
||||
// Returns the current module
|
||||
asIScriptModule *GetModule();
|
||||
|
||||
protected:
|
||||
asIScriptModule *module = nullptr;
|
||||
public:
|
||||
// build the added script sections
|
||||
int build(asIScriptModule *module);
|
||||
};
|
||||
|
||||
#endif // ASBUILDER_H
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "asdatabase.h"
|
||||
#include "class/aspreprocesser.h"
|
||||
#include "class/qascodeparser.h"
|
||||
#include "class/scriptmachine.h"
|
||||
#include "model/codecompletionmodel.h"
|
||||
#include "wingcodeedit.h"
|
||||
|
||||
|
@ -39,10 +40,9 @@ Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, DBL_COLON_TRIGGER, ("::"))
|
|||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, LEFT_PARE_TRIGGER, ("("))
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, (";"))
|
||||
|
||||
AsCompletion::AsCompletion(asIScriptEngine *engine, WingCodeEdit *p)
|
||||
: WingCompleter(p), parser(engine), _engine(engine), m_parseDocument(true) {
|
||||
Q_ASSERT(engine);
|
||||
|
||||
AsCompletion::AsCompletion(WingCodeEdit *p)
|
||||
: WingCompleter(p), parser(ScriptMachine::instance().engine()),
|
||||
m_parseDocument(true) {
|
||||
setTriggerList({*DOT_TRIGGER, *DBL_COLON_TRIGGER,
|
||||
// unleash the power of call tips
|
||||
*LEFT_PARE_TRIGGER,
|
||||
|
@ -157,7 +157,8 @@ void AsCompletion::processTrigger(const QString &trigger,
|
|||
qsizetype pos = 0;
|
||||
for (; p < end;) {
|
||||
asUINT tokenLen = 0;
|
||||
auto tt = _engine->ParseToken(p, len, &tokenLen);
|
||||
auto tt =
|
||||
ScriptMachine::instance().engine()->ParseToken(p, len, &tokenLen);
|
||||
if (tt == asTC_WHITESPACE) {
|
||||
p += tokenLen;
|
||||
pos += tokenLen;
|
||||
|
@ -292,7 +293,7 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
|
|||
auto code = editor->toPlainText();
|
||||
|
||||
// first preprocess the code
|
||||
AsPreprocesser prepc(_engine);
|
||||
AsPreprocesser prepc(ScriptMachine::instance().engine());
|
||||
// TODO: set include callback
|
||||
// prepc.setIncludeCallback();
|
||||
|
||||
|
@ -306,7 +307,7 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
|
|||
QList<CodeInfoTip> ret;
|
||||
|
||||
for (auto &d : data) {
|
||||
QAsCodeParser parser(_engine);
|
||||
QAsCodeParser parser(ScriptMachine::instance().engine());
|
||||
auto syms =
|
||||
parser.parseAndIntell(editor->textCursor().position(), d.script);
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
class AsCompletion : public WingCompleter {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AsCompletion(asIScriptEngine *engine, WingCodeEdit *p);
|
||||
explicit AsCompletion(WingCodeEdit *p);
|
||||
|
||||
virtual ~AsCompletion();
|
||||
|
||||
|
@ -56,7 +56,6 @@ private:
|
|||
|
||||
private:
|
||||
ASDataBase parser;
|
||||
asIScriptEngine *_engine;
|
||||
bool m_parseDocument;
|
||||
};
|
||||
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
|
||||
#include "control/scriptingconsole.h"
|
||||
|
||||
AsConsoleCompletion::AsConsoleCompletion(asIScriptEngine *engine,
|
||||
ScriptingConsole *p)
|
||||
: AsCompletion(engine, p), _console(p) {
|
||||
AsConsoleCompletion::AsConsoleCompletion(ScriptingConsole *p)
|
||||
: AsCompletion(p), _console(p) {
|
||||
setParseDocument(false);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class ScriptingConsole;
|
|||
class AsConsoleCompletion : public AsCompletion {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AsConsoleCompletion(asIScriptEngine *engine, ScriptingConsole *p);
|
||||
explicit AsConsoleCompletion(ScriptingConsole *p);
|
||||
virtual ~AsConsoleCompletion() = default;
|
||||
|
||||
private:
|
||||
|
|
|
@ -17,6 +17,25 @@
|
|||
|
||||
#include "ascontextmgr.h"
|
||||
|
||||
// copy from base class
|
||||
struct SContextInfo {
|
||||
asUINT sleepUntil;
|
||||
std::vector<asIScriptContext *> coRoutines;
|
||||
asUINT currentCoRoutine;
|
||||
asIScriptContext *keepCtxAfterExecution;
|
||||
};
|
||||
|
||||
asContextMgr::asContextMgr() : CContextMgr() {}
|
||||
|
||||
bool asContextMgr::isRunning() const { return !m_threads.empty(); }
|
||||
bool asContextMgr::findThreadWithUserData(asPWORD index, void *data) const {
|
||||
for (auto &th : m_threads) {
|
||||
auto ctx = th->keepCtxAfterExecution;
|
||||
if (ctx) {
|
||||
auto user = ctx->GetUserData(index);
|
||||
if (user == data) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class asContextMgr : public CContextMgr {
|
|||
public:
|
||||
asContextMgr();
|
||||
|
||||
bool isRunning() const;
|
||||
bool findThreadWithUserData(asPWORD index, void *data) const;
|
||||
};
|
||||
|
||||
#endif // ASCONTEXTMGR_H
|
||||
|
|
|
@ -75,6 +75,12 @@ void asDebugger::lineCallback(asIScriptContext *ctx) {
|
|||
if (ctx == nullptr)
|
||||
return;
|
||||
|
||||
auto isDbg = reinterpret_cast<asPWORD>(
|
||||
ctx->GetUserData(AsUserDataType::UserData_isDbg));
|
||||
if (!isDbg) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *file = 0;
|
||||
int col = 0;
|
||||
int lineNbr = ctx->GetLineNumber(0, &col, &file);
|
||||
|
@ -500,6 +506,8 @@ asDebugger::GCStatistic asDebugger::gcStatistics() {
|
|||
|
||||
void asDebugger::runDebugAction(DebugAction action) { m_action = action; }
|
||||
|
||||
void asDebugger::resetState() { m_action = CONTINUE; }
|
||||
|
||||
void asDebugger::deleteDbgContextInfo(void *info) {
|
||||
if (info) {
|
||||
delete reinterpret_cast<ContextDbgInfo *>(info);
|
||||
|
|
|
@ -116,6 +116,7 @@ public:
|
|||
void runDebugAction(DebugAction action);
|
||||
|
||||
DebugAction currentState() const;
|
||||
void resetState();
|
||||
|
||||
static void deleteDbgContextInfo(void *info);
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ QString ClangFormatManager::formatCode(const QString &codes, bool &ok) {
|
|||
.arg(m_clangStyle)
|
||||
.arg(m_identWidth);
|
||||
auto ret = runClangFormat(
|
||||
{style, QStringLiteral("--assume-filename=wing.cpp")}, codes, ok);
|
||||
{style, QStringLiteral("--assume-filename=wing.cs")}, codes, ok);
|
||||
return ret;
|
||||
} else {
|
||||
return runClangFormat({}, codes, ok);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Qt-Advanced-Docking-System/src/DockAreaWidget.h"
|
||||
#include "class/languagemanager.h"
|
||||
#include "class/logger.h"
|
||||
#include "class/scriptmachine.h"
|
||||
#include "class/settingmanager.h"
|
||||
#include "class/skinmanager.h"
|
||||
#include "class/wingcstruct.h"
|
||||
|
@ -3886,6 +3887,8 @@ void PluginSystem::loadAllPlugin() {
|
|||
}
|
||||
}
|
||||
|
||||
Logger::newLine();
|
||||
|
||||
// loading finished, delete the checking engine
|
||||
finalizeCheckingEngine();
|
||||
}
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
/*==============================================================================
|
||||
** 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 "scriptconsolemachine.h"
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QTextStream>
|
||||
|
||||
ScriptConsoleMachine::ScriptConsoleMachine(
|
||||
std::function<QString(void)> &getInputFn, QObject *parent)
|
||||
: ScriptMachine(getInputFn, parent) {
|
||||
if (!ScriptConsoleMachine::configureEngine(engine())) {
|
||||
destoryMachine();
|
||||
}
|
||||
if (engine()) {
|
||||
_model = new ScriptObjModel(engine(), debugger(), this);
|
||||
}
|
||||
}
|
||||
|
||||
ScriptConsoleMachine::~ScriptConsoleMachine() {}
|
||||
|
||||
bool ScriptConsoleMachine::executeCode(const QString &code) {
|
||||
return execString(engine(), code);
|
||||
}
|
||||
|
||||
ScriptObjModel *ScriptConsoleMachine::model() const { return _model; }
|
||||
|
||||
bool ScriptConsoleMachine::configureEngine(asIScriptEngine *engine) {
|
||||
_clsfn = std::bind(&ScriptConsoleMachine::onClearConsole, this);
|
||||
auto r = engine->RegisterGlobalFunction(
|
||||
"void clear()", asMETHOD(decltype(_clsfn), operator()),
|
||||
asCALL_THISCALL_ASGLOBAL, &_clsfn);
|
||||
Q_ASSERT(r >= 0);
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
|
||||
const QString &code) {
|
||||
auto mod = engine->GetModule("Console", asGM_CREATE_IF_NOT_EXISTS);
|
||||
if (code.startsWith(QStringLiteral("addvar "))) {
|
||||
auto varcmd = code.mid(7) + QStringLiteral(";");
|
||||
if (varcmd.length() == 1) {
|
||||
MessageInfo info;
|
||||
info.message = tr("EmptyDecl");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
return false;
|
||||
}
|
||||
auto ret = mod->CompileGlobalVar("addvar", varcmd.toUtf8(), 0) >= 0;
|
||||
_model->updateData();
|
||||
return ret;
|
||||
} else if (code.startsWith(QStringLiteral("rmvar "))) {
|
||||
if (mod == nullptr || mod->GetGlobalVarCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// remove the tailing semi-colons
|
||||
static QRegularExpression re(QStringLiteral(";+$"));
|
||||
|
||||
auto varcmd = code.mid(6).remove(re);
|
||||
for (auto &var : varcmd.split(' ', Qt::SkipEmptyParts)) {
|
||||
int index = mod->GetGlobalVarIndexByName(var.toUtf8());
|
||||
if (index >= 0) {
|
||||
mod->RemoveGlobalVar(index);
|
||||
}
|
||||
}
|
||||
_model->updateData();
|
||||
return true;
|
||||
} else if (code.startsWith(QStringLiteral("lsfn"))) {
|
||||
if (code.trimmed().length() != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString str;
|
||||
QTextStream s(&str);
|
||||
asUINT n;
|
||||
|
||||
// List the application registered functions
|
||||
s << tr("Application functions:") << Qt::endl;
|
||||
for (n = 0; n < engine->GetGlobalFunctionCount(); n++) {
|
||||
asIScriptFunction *func = engine->GetGlobalFunctionByIndex(n);
|
||||
|
||||
// Skip the functions that start with _ as these are not meant to be
|
||||
// called explicitly by the user
|
||||
if (func->GetName()[0] != '_')
|
||||
s << QStringLiteral(" ") << func->GetDeclaration() << Qt::endl;
|
||||
}
|
||||
|
||||
// List the user functions in the module
|
||||
if (mod) {
|
||||
s << Qt::endl;
|
||||
s << tr("User functions:") << Qt::endl;
|
||||
for (n = 0; n < mod->GetFunctionCount(); n++) {
|
||||
asIScriptFunction *func = mod->GetFunctionByIndex(n);
|
||||
s << QStringLiteral(" ") << func->GetDeclaration() << Qt::endl;
|
||||
}
|
||||
}
|
||||
|
||||
MessageInfo info;
|
||||
info.message = str;
|
||||
emit onOutput(MessageType::Info, info);
|
||||
return true;
|
||||
} else if (code.startsWith(QStringLiteral("lsvar"))) {
|
||||
if (code.trimmed().length() != 5) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString str;
|
||||
QTextStream s(&str);
|
||||
asUINT n;
|
||||
|
||||
// List the application registered variables
|
||||
s << tr("Application variables:") << Qt::endl;
|
||||
for (n = 0; n < engine->GetGlobalPropertyCount(); n++) {
|
||||
const char *name;
|
||||
int typeId;
|
||||
bool isConst;
|
||||
engine->GetGlobalPropertyByIndex(n, &name, 0, &typeId, &isConst);
|
||||
auto decl =
|
||||
isConst ? QStringLiteral(" const ") : QStringLiteral(" ");
|
||||
decl += engine->GetTypeDeclaration(typeId);
|
||||
decl += QStringLiteral(" ");
|
||||
decl += name;
|
||||
s << decl << Qt::endl;
|
||||
}
|
||||
|
||||
// List the user variables in the module
|
||||
if (mod) {
|
||||
s << Qt::endl;
|
||||
s << tr("User variables:") << Qt::endl;
|
||||
for (n = 0; n < (asUINT)mod->GetGlobalVarCount(); n++) {
|
||||
s << QStringLiteral(" ") << mod->GetGlobalVarDeclaration(n)
|
||||
<< Qt::endl;
|
||||
}
|
||||
}
|
||||
|
||||
MessageInfo info;
|
||||
info.message = str;
|
||||
emit onOutput(MessageType::Info, info);
|
||||
return true;
|
||||
} else {
|
||||
return ScriptMachine::executeCode(code);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*==============================================================================
|
||||
** 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 SCRIPTCONSOLEMACHINE_H
|
||||
#define SCRIPTCONSOLEMACHINE_H
|
||||
|
||||
#include "model/scriptobjmodel.h"
|
||||
#include "scriptmachine.h"
|
||||
|
||||
class ScriptConsoleMachine : public ScriptMachine {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ScriptConsoleMachine(std::function<QString()> &getInputFn,
|
||||
QObject *parent = nullptr);
|
||||
virtual ~ScriptConsoleMachine();
|
||||
|
||||
virtual bool executeCode(const QString &code) override;
|
||||
|
||||
ScriptObjModel *model() const;
|
||||
|
||||
signals:
|
||||
void onClearConsole();
|
||||
|
||||
protected:
|
||||
virtual bool configureEngine(asIScriptEngine *engine) override;
|
||||
|
||||
private:
|
||||
bool execString(asIScriptEngine *engine, const QString &code);
|
||||
|
||||
private:
|
||||
ScriptObjModel *_model = nullptr;
|
||||
|
||||
std::function<void(void)> _clsfn;
|
||||
};
|
||||
|
||||
#endif // SCRIPTCONSOLEMACHINE_H
|
|
@ -40,6 +40,7 @@
|
|||
#include "scriptaddon/scriptregex.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QScopeGuard>
|
||||
|
||||
ScriptMachine::~ScriptMachine() {
|
||||
if (_ctxMgr) {
|
||||
|
@ -49,94 +50,119 @@ ScriptMachine::~ScriptMachine() {
|
|||
destoryMachine();
|
||||
}
|
||||
|
||||
bool ScriptMachine::inited() { return _engine != nullptr; }
|
||||
bool ScriptMachine::init() {
|
||||
if (isInited()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptMachine::isRunning() const {
|
||||
return _debugger->getEngine() || _ctxMgr->isRunning();
|
||||
qRegisterMetaType<MessageInfo>();
|
||||
|
||||
_engine = asCreateScriptEngine();
|
||||
if (!ScriptMachine::configureEngine()) {
|
||||
_engine->ShutDownAndRelease();
|
||||
_engine = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let the debugger hold an engine pointer that can be used by the
|
||||
// callbacks
|
||||
_debugger->setEngine(_engine);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
||||
if (engine == nullptr) {
|
||||
bool ScriptMachine::isInited() const { return _engine != nullptr; }
|
||||
|
||||
bool ScriptMachine::isRunning(ConsoleMode mode) const {
|
||||
return _ctxMgr->findThreadWithUserData(
|
||||
AsUserDataType::UserData_ContextMode,
|
||||
reinterpret_cast<void *>(asPWORD(mode)));
|
||||
}
|
||||
|
||||
bool ScriptMachine::configureEngine() {
|
||||
if (_engine == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we need utf8, the default is what we want
|
||||
engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true);
|
||||
engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, true);
|
||||
engine->SetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE, false);
|
||||
engine->SetEngineProperty(asEP_ALLOW_MULTILINE_STRINGS, false);
|
||||
engine->SetEngineProperty(asEP_USE_CHARACTER_LITERALS, false);
|
||||
engine->SetEngineProperty(asEP_DISABLE_INTEGER_DIVISION, false);
|
||||
engine->SetEngineProperty(asEP_PRIVATE_PROP_AS_PROTECTED, false);
|
||||
engine->SetEngineProperty(asEP_ALTER_SYNTAX_NAMED_ARGS, 0);
|
||||
engine->SetEngineProperty(asEP_ALLOW_UNICODE_IDENTIFIERS, true);
|
||||
engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, true); // enum class like
|
||||
setDebugMode(false);
|
||||
_engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true);
|
||||
_engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, true);
|
||||
_engine->SetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE, false);
|
||||
_engine->SetEngineProperty(asEP_ALLOW_MULTILINE_STRINGS, false);
|
||||
_engine->SetEngineProperty(asEP_USE_CHARACTER_LITERALS, false);
|
||||
_engine->SetEngineProperty(asEP_DISABLE_INTEGER_DIVISION, false);
|
||||
_engine->SetEngineProperty(asEP_PRIVATE_PROP_AS_PROTECTED, false);
|
||||
_engine->SetEngineProperty(asEP_ALTER_SYNTAX_NAMED_ARGS, 0);
|
||||
_engine->SetEngineProperty(asEP_ALLOW_UNICODE_IDENTIFIERS, true);
|
||||
_engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE,
|
||||
true); // enum class like
|
||||
|
||||
// We will only initialize the global variables once we're
|
||||
// ready to execute, so disable the automatic initialization
|
||||
_engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false);
|
||||
|
||||
// The script compiler will send any compiler messages to the callback
|
||||
auto r = engine->SetMessageCallback(asFUNCTION(messageCallback), this,
|
||||
asCALL_CDECL);
|
||||
auto r = _engine->SetMessageCallback(asFUNCTION(messageCallback), this,
|
||||
asCALL_CDECL);
|
||||
Q_ASSERT(r >= 0);
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
engine->SetContextUserDataCleanupCallback(
|
||||
_engine->SetContextUserDataCleanupCallback(
|
||||
&ScriptMachine::cleanUpDbgContext,
|
||||
AsUserDataType::UserData_ContextDbgInfo);
|
||||
|
||||
engine->SetFunctionUserDataCleanupCallback(
|
||||
_engine->SetFunctionUserDataCleanupCallback(
|
||||
&ScriptMachine::cleanUpPluginSysIDFunction,
|
||||
AsUserDataType::UserData_PluginFn);
|
||||
|
||||
registerEngineAddon(engine);
|
||||
registerEngineAddon(_engine);
|
||||
|
||||
_rtypes.resize(RegisteredType::tMAXCOUNT);
|
||||
_rtypes[RegisteredType::tString] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("string"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("string"));
|
||||
_rtypes[RegisteredType::tChar] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("char"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("char"));
|
||||
_rtypes[RegisteredType::tArray] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("array"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("array"));
|
||||
_rtypes[RegisteredType::tComplex] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("complex"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("complex"));
|
||||
_rtypes[RegisteredType::tWeakref] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("weakref"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("weakref"));
|
||||
_rtypes[RegisteredType::tConstWeakref] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("const_weakref"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("const_weakref"));
|
||||
_rtypes[RegisteredType::tAny] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("any"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("any"));
|
||||
_rtypes[RegisteredType::tDictionary] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("dictionary"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("dictionary"));
|
||||
_rtypes[RegisteredType::tDictionaryValue] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("dictionaryValue"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("dictionaryValue"));
|
||||
_rtypes[RegisteredType::tGrid] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("grid"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("grid"));
|
||||
_rtypes[RegisteredType::tRef] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("ref"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("ref"));
|
||||
_rtypes[RegisteredType::tColor] =
|
||||
q_check_ptr(engine->GetTypeInfoByName("color"));
|
||||
q_check_ptr(_engine->GetTypeInfoByName("color"));
|
||||
|
||||
// Register a couple of extra functions for the scripts
|
||||
_printFn = std::bind(&ScriptMachine::print, this, std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
r = engine->RegisterGlobalFunction("void print(? &in obj)",
|
||||
asMETHOD(decltype(_printFn), operator()),
|
||||
asCALL_THISCALL_ASGLOBAL, &_printFn);
|
||||
r = _engine->RegisterGlobalFunction("void print(? &in obj)",
|
||||
asMETHOD(ScriptMachine, print),
|
||||
asCALL_THISCALL_ASGLOBAL, this);
|
||||
Q_ASSERT(r >= 0);
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r = engine->RegisterGlobalFunction(
|
||||
"string getInput()", asMETHOD(decltype(_getInputFn), operator()),
|
||||
asCALL_THISCALL_ASGLOBAL, &_getInputFn);
|
||||
assert(r >= 0);
|
||||
r = _engine->RegisterGlobalFunction("string getInput()",
|
||||
asMETHOD(ScriptMachine, getInput),
|
||||
asCALL_THISCALL_ASGLOBAL, this);
|
||||
Q_ASSERT(r >= 0);
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r = engine->RegisterGlobalFunction(
|
||||
r = _engine->RegisterGlobalFunction(
|
||||
"int exec(string &out output, const string &in exe, "
|
||||
"const string &in params = \"\", int timeout = 3000)",
|
||||
asFUNCTION(execSystemCmd), asCALL_CDECL);
|
||||
|
@ -147,12 +173,12 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
|
||||
// Setup the context manager and register the support for co-routines
|
||||
_ctxMgr = new asContextMgr();
|
||||
_ctxMgr->RegisterCoRoutineSupport(engine);
|
||||
_ctxMgr->RegisterCoRoutineSupport(_engine);
|
||||
|
||||
// Tell the engine to use our context pool. This will also
|
||||
// allow us to debug internal script calls made by the engine
|
||||
r = engine->SetContextCallbacks(requestContextCallback,
|
||||
returnContextCallback, this);
|
||||
r = _engine->SetContextCallbacks(requestContextCallback,
|
||||
returnContextCallback, this);
|
||||
Q_ASSERT(r >= 0);
|
||||
if (r < 0) {
|
||||
return false;
|
||||
|
@ -160,8 +186,8 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
|
||||
_debugger = new asDebugger(this);
|
||||
|
||||
// Register the to-string callbacks so the user can see the contents of
|
||||
// strings
|
||||
// Register the to-string callbacks so the user can see
|
||||
// the contents of strings
|
||||
_debugger->registerToStringCallback(_rtypes[RegisteredType::tString],
|
||||
&AngelObjString::stringToString);
|
||||
_debugger->registerToStringCallback(_rtypes[RegisteredType::tChar],
|
||||
|
@ -175,6 +201,9 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
|
|||
|
||||
PluginSystem::instance().angelApi()->installAPI(this);
|
||||
|
||||
// create module for Console
|
||||
_engine->GetModule("WINGCONSOLE", asGM_ALWAYS_CREATE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -198,34 +227,64 @@ QString ScriptMachine::getCallStack(asIScriptContext *context) {
|
|||
}
|
||||
|
||||
void ScriptMachine::destoryMachine() {
|
||||
_debugger->setEngine(nullptr);
|
||||
_engine->ShutDownAndRelease();
|
||||
_engine = nullptr;
|
||||
}
|
||||
|
||||
void ScriptMachine::exceptionCallback(asIScriptContext *context) {
|
||||
QString message =
|
||||
tr("- Exception '%1' in '%2'\n")
|
||||
.arg(context->GetExceptionString(),
|
||||
context->GetExceptionFunction()->GetDeclaration()) +
|
||||
QStringLiteral("\n") + getCallStack(context);
|
||||
if (context) {
|
||||
ConsoleMode mode = ConsoleMode(reinterpret_cast<asPWORD>(
|
||||
context->GetUserData(AsUserDataType::UserData_ContextMode)));
|
||||
QString message =
|
||||
tr("- Exception '%1' in '%2'\n")
|
||||
.arg(context->GetExceptionString(),
|
||||
context->GetExceptionFunction()->GetDeclaration()) +
|
||||
QStringLiteral("\n") + getCallStack(context);
|
||||
|
||||
const char *section;
|
||||
MessageInfo msg;
|
||||
msg.row = context->GetExceptionLineNumber(&msg.col, §ion);
|
||||
msg.type = asMSGTYPE_ERROR;
|
||||
msg.message = message;
|
||||
emit onOutput(MessageType::Error, msg);
|
||||
const char *section;
|
||||
MessageInfo msg;
|
||||
msg.row = context->GetExceptionLineNumber(&msg.col, §ion);
|
||||
msg.type = MessageType::Error;
|
||||
msg.message = message;
|
||||
|
||||
outputMessage(mode, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptMachine::print(void *ref, int typeId) {
|
||||
MessageInfo info;
|
||||
info.message = _debugger->toString(ref, typeId, _engine);
|
||||
emit onOutput(MessageType::Print, info);
|
||||
auto context = asGetActiveContext();
|
||||
if (context) {
|
||||
ConsoleMode mode = ConsoleMode(reinterpret_cast<asPWORD>(
|
||||
context->GetUserData(AsUserDataType::UserData_ContextMode)));
|
||||
|
||||
MessageInfo info;
|
||||
info.type = MessageType::Print;
|
||||
info.message = _debugger->toString(ref, typeId, _engine);
|
||||
|
||||
outputMessage(mode, info);
|
||||
}
|
||||
}
|
||||
|
||||
QString ScriptMachine::getInput() {
|
||||
Q_ASSERT(_getInputFn);
|
||||
return _getInputFn();
|
||||
auto context = asGetActiveContext();
|
||||
if (context) {
|
||||
ConsoleMode mode = ConsoleMode(reinterpret_cast<asPWORD>(
|
||||
context->GetUserData(AsUserDataType::UserData_ContextMode)));
|
||||
|
||||
auto cbs = _regcalls.value(mode);
|
||||
if (cbs.getInputFn) {
|
||||
return cbs.getInputFn();
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void ScriptMachine::outputMessage(ConsoleMode mode, const MessageInfo &info) {
|
||||
auto cbs = _regcalls.value(mode);
|
||||
if (cbs.printMsgFn) {
|
||||
cbs.printMsgFn(info);
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptMachine::isType(asITypeInfo *tinfo, RegisteredType type) {
|
||||
|
@ -257,11 +316,32 @@ int ScriptMachine::execSystemCmd(QString &out, const QString &exe,
|
|||
}
|
||||
}
|
||||
|
||||
bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
||||
// We will only initialize the global variables once we're
|
||||
// ready to execute, so disable the automatic initialization
|
||||
_engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false);
|
||||
setDebugMode(isInDebug);
|
||||
bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
|
||||
bool isInDebug) {
|
||||
// Compile the script
|
||||
auto mod = createModule(mode);
|
||||
// script-running is not allowed in interactive mode
|
||||
if (mod == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QScopeGuard guard([mod, mode]() {
|
||||
if (mode != ConsoleMode::Interactive) {
|
||||
// Before leaving, allow the engine to clean up remaining objects by
|
||||
// discarding the module and doing a full garbage collection so that
|
||||
// this can also be debugged if desired
|
||||
mod->Discard();
|
||||
}
|
||||
});
|
||||
|
||||
asPWORD isDbg = 0;
|
||||
if (mode == Scripting) {
|
||||
if (isInDebug) {
|
||||
isDbg = 1;
|
||||
_debugger->resetState();
|
||||
}
|
||||
}
|
||||
_engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, isDbg == 0);
|
||||
|
||||
asBuilder builder(_engine);
|
||||
for (auto &m : PluginSystem::instance().scriptMarcos()) {
|
||||
|
@ -272,27 +352,17 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
builder.setPragmaCallback(&ScriptMachine::pragmaCallback, this);
|
||||
builder.setIncludeCallback(&ScriptMachine::includeCallback, this);
|
||||
|
||||
// Compile the script
|
||||
auto r = builder.StartNewModule("script");
|
||||
auto r = builder.loadSectionFromFile(script.toUtf8());
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r = builder.loadSectionFromFile(script.toUtf8());
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r = builder.Build();
|
||||
r = builder.build(mod);
|
||||
if (r < 0) {
|
||||
MessageInfo info;
|
||||
info.message = tr("Script failed to build");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
return false;
|
||||
}
|
||||
|
||||
asIScriptModule *mod = builder.GetModule();
|
||||
if (!mod) {
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -306,19 +376,17 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
if (func == nullptr) {
|
||||
MessageInfo info;
|
||||
info.message = tr("Cannot find 'int main()' or 'void main()'");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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.");
|
||||
emit onOutput(MessageType::Info, info);
|
||||
info.type = MessageType::Info;
|
||||
outputMessage(mode, info);
|
||||
}
|
||||
|
||||
// Once we have the main function, we first need to initialize the global
|
||||
|
@ -328,7 +396,8 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
if (r < 0) {
|
||||
MessageInfo info;
|
||||
info.message = tr("Failed while initializing global variables");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -336,6 +405,16 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
// The context manager will request the context from the
|
||||
// pool, which will automatically attach the debugger
|
||||
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
|
||||
|
||||
ctx->SetUserData(reinterpret_cast<void *>(isDbg),
|
||||
AsUserDataType::UserData_isDbg);
|
||||
mod->SetUserData(reinterpret_cast<void *>(isDbg),
|
||||
AsUserDataType::UserData_isDbg);
|
||||
|
||||
asPWORD umode = asPWORD(mode);
|
||||
ctx->SetUserData(reinterpret_cast<void *>(umode),
|
||||
AsUserDataType::UserData_ContextMode);
|
||||
|
||||
ctx->SetExceptionCallback(asMETHOD(ScriptMachine, exceptionCallback), this,
|
||||
asCALL_THISCALL);
|
||||
|
||||
|
@ -353,12 +432,14 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
info.message = tr("The script failed with an exception") +
|
||||
QStringLiteral("\n") +
|
||||
QString::fromStdString(GetExceptionInfo(ctx, true));
|
||||
emit onOutput(MessageType::Error, info);
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
r = -1;
|
||||
} else if (r == asEXECUTION_ABORTED) {
|
||||
MessageInfo info;
|
||||
info.message = tr("The script was aborted");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
r = -1;
|
||||
} else {
|
||||
auto e = QMetaEnum::fromType<asEContextState>();
|
||||
|
@ -366,7 +447,8 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
info.message = tr("The script terminated unexpectedly") +
|
||||
QStringLiteral(" (") + e.valueToKey(r) +
|
||||
QStringLiteral(")");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
r = -1;
|
||||
}
|
||||
} else {
|
||||
|
@ -379,7 +461,8 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
|
||||
MessageInfo info;
|
||||
info.message = tr("The script exited with ") + QString::number(r);
|
||||
emit onOutput(MessageType::Info, info);
|
||||
info.type = MessageType::Info;
|
||||
outputMessage(mode, info);
|
||||
|
||||
// Return the context after retrieving the return value
|
||||
_ctxMgr->DoneWithContext(ctx);
|
||||
|
@ -389,31 +472,21 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
|
|||
// this can also be debugged if desired
|
||||
_engine->GarbageCollect();
|
||||
|
||||
// Release all contexts that have been allocated
|
||||
for (auto &ctx : _ctxPool) {
|
||||
ctx->Release();
|
||||
}
|
||||
|
||||
_ctxPool.clear();
|
||||
|
||||
// Detach debugger
|
||||
Q_ASSERT(_debugger);
|
||||
_debugger->setEngine(nullptr);
|
||||
|
||||
if (isInDebug) {
|
||||
if (isDbg) {
|
||||
_debugger->clearBreakPoint();
|
||||
setDebugMode(false);
|
||||
emit onDebugFinished();
|
||||
}
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
void ScriptMachine::abortScript() {
|
||||
void ScriptMachine::abortDbgScript(ConsoleMode mode) {
|
||||
if (_debugger->getEngine()) {
|
||||
_debugger->runDebugAction(asDebugger::ABORT);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptMachine::abortScript() { _ctxMgr->AbortAll(); }
|
||||
|
||||
void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) {
|
||||
MessageType t = MessageType::Print;
|
||||
switch (msg->type) {
|
||||
|
@ -438,7 +511,8 @@ void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) {
|
|||
info.col = msg->col;
|
||||
info.section = msg->section;
|
||||
info.message = m;
|
||||
emit ins->onOutput(t, info);
|
||||
info.type = t;
|
||||
ins->outputMessage(ins->_curMode, info);
|
||||
}
|
||||
|
||||
void ScriptMachine::cleanUpDbgContext(asIScriptContext *context) {
|
||||
|
@ -460,17 +534,56 @@ asITypeInfo *ScriptMachine::typeInfo(RegisteredType type) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ScriptMachine::ScriptMachine(const std::function<QString()> &getInputFn,
|
||||
QObject *parent)
|
||||
: QObject(parent), _getInputFn(getInputFn) {
|
||||
Q_ASSERT(getInputFn);
|
||||
qRegisterMetaType<MessageInfo>();
|
||||
ScriptMachine &ScriptMachine::instance() {
|
||||
static ScriptMachine ins;
|
||||
return ins;
|
||||
}
|
||||
|
||||
_engine = asCreateScriptEngine();
|
||||
if (!ScriptMachine::configureEngine(_engine)) {
|
||||
_engine->ShutDownAndRelease();
|
||||
_engine = nullptr;
|
||||
ScriptMachine::ScriptMachine() : QObject() {}
|
||||
|
||||
asIScriptModule *ScriptMachine::createModule(ConsoleMode mode) {
|
||||
if (isModuleExists(mode)) {
|
||||
return nullptr;
|
||||
}
|
||||
switch (mode) {
|
||||
case Interactive:
|
||||
return nullptr;
|
||||
case Scripting:
|
||||
return _engine->GetModule("WINGSCRIPT", asGM_ALWAYS_CREATE);
|
||||
case Background:
|
||||
return _engine->GetModule("WINGSRV", asGM_ALWAYS_CREATE);
|
||||
}
|
||||
// should not go there
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
asIScriptModule *ScriptMachine::createModuleIfNotExist(ConsoleMode mode) {
|
||||
switch (mode) {
|
||||
case Interactive:
|
||||
return _engine->GetModule("WINGCONSOLE", asGM_ONLY_IF_EXISTS);
|
||||
case Scripting:
|
||||
return _engine->GetModule("WINGSCRIPT", asGM_CREATE_IF_NOT_EXISTS);
|
||||
case Background:
|
||||
return _engine->GetModule("WINGSRV", asGM_CREATE_IF_NOT_EXISTS);
|
||||
}
|
||||
// should not go there
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
asIScriptModule *ScriptMachine::module(ConsoleMode mode) {
|
||||
switch (mode) {
|
||||
case Interactive:
|
||||
return _engine->GetModule("WINGCONSOLE", asGM_ONLY_IF_EXISTS);
|
||||
case Scripting:
|
||||
return _engine->GetModule("WINGSCRIPT", asGM_ONLY_IF_EXISTS);
|
||||
case Background:
|
||||
return _engine->GetModule("WINGSRV", asGM_ONLY_IF_EXISTS);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ScriptMachine::isModuleExists(ConsoleMode mode) {
|
||||
return module(mode) != nullptr;
|
||||
}
|
||||
|
||||
asIScriptContext *ScriptMachine::requestContextCallback(asIScriptEngine *engine,
|
||||
|
@ -808,8 +921,6 @@ QString ScriptMachine::processTranslation(const char *content,
|
|||
}},
|
||||
{QRegularExpression(QStringLiteral("^Instead found '(.*?)'")),
|
||||
[machine](const QStringList &contents) -> QString {
|
||||
if (machine->m_insteadFoundDisabled)
|
||||
return {};
|
||||
return tr("Instead found '%1'").arg(contents.at(1));
|
||||
}},
|
||||
{QRegularExpression(
|
||||
|
@ -1588,14 +1699,6 @@ void ScriptMachine::translation() {
|
|||
tr("Too many nested calls");
|
||||
}
|
||||
|
||||
bool ScriptMachine::insteadFoundDisabled() const {
|
||||
return m_insteadFoundDisabled;
|
||||
}
|
||||
|
||||
void ScriptMachine::setInsteadFoundDisabled(bool newInsteadFoundDisabled) {
|
||||
m_insteadFoundDisabled = newInsteadFoundDisabled;
|
||||
}
|
||||
|
||||
void ScriptMachine::registerEngineAddon(asIScriptEngine *engine) {
|
||||
RegisterScriptArray(engine, true);
|
||||
RegisterQString(engine);
|
||||
|
@ -1649,6 +1752,11 @@ void ScriptMachine::registerEngineAssert(asIScriptEngine *engine) {
|
|||
}
|
||||
}
|
||||
|
||||
void ScriptMachine::registerCallBack(ConsoleMode mode,
|
||||
const RegCallBacks &callbacks) {
|
||||
_regcalls.insert(mode, callbacks);
|
||||
}
|
||||
|
||||
void ScriptMachine::scriptAssert(bool b) {
|
||||
auto ctx = asGetActiveContext();
|
||||
if (ctx) {
|
||||
|
@ -1679,28 +1787,35 @@ void ScriptMachine::scriptThrow(const QString &msg) {
|
|||
}
|
||||
}
|
||||
|
||||
bool ScriptMachine::isDebugMode() const {
|
||||
return !_engine->GetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES);
|
||||
}
|
||||
bool ScriptMachine::isDebugMode(ConsoleMode mode) {
|
||||
if (mode == Scripting) {
|
||||
auto mod = module(mode);
|
||||
if (mod) {
|
||||
return reinterpret_cast<asPWORD>(
|
||||
mod->GetUserData(AsUserDataType::UserData_isDbg));
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptMachine::setDebugMode(bool isDbg) {
|
||||
_engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, !isDbg);
|
||||
return false;
|
||||
}
|
||||
|
||||
asIScriptEngine *ScriptMachine::engine() const { return _engine; }
|
||||
|
||||
asDebugger *ScriptMachine::debugger() const { return _debugger; }
|
||||
|
||||
bool ScriptMachine::executeCode(const QString &code) {
|
||||
// We will only initialize the global variables once we're
|
||||
// ready to execute, so disable the automatic initialization
|
||||
_engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false);
|
||||
setDebugMode(false);
|
||||
bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
|
||||
asIScriptModule *mod = createModuleIfNotExist(mode);
|
||||
|
||||
asIScriptModule *mod = _engine->GetModule("Console", asGM_ONLY_IF_EXISTS);
|
||||
if (!mod) {
|
||||
return false;
|
||||
}
|
||||
QScopeGuard guard([mod, mode]() {
|
||||
if (mode != ConsoleMode::Interactive) {
|
||||
// Before leaving, allow the engine to clean up remaining objects by
|
||||
// discarding the module and doing a full garbage collection so that
|
||||
// this can also be debugged if desired
|
||||
mod->Discard();
|
||||
}
|
||||
});
|
||||
|
||||
_engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, false);
|
||||
|
||||
// first, preparse the code
|
||||
QAsCodeParser parser(_engine);
|
||||
|
@ -1717,9 +1832,10 @@ bool ScriptMachine::executeCode(const QString &code) {
|
|||
auto r = mod->CompileFunction(nullptr, ccode, -1, 0, &func);
|
||||
if (r < 0) {
|
||||
MessageInfo info;
|
||||
info.mode = mode;
|
||||
info.message = tr("Script failed to build");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
mod->Discard();
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
|
@ -1728,9 +1844,10 @@ bool ScriptMachine::executeCode(const QString &code) {
|
|||
auto r = mod->Build();
|
||||
if (r < 0) {
|
||||
MessageInfo info;
|
||||
info.mode = mode;
|
||||
info.message = tr("Script failed to build");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
mod->Discard();
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1743,21 +1860,29 @@ bool ScriptMachine::executeCode(const QString &code) {
|
|||
|
||||
if (func == nullptr) {
|
||||
MessageInfo info;
|
||||
info.mode = mode;
|
||||
info.message = tr("Cannot find 'int main()' or 'void main()'");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
mod->Discard();
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Let the debugger hold an engine pointer that can be used by the
|
||||
// callbacks
|
||||
_debugger->setEngine(_engine);
|
||||
|
||||
// Set up a context to execute the script
|
||||
// The context manager will request the context from the
|
||||
// pool, which will automatically attach the debugger
|
||||
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
|
||||
|
||||
asPWORD isDbg = 0;
|
||||
ctx->SetUserData(reinterpret_cast<void *>(isDbg),
|
||||
AsUserDataType::UserData_isDbg);
|
||||
mod->SetUserData(reinterpret_cast<void *>(isDbg),
|
||||
AsUserDataType::UserData_isDbg);
|
||||
|
||||
asPWORD umode = asPWORD(mode);
|
||||
ctx->SetUserData(reinterpret_cast<void *>(umode),
|
||||
AsUserDataType::UserData_ContextMode);
|
||||
|
||||
ctx->SetExceptionCallback(asMETHOD(ScriptMachine, exceptionCallback), this,
|
||||
asCALL_THISCALL);
|
||||
|
||||
|
@ -1772,15 +1897,19 @@ bool ScriptMachine::executeCode(const QString &code) {
|
|||
if (r != asEXECUTION_FINISHED) {
|
||||
if (r == asEXECUTION_EXCEPTION) {
|
||||
MessageInfo info;
|
||||
info.mode = mode;
|
||||
info.message = tr("The script failed with an exception") +
|
||||
QStringLiteral("\n") +
|
||||
QString::fromStdString(GetExceptionInfo(ctx, true));
|
||||
emit onOutput(MessageType::Error, info);
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
r = -1;
|
||||
} else if (r == asEXECUTION_ABORTED) {
|
||||
MessageInfo info;
|
||||
info.mode = mode;
|
||||
info.message = tr("The script was aborted");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
r = -1;
|
||||
} else {
|
||||
auto e = QMetaEnum::fromType<asEContextState>();
|
||||
|
@ -1788,7 +1917,8 @@ bool ScriptMachine::executeCode(const QString &code) {
|
|||
info.message = tr("The script terminated unexpectedly") +
|
||||
QStringLiteral(" (") + e.valueToKey(r) +
|
||||
QStringLiteral(")");
|
||||
emit onOutput(MessageType::Error, info);
|
||||
info.type = MessageType::Error;
|
||||
outputMessage(mode, info);
|
||||
r = -1;
|
||||
}
|
||||
} else {
|
||||
|
@ -1797,24 +1927,8 @@ bool ScriptMachine::executeCode(const QString &code) {
|
|||
|
||||
// Return the context after retrieving the return value
|
||||
_ctxMgr->DoneWithContext(ctx);
|
||||
|
||||
// Before leaving, allow the engine to clean up remaining objects by
|
||||
// discarding the module and doing a full garbage collection so that
|
||||
// this can also be debugged if desired
|
||||
mod->Discard();
|
||||
_engine->GarbageCollect();
|
||||
|
||||
// Release all contexts that have been allocated
|
||||
for (auto ctx : std::as_const(_ctxPool)) {
|
||||
ctx->Release();
|
||||
}
|
||||
|
||||
_ctxPool.clear();
|
||||
|
||||
// Detach debugger
|
||||
Q_ASSERT(_debugger);
|
||||
_debugger->setEngine(nullptr);
|
||||
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -31,14 +31,23 @@ class ScriptMachine : public QObject {
|
|||
private:
|
||||
using TranslateFunc = std::function<QString(const QStringList &)>;
|
||||
|
||||
public:
|
||||
// we have three console modes
|
||||
enum ConsoleMode {
|
||||
Interactive, // in a shell
|
||||
Scripting, // in scripting dialog
|
||||
Background // run codes from other way
|
||||
};
|
||||
|
||||
public:
|
||||
enum class MessageType { Info, Warn, Error, Print };
|
||||
|
||||
struct MessageInfo {
|
||||
ConsoleMode mode = ConsoleMode::Background;
|
||||
QString section;
|
||||
int row = -1;
|
||||
int col = -1;
|
||||
asEMsgType type = asEMsgType::asMSGTYPE_INFORMATION;
|
||||
MessageType type = MessageType::Info;
|
||||
QString message;
|
||||
};
|
||||
|
||||
|
@ -78,25 +87,42 @@ public:
|
|||
Q_ENUM(asEContextState)
|
||||
|
||||
public:
|
||||
explicit ScriptMachine(const std::function<QString()> &getInputFn,
|
||||
QObject *parent = nullptr);
|
||||
struct RegCallBacks {
|
||||
std::function<QString()> getInputFn;
|
||||
std::function<void()> clearFn;
|
||||
std::function<void(const ScriptMachine::MessageInfo &)> printMsgFn;
|
||||
};
|
||||
|
||||
private:
|
||||
explicit ScriptMachine();
|
||||
Q_DISABLE_COPY_MOVE(ScriptMachine)
|
||||
|
||||
public:
|
||||
asIScriptModule *createModule(ConsoleMode mode);
|
||||
asIScriptModule *createModuleIfNotExist(ConsoleMode mode);
|
||||
asIScriptModule *module(ConsoleMode mode);
|
||||
bool isModuleExists(ConsoleMode mode);
|
||||
|
||||
public:
|
||||
static ScriptMachine &instance();
|
||||
|
||||
virtual ~ScriptMachine();
|
||||
|
||||
bool inited();
|
||||
|
||||
bool isRunning() const;
|
||||
|
||||
asDebugger *debugger() const;
|
||||
|
||||
asIScriptEngine *engine() const;
|
||||
|
||||
bool insteadFoundDisabled() const;
|
||||
void setInsteadFoundDisabled(bool newInsteadFoundDisabled);
|
||||
public:
|
||||
bool init();
|
||||
bool isInited() const;
|
||||
bool isRunning(ConsoleMode mode = Scripting) const;
|
||||
|
||||
static void registerEngineAddon(asIScriptEngine *engine);
|
||||
static void registerEngineAssert(asIScriptEngine *engine);
|
||||
|
||||
void registerCallBack(ConsoleMode mode, const RegCallBacks &callbacks);
|
||||
|
||||
public:
|
||||
asDebugger *debugger() const;
|
||||
|
||||
asIScriptEngine *engine() const;
|
||||
|
||||
public:
|
||||
static void scriptAssert(bool b);
|
||||
static void scriptAssert_X(bool b, const QString &msg);
|
||||
|
@ -109,20 +135,19 @@ public:
|
|||
|
||||
public:
|
||||
// debug or release?
|
||||
bool isDebugMode() const;
|
||||
void setDebugMode(bool isDbg);
|
||||
bool isDebugMode(ConsoleMode mode = Scripting);
|
||||
|
||||
public slots:
|
||||
virtual bool executeCode(const QString &code);
|
||||
virtual bool executeScript(const QString &script, bool isInDebug = false);
|
||||
bool executeCode(ConsoleMode mode, const QString &code);
|
||||
// only scripting mode can be debugged
|
||||
bool executeScript(ConsoleMode mode, const QString &script,
|
||||
bool isInDebug = false);
|
||||
|
||||
void abortDbgScript(ConsoleMode mode);
|
||||
void abortScript();
|
||||
|
||||
private:
|
||||
bool execute(const QString &code, bool isInDebug = false);
|
||||
|
||||
protected:
|
||||
virtual bool configureEngine(asIScriptEngine *engine);
|
||||
bool configureEngine();
|
||||
|
||||
QString getCallStack(asIScriptContext *context);
|
||||
|
||||
|
@ -130,8 +155,8 @@ protected:
|
|||
|
||||
private:
|
||||
void print(void *ref, int typeId);
|
||||
|
||||
QString getInput();
|
||||
void outputMessage(ConsoleMode mode, const MessageInfo &info);
|
||||
|
||||
bool isType(asITypeInfo *tinfo, RegisteredType type);
|
||||
|
||||
|
@ -166,8 +191,6 @@ private:
|
|||
Q_DECL_UNUSED void translation();
|
||||
|
||||
signals:
|
||||
void onOutput(MessageType type, const MessageInfo &message);
|
||||
|
||||
void onDebugFinished();
|
||||
|
||||
private:
|
||||
|
@ -175,12 +198,10 @@ private:
|
|||
asDebugger *_debugger = nullptr;
|
||||
asContextMgr *_ctxMgr = nullptr;
|
||||
QVector<asIScriptContext *> _ctxPool;
|
||||
std::function<void(void *ref, int typeId)> _printFn;
|
||||
|
||||
QVector<asITypeInfo *> _rtypes;
|
||||
std::function<QString(void)> _getInputFn;
|
||||
|
||||
bool m_insteadFoundDisabled = false;
|
||||
QMap<ConsoleMode, RegCallBacks> _regcalls;
|
||||
ConsoleMode _curMode = ConsoleMode::Background;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ScriptMachine::MessageInfo)
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <QJsonObject>
|
||||
#include <QMenu>
|
||||
|
||||
#include "scriptmachine.h"
|
||||
#include "settingmanager.h"
|
||||
#include "utilities.h"
|
||||
#include "wingmessagebox.h"
|
||||
|
@ -50,7 +51,7 @@ ScriptManager::ScriptManager() : QObject() {
|
|||
refresh();
|
||||
}
|
||||
|
||||
ScriptManager::~ScriptManager() { detach(); }
|
||||
ScriptManager::~ScriptManager() {}
|
||||
|
||||
QStringList ScriptManager::getScriptFileNames(const QDir &dir) const {
|
||||
if (!dir.exists()) {
|
||||
|
@ -206,14 +207,6 @@ ScriptManager::ensureDirMeta(const QFileInfo &info) {
|
|||
return meta;
|
||||
}
|
||||
|
||||
void ScriptManager::attach(ScriptingConsole *console) {
|
||||
if (console) {
|
||||
_console = console;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptManager::detach() { _console = nullptr; }
|
||||
|
||||
ScriptManager::ScriptDirMeta
|
||||
ScriptManager::usrDirMeta(const QString &cat) const {
|
||||
return _usrDirMetas.value(cat);
|
||||
|
@ -257,13 +250,16 @@ ScriptManager::buildUpRibbonScriptRunner(RibbonButtonGroup *group) {
|
|||
}
|
||||
|
||||
void ScriptManager::runScript(const QString &filename) {
|
||||
Q_ASSERT(_console);
|
||||
_console->setMode(ScriptingConsole::Output);
|
||||
_console->stdWarn(tr("Excuting:") + filename);
|
||||
_console->newLine();
|
||||
_console->machine()->executeScript(filename);
|
||||
_console->appendCommandPrompt();
|
||||
_console->setMode(ScriptingConsole::Input);
|
||||
// ScriptMachine::instance().executeScript(filename);
|
||||
|
||||
// Q_ASSERT(_console);
|
||||
// _console->setMode(ScriptingConsole::Output);
|
||||
// _console->stdWarn(tr("Excuting:") + filename);
|
||||
// _console->newLine();
|
||||
// // TODO
|
||||
// // _console->machine()->executeScript(filename);
|
||||
// _console->appendCommandPrompt();
|
||||
// _console->setMode(ScriptingConsole::Input);
|
||||
}
|
||||
|
||||
QStringList ScriptManager::usrScriptsDbCats() const {
|
||||
|
|
|
@ -65,9 +65,6 @@ public:
|
|||
void refreshUsrScriptsDbCats();
|
||||
void refreshSysScriptsDbCats();
|
||||
|
||||
void attach(ScriptingConsole *console);
|
||||
void detach();
|
||||
|
||||
ScriptDirMeta usrDirMeta(const QString &cat) const;
|
||||
ScriptDirMeta sysDirMeta(const QString &cat) const;
|
||||
|
||||
|
@ -133,8 +130,6 @@ private:
|
|||
|
||||
QHash<QString, ScriptDirMeta> _usrDirMetas;
|
||||
QHash<QString, ScriptDirMeta> _sysDirMetas;
|
||||
|
||||
ScriptingConsole *_console = nullptr;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ScriptManager::ScriptDirMeta)
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "class/scriptmachine.h"
|
||||
#include "class/wingfiledialog.h"
|
||||
#include "class/winginputdialog.h"
|
||||
#include "control/scriptingconsole.h"
|
||||
#include "define.h"
|
||||
#include "scriptaddon/scriptqdictionary.h"
|
||||
|
||||
|
@ -2084,44 +2083,35 @@ bool WingAngelAPI::execScriptCode(const WingHex::SenderInfo &sender,
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_console) {
|
||||
QTemporaryFile f;
|
||||
if (f.open()) {
|
||||
f.write(code.toUtf8());
|
||||
f.close();
|
||||
}
|
||||
|
||||
_console->setMode(ScriptingConsole::Output);
|
||||
_console->stdOut(getSenderHeader(sender));
|
||||
auto handles = _handles;
|
||||
_console->machine()->executeScript(f.fileName());
|
||||
cleanUpHandles(handles);
|
||||
_console->appendCommandPrompt();
|
||||
_console->setMode(ScriptingConsole::Input);
|
||||
QTemporaryFile f;
|
||||
if (f.open()) {
|
||||
f.write(code.toUtf8());
|
||||
f.close();
|
||||
}
|
||||
|
||||
auto handles = _handles;
|
||||
ScriptMachine::instance().executeScript(ScriptMachine::Background,
|
||||
f.fileName());
|
||||
cleanUpHandles(handles);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WingAngelAPI::execScript(const WingHex::SenderInfo &sender,
|
||||
const QString &fileName) {
|
||||
_console->setMode(ScriptingConsole::Output);
|
||||
_console->stdOut(getSenderHeader(sender));
|
||||
auto handles = _handles;
|
||||
auto ret = _console->machine()->executeScript(fileName);
|
||||
auto ret = ScriptMachine::instance().executeScript(
|
||||
ScriptMachine::Background, fileName);
|
||||
cleanUpHandles(handles);
|
||||
_console->appendCommandPrompt();
|
||||
_console->setMode(ScriptingConsole::Input);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool WingAngelAPI::execCode(const WingHex::SenderInfo &sender,
|
||||
const QString &code) {
|
||||
_console->setMode(ScriptingConsole::Output);
|
||||
_console->stdOut(getSenderHeader(sender));
|
||||
auto ret = _console->machine()->executeCode(code);
|
||||
_console->appendCommandPrompt();
|
||||
_console->setMode(ScriptingConsole::Input);
|
||||
auto handles = _handles;
|
||||
auto ret =
|
||||
ScriptMachine::instance().executeCode(ScriptMachine::Background, code);
|
||||
cleanUpHandles(handles);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -2175,7 +2165,7 @@ void *WingAngelAPI::vector2AsArray(const WingHex::SenderInfo &sender,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto engine = _console->machine()->engine();
|
||||
auto engine = ScriptMachine::instance().engine();
|
||||
auto info = engine->GetTypeInfoByDecl(typeStr.toUtf8());
|
||||
if (info) {
|
||||
auto len = content.length();
|
||||
|
@ -2197,7 +2187,7 @@ void *WingAngelAPI::list2AsArray(const WingHex::SenderInfo &sender,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
auto engine = _console->machine()->engine();
|
||||
auto engine = ScriptMachine::instance().engine();
|
||||
auto info = engine->GetTypeInfoByDecl(typeStr.toUtf8());
|
||||
if (info) {
|
||||
auto len = content.length();
|
||||
|
@ -2222,7 +2212,7 @@ void *WingAngelAPI::newAsDictionary(
|
|||
const WingHex::SenderInfo &sender,
|
||||
const QHash<QString, QPair<MetaType, void *>> &content) {
|
||||
Q_UNUSED(sender);
|
||||
auto engine = _console->machine()->engine();
|
||||
auto engine = ScriptMachine::instance().engine();
|
||||
auto dic = CScriptDictionary::Create(engine);
|
||||
|
||||
for (auto p = content.constKeyValueBegin(); p != content.constKeyValueEnd();
|
||||
|
@ -2248,11 +2238,6 @@ void WingAngelAPI::deleteAsDictionary(const WingHex::SenderInfo &sender,
|
|||
}
|
||||
}
|
||||
|
||||
QString WingAngelAPI::getSenderHeader(const WingHex::SenderInfo &sender) {
|
||||
return QStringLiteral("(") + sender.puid + QStringLiteral("::") +
|
||||
sender.plgcls + QStringLiteral(") ");
|
||||
}
|
||||
|
||||
void WingAngelAPI::cleanUpHandles(const QVector<int> &handles) {
|
||||
for (auto &h : _handles) {
|
||||
if (!handles.contains(h)) {
|
||||
|
@ -2510,7 +2495,3 @@ bool WingAngelAPI::_DataVisual_updateTextTable(const QString &json,
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WingAngelAPI::setBindingConsole(ScriptingConsole *console) {
|
||||
_console = console;
|
||||
}
|
||||
|
|
|
@ -73,9 +73,6 @@ public:
|
|||
void installAPI(ScriptMachine *machine);
|
||||
void installBasicTypes(asIScriptEngine *engine);
|
||||
|
||||
void setBindingConsole(ScriptingConsole *console);
|
||||
void unBindConsole();
|
||||
|
||||
static QString qvariantCastASString(const QMetaType::Type &id);
|
||||
|
||||
static int qvariantCastASID(asIScriptEngine *engine,
|
||||
|
@ -203,8 +200,6 @@ private:
|
|||
|
||||
// =========================================================
|
||||
|
||||
QString getSenderHeader(const WingHex::SenderInfo &sender);
|
||||
|
||||
void cleanUpHandles(const QVector<int> &handles);
|
||||
|
||||
private:
|
||||
|
@ -261,8 +256,6 @@ private:
|
|||
QVector<IWingPlugin::UNSAFE_SCFNPTR> _usfns;
|
||||
QHash<QString, QHash<QString, qsizetype>> _urfns;
|
||||
|
||||
ScriptingConsole *_console = nullptr;
|
||||
|
||||
QHash<QString, QHash<QString, QList<QPair<QString, int>>>> _objs;
|
||||
|
||||
QVector<int> _handles;
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include "class/ascompletion.h"
|
||||
#include "class/clangformatmanager.h"
|
||||
|
||||
ScriptEditor::ScriptEditor(asIScriptEngine *engine, QWidget *parent)
|
||||
ScriptEditor::ScriptEditor(QWidget *parent)
|
||||
: ads::CDockWidget(nullptr, QString(), parent) {
|
||||
this->setFeatures(
|
||||
CDockWidget::DockWidgetFocusable | CDockWidget::DockWidgetMovable |
|
||||
|
@ -48,7 +48,7 @@ ScriptEditor::ScriptEditor(asIScriptEngine *engine, QWidget *parent)
|
|||
m_editor->setSyntax(
|
||||
m_editor->syntaxRepo().definitionForName("AngelScript"));
|
||||
|
||||
auto cm = new AsCompletion(engine, m_editor);
|
||||
auto cm = new AsCompletion(m_editor);
|
||||
connect(cm, &AsCompletion::onFunctionTip, this,
|
||||
&ScriptEditor::onFunctionTip);
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ class ScriptEditor : public ads::CDockWidget {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ScriptEditor(asIScriptEngine *engine, QWidget *parent = nullptr);
|
||||
explicit ScriptEditor(QWidget *parent = nullptr);
|
||||
virtual ~ScriptEditor();
|
||||
|
||||
QString fileName() const;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "scriptingconsole.h"
|
||||
#include "QConsoleWidget/QConsoleIODevice.h"
|
||||
#include "class/logger.h"
|
||||
#include "class/scriptconsolemachine.h"
|
||||
#include "class/scriptmachine.h"
|
||||
#include "class/scriptsettings.h"
|
||||
#include "class/skinmanager.h"
|
||||
#include "model/codecompletionmodel.h"
|
||||
|
@ -91,103 +91,16 @@ void ScriptingConsole::handleReturnKey() {
|
|||
void ScriptingConsole::init() {
|
||||
_getInputFn = std::bind(&ScriptingConsole::getInput, this);
|
||||
|
||||
_sp = new ScriptConsoleMachine(_getInputFn, this);
|
||||
connect(_sp, &ScriptConsoleMachine::onClearConsole, this,
|
||||
&ScriptingConsole::clear);
|
||||
connect(this, &ScriptingConsole::abortEvaluation, _sp,
|
||||
&ScriptConsoleMachine::abortScript);
|
||||
|
||||
connect(
|
||||
_sp, &ScriptConsoleMachine::onOutput, this,
|
||||
[=](ScriptConsoleMachine::MessageType type,
|
||||
const ScriptConsoleMachine::MessageInfo &message) {
|
||||
// <type, <row, col>>
|
||||
static QPair<ScriptConsoleMachine::MessageType, QPair<int, int>>
|
||||
lastInfo{ScriptConsoleMachine::MessageType::Print, {-1, -1}};
|
||||
|
||||
auto doc = this->document();
|
||||
auto lastLine = doc->lastBlock();
|
||||
auto isNotBlockStart = !lastLine.text().isEmpty();
|
||||
|
||||
auto fmtMsg = [](const ScriptConsoleMachine::MessageInfo &message)
|
||||
-> QString {
|
||||
if (message.row <= 0 || message.col <= 0) {
|
||||
return message.message;
|
||||
} else {
|
||||
return QStringLiteral("(") + QString::number(message.row) +
|
||||
QStringLiteral(", ") + QString::number(message.col) +
|
||||
QStringLiteral(") ") + message.message;
|
||||
}
|
||||
};
|
||||
|
||||
auto isMatchLast =
|
||||
[](ScriptConsoleMachine::MessageType type,
|
||||
const ScriptConsoleMachine::MessageInfo &message) -> bool {
|
||||
if (message.row < 0 || message.col < 0) {
|
||||
return false;
|
||||
}
|
||||
return lastInfo.first == type &&
|
||||
lastInfo.second.first == message.row &&
|
||||
lastInfo.second.second == message.col;
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case ScriptMachine::MessageType::Info:
|
||||
if (isMatchLast(type, message)) {
|
||||
stdOut(message.message);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
newLine();
|
||||
}
|
||||
stdOut(tr("[Info]") + fmtMsg(message));
|
||||
}
|
||||
flush();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Warn:
|
||||
if (isMatchLast(type, message)) {
|
||||
stdWarn(message.message);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
newLine();
|
||||
}
|
||||
stdWarn(tr("[Warn]") + fmtMsg(message));
|
||||
}
|
||||
flush();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Error:
|
||||
if (isMatchLast(type, message)) {
|
||||
stdErr(message.message);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
newLine();
|
||||
}
|
||||
stdErr(tr("[Error]") + fmtMsg(message));
|
||||
}
|
||||
flush();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Print:
|
||||
if (lastInfo.first != type) {
|
||||
newLine();
|
||||
}
|
||||
// If running ouput in the console,
|
||||
// otherwise logging.
|
||||
if (_sp->isRunning()) {
|
||||
stdOut(message.message);
|
||||
} else {
|
||||
Logger::logPrint(Logger::packDebugStr(
|
||||
packUpLoggingStr(message.message)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
lastInfo.first = type;
|
||||
lastInfo.second = qMakePair(message.row, message.col);
|
||||
});
|
||||
// _sp = new ScriptConsoleMachine(_getInputFn, this);
|
||||
// connect(_sp, &ScriptConsoleMachine::onClearConsole, this,
|
||||
// &ScriptingConsole::clear);
|
||||
// connect(this, &ScriptingConsole::abortEvaluation, _sp,
|
||||
// &ScriptConsoleMachine::abortScript);
|
||||
|
||||
connect(this, &QConsoleWidget::consoleCommand, this,
|
||||
&ScriptingConsole::runConsoleCommand);
|
||||
|
||||
auto cm = new AsConsoleCompletion(_sp->engine(), this);
|
||||
auto cm = new AsConsoleCompletion(this);
|
||||
connect(cm, &AsCompletion::onFunctionTip, this,
|
||||
&ScriptingConsole::onFunctionTip);
|
||||
}
|
||||
|
@ -201,6 +114,80 @@ void ScriptingConsole::clearConsole() {
|
|||
|
||||
void ScriptingConsole::processKeyEvent(QKeyEvent *e) { keyPressEvent(e); }
|
||||
|
||||
void ScriptingConsole::onOutput(const ScriptMachine::MessageInfo &message) {
|
||||
// <type, <row, col>>
|
||||
static QPair<ScriptMachine::MessageType, QPair<int, int>> lastInfo{
|
||||
ScriptMachine::MessageType::Print, {-1, -1}};
|
||||
|
||||
auto doc = this->document();
|
||||
auto lastLine = doc->lastBlock();
|
||||
auto isNotBlockStart = !lastLine.text().isEmpty();
|
||||
|
||||
auto fmtMsg = [](const ScriptMachine::MessageInfo &message) -> QString {
|
||||
if (message.row <= 0 || message.col <= 0) {
|
||||
return message.message;
|
||||
} else {
|
||||
return QStringLiteral("(") + QString::number(message.row) +
|
||||
QStringLiteral(", ") + QString::number(message.col) +
|
||||
QStringLiteral(")") + message.message;
|
||||
}
|
||||
};
|
||||
|
||||
auto isMatchLast = [](const ScriptMachine::MessageInfo &message) -> bool {
|
||||
if (message.row < 0 || message.col < 0) {
|
||||
return false;
|
||||
}
|
||||
return lastInfo.first == message.type &&
|
||||
lastInfo.second.first == message.row &&
|
||||
lastInfo.second.second == message.col;
|
||||
};
|
||||
|
||||
switch (message.type) {
|
||||
case ScriptMachine::MessageType::Info:
|
||||
if (isMatchLast(message)) {
|
||||
stdOut(message.message);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
newLine();
|
||||
}
|
||||
stdOut(tr("[Info]") + fmtMsg(message));
|
||||
}
|
||||
flush();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Warn:
|
||||
if (isMatchLast(message)) {
|
||||
stdWarn(message.message);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
newLine();
|
||||
}
|
||||
stdWarn(tr("[Warn]") + fmtMsg(message));
|
||||
}
|
||||
flush();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Error:
|
||||
if (isMatchLast(message)) {
|
||||
stdErr(message.message);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
newLine();
|
||||
}
|
||||
stdErr(tr("[Error]") + fmtMsg(message));
|
||||
}
|
||||
flush();
|
||||
break;
|
||||
case ScriptMachine::MessageType::Print:
|
||||
if (lastInfo.first != message.type) {
|
||||
newLine();
|
||||
}
|
||||
stdOut(message.message);
|
||||
break;
|
||||
}
|
||||
|
||||
lastInfo.first = message.type;
|
||||
lastInfo.second = qMakePair(message.row, message.col);
|
||||
}
|
||||
|
||||
void ScriptingConsole::applyScriptSettings() {
|
||||
auto &set = ScriptSettings::instance();
|
||||
auto dfont = QFont(set.consoleFontFamily());
|
||||
|
@ -241,7 +228,9 @@ void ScriptingConsole::runConsoleCommand(const QString &code) {
|
|||
} else {
|
||||
setMode(Output);
|
||||
_codes += exec;
|
||||
if (!_sp->executeCode(_codes)) {
|
||||
if (!ScriptMachine::instance().executeCode(ScriptMachine::Interactive,
|
||||
_codes)) {
|
||||
// WingMessageBox::
|
||||
}
|
||||
_codes.clear();
|
||||
appendCommandPrompt();
|
||||
|
@ -290,10 +279,6 @@ QString ScriptingConsole::currentCodes() const {
|
|||
return _codes + currentCommandLine();
|
||||
}
|
||||
|
||||
ScriptMachine *ScriptingConsole::machine() const { return _sp; }
|
||||
|
||||
ScriptConsoleMachine *ScriptingConsole::consoleMachine() const { return _sp; }
|
||||
|
||||
void ScriptingConsole::contextMenuEvent(QContextMenuEvent *event) {
|
||||
QMenu menu(this);
|
||||
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
#ifndef ScriptingConsole_H
|
||||
#define ScriptingConsole_H
|
||||
|
||||
#include "scriptingconsolebase.h"
|
||||
|
||||
#include "class/asconsolecompletion.h"
|
||||
#include "class/scriptconsolemachine.h"
|
||||
#include "class/scriptmachine.h"
|
||||
#include "scriptingconsolebase.h"
|
||||
|
||||
#include <QMutex>
|
||||
|
||||
|
@ -33,14 +32,14 @@ public:
|
|||
|
||||
virtual ~ScriptingConsole();
|
||||
|
||||
ScriptMachine *machine() const;
|
||||
ScriptConsoleMachine *consoleMachine() const;
|
||||
|
||||
QString currentCodes() const;
|
||||
|
||||
signals:
|
||||
void onFunctionTip(const QString &tip);
|
||||
|
||||
public:
|
||||
QString getInput();
|
||||
|
||||
public slots:
|
||||
void init();
|
||||
|
||||
|
@ -48,14 +47,14 @@ public slots:
|
|||
|
||||
void processKeyEvent(QKeyEvent *e);
|
||||
|
||||
void onOutput(const ScriptMachine::MessageInfo &message);
|
||||
|
||||
private slots:
|
||||
void applyScriptSettings();
|
||||
|
||||
private:
|
||||
void runConsoleCommand(const QString &code);
|
||||
|
||||
QString getInput();
|
||||
|
||||
QString packUpLoggingStr(const QString &message);
|
||||
|
||||
protected:
|
||||
|
@ -67,8 +66,6 @@ protected slots:
|
|||
virtual void onCompletion(const QModelIndex &index) override;
|
||||
|
||||
private:
|
||||
ScriptConsoleMachine *_sp = nullptr;
|
||||
|
||||
QString _codes;
|
||||
|
||||
std::function<QString(void)> _getInputFn;
|
||||
|
|
|
@ -13,6 +13,8 @@ enum AsUserDataType {
|
|||
UserData_ContextDbgInfo,
|
||||
UserData_API,
|
||||
UserData_PluginFn,
|
||||
UserData_isDbg,
|
||||
UserData_ContextMode,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "class/pluginsystem.h"
|
||||
#include "class/qkeysequences.h"
|
||||
#include "class/richtextitemdelegate.h"
|
||||
#include "class/scriptconsolemachine.h"
|
||||
#include "class/scriptmachine.h"
|
||||
#include "class/settingmanager.h"
|
||||
#include "class/wingfiledialog.h"
|
||||
#include "class/winginputdialog.h"
|
||||
|
@ -230,6 +230,32 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
|
|||
// Don't setup it too early, because the plugin can register script
|
||||
// functions. Code completions of them will be not worked out.
|
||||
if (set.scriptEnabled()) {
|
||||
auto &sm = ScriptMachine::instance();
|
||||
auto smr = sm.init();
|
||||
if (smr) {
|
||||
ScriptMachine::RegCallBacks callbacks;
|
||||
callbacks.getInputFn = [this]() -> QString {
|
||||
return m_scriptConsole->getInput();
|
||||
};
|
||||
callbacks.clearFn = [this]() { m_scriptConsole->clearConsole(); };
|
||||
callbacks.printMsgFn =
|
||||
[this](const ScriptMachine::MessageInfo &message) {
|
||||
m_scriptConsole->onOutput(message);
|
||||
};
|
||||
sm.registerCallBack(ScriptMachine::Interactive, callbacks);
|
||||
|
||||
callbacks.getInputFn = [this]() -> QString {
|
||||
return WingInputDialog::getText(this, tr(""), tr(""));
|
||||
};
|
||||
callbacks.clearFn = [this]() { m_bgScriptOutput->clear(); };
|
||||
callbacks.printMsgFn =
|
||||
std::bind(&MainWindow::onOutputBgScriptOutput, this,
|
||||
std::placeholders::_1);
|
||||
sm.registerCallBack(ScriptMachine::Background, callbacks);
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
|
||||
// At this time, AngelScript service plugin has started
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupConsole"));
|
||||
|
@ -237,25 +263,17 @@ MainWindow::MainWindow(SplashDialog *splash) : FramelessMainWindow() {
|
|||
m_scriptConsole->init();
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupScriptManager"));
|
||||
ScriptManager::instance().attach(m_scriptConsole);
|
||||
|
||||
plg.angelApi()->setBindingConsole(m_scriptConsole);
|
||||
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupScriptService"));
|
||||
|
||||
m_scriptConsole->initOutput();
|
||||
m_scriptConsole->setMode(QConsoleWidget::Input);
|
||||
m_scriptConsole->machine()->setInsteadFoundDisabled(true);
|
||||
|
||||
if (splash)
|
||||
splash->setInfoText(tr("SetupScriptEditor"));
|
||||
m_scriptDialog = new ScriptingDialog(this);
|
||||
m_scriptDialog->initConsole();
|
||||
|
||||
// load the model
|
||||
Q_ASSERT(m_scriptConsole && m_scriptConsole->machine());
|
||||
m_varshowtable->setModel(m_scriptConsole->consoleMachine()->model());
|
||||
}
|
||||
|
||||
// connect settings signals
|
||||
|
@ -535,8 +553,8 @@ void MainWindow::buildUpDockSystem(QWidget *container) {
|
|||
bottomRightArea = buildUpScriptConsoleDock(
|
||||
m_dock, ads::RightDockWidgetArea, bottomLeftArea);
|
||||
qApp->processEvents();
|
||||
buildUpScriptObjShowDock(m_dock, ads::CenterDockWidgetArea,
|
||||
bottomRightArea);
|
||||
buildUpScriptBgOutputDock(m_dock, ads::CenterDockWidgetArea,
|
||||
bottomRightArea);
|
||||
qApp->processEvents();
|
||||
buildUpHashResultDock(m_dock, ads::CenterDockWidgetArea,
|
||||
bottomRightArea);
|
||||
|
@ -1000,17 +1018,14 @@ MainWindow::buildUpScriptConsoleDock(ads::CDockManager *dock,
|
|||
}
|
||||
|
||||
ads::CDockAreaWidget *
|
||||
MainWindow::buildUpScriptObjShowDock(ads::CDockManager *dock,
|
||||
ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw) {
|
||||
m_varshowtable = new QTableViewExt(this);
|
||||
m_varshowtable->setEditTriggers(QTableView::EditTrigger::DoubleClicked);
|
||||
m_varshowtable->setSelectionBehavior(
|
||||
QAbstractItemView::SelectionBehavior::SelectRows);
|
||||
m_varshowtable->horizontalHeader()->setStretchLastSection(true);
|
||||
MainWindow::buildUpScriptBgOutputDock(ads::CDockManager *dock,
|
||||
ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw) {
|
||||
m_bgScriptOutput = new QPlainTextEdit(this);
|
||||
m_bgScriptOutput->setReadOnly(true);
|
||||
|
||||
auto dw = buildDockWidget(dock, QStringLiteral("ScriptObjShow"),
|
||||
tr("ScriptObjShow"), m_varshowtable);
|
||||
auto dw = buildDockWidget(dock, QStringLiteral("BgScriptOutput"),
|
||||
tr("BgScriptOutput"), m_bgScriptOutput);
|
||||
return dock->addDockWidget(area, dw, areaw);
|
||||
}
|
||||
|
||||
|
@ -1720,7 +1735,7 @@ RibbonTabContent *MainWindow::buildPluginPage(RibbonTabContent *tab) {
|
|||
auto pannel = tab->addGroup(tr("General"));
|
||||
addPannelAction(
|
||||
pannel, QStringLiteral("settingplugin"), tr("Plugin"),
|
||||
&MainWindow::on_setting_plugin,
|
||||
&MainWindow::on_settingPlugin,
|
||||
shortcuts.keySequence(QKeySequences::Key::SETTING_PLUGIN));
|
||||
}
|
||||
|
||||
|
@ -1743,13 +1758,12 @@ RibbonTabContent *MainWindow::buildSettingPage(RibbonTabContent *tab) {
|
|||
auto pannel = tab->addGroup(tr("General"));
|
||||
addPannelAction(
|
||||
pannel, QStringLiteral("general"), tr("General"),
|
||||
&MainWindow::on_setting_general,
|
||||
&MainWindow::on_settingGeneral,
|
||||
shortcuts.keySequence(QKeySequences::Key::SETTING_GENERAL));
|
||||
|
||||
if (set.scriptEnabled()) {
|
||||
addPannelAction(pannel, QStringLiteral("scriptset"),
|
||||
tr("ScriptSetting"),
|
||||
&MainWindow::on_setting_script);
|
||||
tr("ScriptSetting"), &MainWindow::on_settingScript);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3097,13 +3111,13 @@ void MainWindow::on_scriptwindow() {
|
|||
m_scriptDialog->raise();
|
||||
}
|
||||
|
||||
void MainWindow::on_setting_general() { m_setdialog->showConfig(0); }
|
||||
void MainWindow::on_settingGeneral() { m_setdialog->showConfig(0); }
|
||||
|
||||
void MainWindow::on_setting_script() {
|
||||
void MainWindow::on_settingScript() {
|
||||
m_scriptDialog->settingDialog()->showConfig();
|
||||
}
|
||||
|
||||
void MainWindow::on_setting_plugin() { m_setdialog->showConfig(2); }
|
||||
void MainWindow::on_settingPlugin() { m_setdialog->showConfig(2); }
|
||||
|
||||
void MainWindow::on_about() { AboutSoftwareDialog().exec(); }
|
||||
|
||||
|
@ -3939,6 +3953,88 @@ ads::CDockAreaWidget *MainWindow::editorViewArea() const {
|
|||
return m_dock->centralWidget()->dockAreaWidget();
|
||||
}
|
||||
|
||||
void MainWindow::onOutputBgScriptOutput(
|
||||
const ScriptMachine::MessageInfo &message) {
|
||||
static QPair<ScriptMachine::MessageType, QPair<int, int>> lastInfo{
|
||||
ScriptMachine::MessageType::Print, {-1, -1}};
|
||||
|
||||
auto doc = m_bgScriptOutput->document();
|
||||
auto lastLine = doc->lastBlock();
|
||||
auto isNotBlockStart = !lastLine.text().isEmpty();
|
||||
|
||||
auto cursor = m_bgScriptOutput->textCursor();
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
|
||||
auto fmtMsg = [](const ScriptMachine::MessageInfo &message) -> QString {
|
||||
if (message.row <= 0 || message.col <= 0) {
|
||||
return message.message;
|
||||
} else {
|
||||
return QStringLiteral("(") + QString::number(message.row) +
|
||||
QStringLiteral(", ") + QString::number(message.col) +
|
||||
QStringLiteral(")") + message.message;
|
||||
}
|
||||
};
|
||||
|
||||
auto isMatchLast = [](const ScriptMachine::MessageInfo &message) -> bool {
|
||||
if (message.row < 0 || message.col < 0) {
|
||||
return false;
|
||||
}
|
||||
return lastInfo.first == message.type &&
|
||||
lastInfo.second.first == message.row &&
|
||||
lastInfo.second.second == message.col;
|
||||
};
|
||||
|
||||
switch (message.type) {
|
||||
case ScriptMachine::MessageType::Info:
|
||||
if (isMatchLast(message)) {
|
||||
cursor.insertText(message.message);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
cursor.insertBlock();
|
||||
}
|
||||
cursor.insertText(tr("[Info]") + fmtMsg(message));
|
||||
}
|
||||
break;
|
||||
case ScriptMachine::MessageType::Warn:
|
||||
if (isMatchLast(message)) {
|
||||
auto fmt = cursor.charFormat();
|
||||
fmt.setForeground(QColorConstants::Svg::gold);
|
||||
cursor.insertText(message.message, fmt);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
m_bgScriptOutput->appendPlainText({});
|
||||
}
|
||||
auto fmt = cursor.charFormat();
|
||||
fmt.setForeground(QColorConstants::Svg::gold);
|
||||
cursor.insertText(tr("[Warn]") + fmtMsg(message), fmt);
|
||||
}
|
||||
break;
|
||||
case ScriptMachine::MessageType::Error:
|
||||
if (isMatchLast(message)) {
|
||||
auto fmt = cursor.charFormat();
|
||||
fmt.setForeground(Qt::red);
|
||||
cursor.insertText(message.message, fmt);
|
||||
} else {
|
||||
if (isNotBlockStart) {
|
||||
cursor.insertBlock();
|
||||
}
|
||||
auto fmt = cursor.charFormat();
|
||||
fmt.setForeground(Qt::red);
|
||||
cursor.insertText(tr("[Error]") + fmtMsg(message), fmt);
|
||||
}
|
||||
break;
|
||||
case ScriptMachine::MessageType::Print:
|
||||
if (lastInfo.first != message.type) {
|
||||
cursor.insertBlock();
|
||||
}
|
||||
cursor.insertText(message.message);
|
||||
break;
|
||||
}
|
||||
|
||||
lastInfo.first = message.type;
|
||||
lastInfo.second = qMakePair(message.row, message.col);
|
||||
}
|
||||
|
||||
QJsonObject MainWindow::extractModelData(const QAbstractItemModel *model,
|
||||
const QModelIndex &parent) {
|
||||
QJsonObject jsonObject;
|
||||
|
@ -3981,11 +4077,8 @@ void MainWindow::closeEvent(QCloseEvent *event) {
|
|||
return;
|
||||
}
|
||||
|
||||
// then checking the scripting console
|
||||
auto sm = m_scriptConsole->consoleMachine();
|
||||
if (sm->isRunning()) {
|
||||
sm->abortScript();
|
||||
}
|
||||
// then abort all script running
|
||||
ScriptMachine::instance().abortScript();
|
||||
|
||||
// then checking itself
|
||||
if (!m_views.isEmpty()) {
|
||||
|
|
|
@ -123,8 +123,8 @@ private:
|
|||
buildUpScriptConsoleDock(ads::CDockManager *dock, ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw = nullptr);
|
||||
ads::CDockAreaWidget *
|
||||
buildUpScriptObjShowDock(ads::CDockManager *dock, ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw = nullptr);
|
||||
buildUpScriptBgOutputDock(ads::CDockManager *dock, ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw = nullptr);
|
||||
ads::CDockAreaWidget *
|
||||
buildUpVisualDataDock(ads::CDockManager *dock, ads::DockWidgetArea area,
|
||||
ads::CDockAreaWidget *areaw = nullptr);
|
||||
|
@ -205,9 +205,9 @@ private slots:
|
|||
void on_inspectQt();
|
||||
|
||||
void on_scriptwindow();
|
||||
void on_setting_general();
|
||||
void on_setting_script();
|
||||
void on_setting_plugin();
|
||||
void on_settingGeneral();
|
||||
void on_settingScript();
|
||||
void on_settingPlugin();
|
||||
|
||||
void on_about();
|
||||
void on_sponsor();
|
||||
|
@ -266,6 +266,8 @@ private:
|
|||
|
||||
inline ads::CDockAreaWidget *editorViewArea() const;
|
||||
|
||||
void onOutputBgScriptOutput(const ScriptMachine::MessageInfo &message);
|
||||
|
||||
private:
|
||||
QJsonObject extractModelData(const QAbstractItemModel *model,
|
||||
const QModelIndex &parent = QModelIndex());
|
||||
|
@ -481,7 +483,7 @@ private:
|
|||
|
||||
ScriptingDialog *m_scriptDialog = nullptr;
|
||||
ScriptingConsole *m_scriptConsole = nullptr;
|
||||
QTableViewExt *m_varshowtable = nullptr;
|
||||
QPlainTextEdit *m_bgScriptOutput = nullptr;
|
||||
|
||||
bool m_isfinding = false;
|
||||
ads::CDockWidget *m_find = nullptr;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "class/languagemanager.h"
|
||||
#include "class/pluginsystem.h"
|
||||
#include "class/qkeysequences.h"
|
||||
#include "class/scriptmachine.h"
|
||||
#include "class/settingmanager.h"
|
||||
#include "class/wingfiledialog.h"
|
||||
#include "class/wingmessagebox.h"
|
||||
|
@ -93,6 +94,17 @@ ScriptingDialog::ScriptingDialog(QWidget *parent)
|
|||
m_dock->restoreState(set.scriptDockLayout());
|
||||
_savedLayout = set.scriptDockLayout();
|
||||
|
||||
ScriptMachine::RegCallBacks callbacks;
|
||||
callbacks.getInputFn = [this]() -> QString {
|
||||
return m_consoleout->getInput();
|
||||
};
|
||||
callbacks.clearFn = [this]() { m_consoleout->clearConsole(); };
|
||||
callbacks.printMsgFn = [this](const ScriptMachine::MessageInfo &message) {
|
||||
m_consoleout->onOutput(message);
|
||||
};
|
||||
ScriptMachine::instance().registerCallBack(ScriptMachine::Scripting,
|
||||
callbacks);
|
||||
|
||||
this->setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
|
@ -102,8 +114,8 @@ void ScriptingDialog::initConsole() {
|
|||
Q_ASSERT(m_consoleout);
|
||||
|
||||
m_consoleout->init();
|
||||
auto machine = m_consoleout->machine();
|
||||
connect(machine, &ScriptMachine::onDebugFinished, this, [=] {
|
||||
auto &machine = ScriptMachine::instance();
|
||||
connect(&machine, &ScriptMachine::onDebugFinished, this, [=] {
|
||||
this->updateRunDebugMode();
|
||||
m_callstack->updateData({});
|
||||
m_varshow->updateData({});
|
||||
|
@ -138,7 +150,7 @@ void ScriptingDialog::initConsole() {
|
|||
_DebugingEditor = nullptr;
|
||||
}
|
||||
});
|
||||
auto dbg = machine->debugger();
|
||||
auto dbg = machine.debugger();
|
||||
Q_ASSERT(dbg);
|
||||
connect(dbg, &asDebugger::onAdjustBreakPointLine, this,
|
||||
[=](const asDebugger::BreakPoint &old, int newLineNr) {
|
||||
|
@ -210,7 +222,7 @@ void ScriptingDialog::initConsole() {
|
|||
});
|
||||
connect(dbg, &asDebugger::onDebugActionExec, this,
|
||||
[this]() { updateRunDebugMode(); });
|
||||
m_sym->setEngine(machine->engine());
|
||||
m_sym->setEngine(machine.engine());
|
||||
}
|
||||
|
||||
bool ScriptingDialog::about2Close() {
|
||||
|
@ -489,16 +501,15 @@ RibbonTabContent *ScriptingDialog::buildDebugPage(RibbonTabContent *tab) {
|
|||
|
||||
auto dbgShortCut = new QShortcut(dbgkey, this);
|
||||
connect(dbgShortCut, &QShortcut::activated, this, [this]() {
|
||||
auto runner = m_consoleout->machine();
|
||||
auto &runner = ScriptMachine::instance();
|
||||
bool isRun = false;
|
||||
bool isDbg = false;
|
||||
bool isPaused = false;
|
||||
if (runner) {
|
||||
isRun = runner->isRunning();
|
||||
isDbg = runner->isDebugMode();
|
||||
auto dbg = runner->debugger();
|
||||
isPaused = dbg->currentState() == asDebugger::PAUSE;
|
||||
}
|
||||
|
||||
isRun = runner.isRunning();
|
||||
isDbg = runner.isDebugMode();
|
||||
auto dbg = runner.debugger();
|
||||
isPaused = dbg->currentState() == asDebugger::PAUSE;
|
||||
|
||||
if (isRun && isDbg && isPaused) {
|
||||
m_Tbtneditors[ToolButtonIndex::DBG_CONTINUE_ACTION]->animateClick();
|
||||
|
@ -728,8 +739,8 @@ void ScriptingDialog::registerEditorView(ScriptEditor *editor) {
|
|||
Q_ASSERT(editor);
|
||||
Q_ASSERT(m_views.contains(editor));
|
||||
|
||||
auto m = m_consoleout->machine();
|
||||
if (m->isRunning() && _DebugingEditor == editor) {
|
||||
auto &m = ScriptMachine::instance();
|
||||
if (m.isRunning() && _DebugingEditor == editor) {
|
||||
if (WingMessageBox::warning(
|
||||
this, this->windowTitle(), tr("ScriptStillRunning"),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
|
||||
|
@ -864,17 +875,17 @@ void ScriptingDialog::swapEditor(ScriptEditor *old, ScriptEditor *cur) {
|
|||
}
|
||||
|
||||
void ScriptingDialog::updateRunDebugMode(bool disable) {
|
||||
auto runner = m_consoleout->machine();
|
||||
auto &runner = ScriptMachine::instance();
|
||||
auto enable = !disable;
|
||||
bool isRun = false;
|
||||
bool isDbg = false;
|
||||
bool isPaused = false;
|
||||
if (runner) {
|
||||
isRun = runner->isRunning();
|
||||
isDbg = runner->isDebugMode();
|
||||
auto dbg = runner->debugger();
|
||||
isPaused = dbg->currentState() == asDebugger::PAUSE;
|
||||
}
|
||||
|
||||
isRun = runner.isRunning();
|
||||
isDbg = runner.isDebugMode();
|
||||
auto dbg = runner.debugger();
|
||||
isPaused = dbg->currentState() == asDebugger::PAUSE;
|
||||
|
||||
m_Tbtneditors.value(ToolButtonIndex::DBG_RUN_ACTION)->setEnabled(!isRun);
|
||||
m_Tbtneditors.value(ToolButtonIndex::DBG_RUN_DBG_ACTION)
|
||||
->setEnabled(!isRun);
|
||||
|
@ -920,8 +931,8 @@ ScriptEditor *ScriptingDialog::findEditorView(const QString &filename) {
|
|||
}
|
||||
|
||||
bool ScriptingDialog::isCurrentDebugging() const {
|
||||
auto m = m_consoleout->machine();
|
||||
return m && m->isDebugMode();
|
||||
auto &m = ScriptMachine::instance();
|
||||
return m.isDebugMode();
|
||||
}
|
||||
|
||||
ScriptEditor *ScriptingDialog::openFile(const QString &filename) {
|
||||
|
@ -932,8 +943,7 @@ ScriptEditor *ScriptingDialog::openFile(const QString &filename) {
|
|||
return e;
|
||||
}
|
||||
|
||||
auto editor =
|
||||
new ScriptEditor(m_consoleout->consoleMachine()->engine(), this);
|
||||
auto editor = new ScriptEditor(this);
|
||||
|
||||
auto res = editor->openFile(filename);
|
||||
if (!res) {
|
||||
|
@ -949,9 +959,9 @@ ScriptEditor *ScriptingDialog::openFile(const QString &filename) {
|
|||
|
||||
void ScriptingDialog::runDbgCommand(asDebugger::DebugAction action) {
|
||||
updateRunDebugMode(true);
|
||||
auto machine = m_consoleout->machine();
|
||||
if (machine->isDebugMode()) {
|
||||
auto dbg = machine->debugger();
|
||||
auto &machine = ScriptMachine::instance();
|
||||
if (machine.isDebugMode()) {
|
||||
auto dbg = machine.debugger();
|
||||
dbg->runDebugAction(action);
|
||||
}
|
||||
}
|
||||
|
@ -978,7 +988,7 @@ void ScriptingDialog::startDebugScript(ScriptEditor *editor) {
|
|||
m_consoleout->clear();
|
||||
|
||||
// add breakpoints
|
||||
auto dbg = m_consoleout->machine()->debugger();
|
||||
auto dbg = ScriptMachine::instance().debugger();
|
||||
auto fileName = editor->fileName();
|
||||
auto e = editor->editor();
|
||||
auto totalblk = e->blockCount();
|
||||
|
@ -992,7 +1002,8 @@ void ScriptingDialog::startDebugScript(ScriptEditor *editor) {
|
|||
PluginSystem::instance().scriptPragmaBegin();
|
||||
|
||||
editor->setReadOnly(true);
|
||||
m_consoleout->machine()->executeScript(fileName, true);
|
||||
ScriptMachine::instance().executeScript(ScriptMachine::Scripting, fileName,
|
||||
true);
|
||||
editor->setReadOnly(false);
|
||||
|
||||
updateRunDebugMode();
|
||||
|
@ -1006,8 +1017,9 @@ void ScriptingDialog::addBreakPoint(ScriptEditor *editor, int line) {
|
|||
const auto curSym = QStringLiteral("cur");
|
||||
const auto hitCur = QStringLiteral("curbp");
|
||||
|
||||
if (m_consoleout->machine()->isDebugMode()) {
|
||||
auto dbg = m_consoleout->machine()->debugger();
|
||||
auto &m = ScriptMachine::instance();
|
||||
if (m.isDebugMode()) {
|
||||
auto dbg = m.debugger();
|
||||
auto symID = e->symbolMark(line);
|
||||
if (curSym == symID) {
|
||||
e->addSymbolMark(line, hitCur);
|
||||
|
@ -1027,8 +1039,9 @@ void ScriptingDialog::removeBreakPoint(ScriptEditor *editor, int line) {
|
|||
Q_ASSERT(editor);
|
||||
auto e = editor->editor();
|
||||
|
||||
if (m_consoleout->machine()->isDebugMode()) {
|
||||
auto dbg = m_consoleout->machine()->debugger();
|
||||
auto &m = ScriptMachine::instance();
|
||||
if (m.isDebugMode()) {
|
||||
auto dbg = m.debugger();
|
||||
auto symID = e->symbolMark(line);
|
||||
|
||||
const auto bpMark = QStringLiteral("bp");
|
||||
|
@ -1053,8 +1066,9 @@ void ScriptingDialog::toggleBreakPoint(ScriptEditor *editor, int line) {
|
|||
Q_ASSERT(editor);
|
||||
auto e = editor->editor();
|
||||
|
||||
if (m_consoleout->machine()->isDebugMode()) {
|
||||
auto dbg = m_consoleout->machine()->debugger();
|
||||
auto &m = ScriptMachine::instance();
|
||||
if (m.isDebugMode()) {
|
||||
auto dbg = m.debugger();
|
||||
auto symID = e->symbolMark(line);
|
||||
|
||||
const auto bpMark = QStringLiteral("bp");
|
||||
|
@ -1134,8 +1148,7 @@ void ScriptingDialog::on_newfile() {
|
|||
return;
|
||||
}
|
||||
|
||||
auto editor =
|
||||
new ScriptEditor(m_consoleout->consoleMachine()->engine(), this);
|
||||
auto editor = new ScriptEditor(this);
|
||||
auto res = editor->openFile(filename);
|
||||
if (!res) {
|
||||
WingMessageBox::critical(this, tr("Error"), tr("FilePermission"));
|
||||
|
@ -1355,7 +1368,7 @@ void ScriptingDialog::on_runscript() {
|
|||
PluginSystem::instance().scriptPragmaBegin();
|
||||
|
||||
editor->setReadOnly(true);
|
||||
m_consoleout->machine()->executeScript(editor->fileName());
|
||||
// ScriptMachine::instance().executeScript(editor->fileName());
|
||||
editor->setReadOnly(false);
|
||||
updateRunDebugMode();
|
||||
}
|
||||
|
@ -1423,8 +1436,8 @@ void ScriptingDialog::on_removebreakpoint() {
|
|||
}
|
||||
|
||||
void ScriptingDialog::closeEvent(QCloseEvent *event) {
|
||||
auto runner = m_consoleout->machine();
|
||||
if (runner->isRunning()) {
|
||||
auto &runner = ScriptMachine::instance();
|
||||
if (runner.isRunning()) {
|
||||
if (WingMessageBox::warning(
|
||||
this, this->windowTitle(), tr("ScriptStillRunning"),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
|
||||
|
|
|
@ -1,119 +0,0 @@
|
|||
/*==============================================================================
|
||||
** 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 "scriptobjmodel.h"
|
||||
|
||||
ScriptObjModel::ScriptObjModel(asIScriptEngine *engine, asDebugger *debugger,
|
||||
QObject *parent)
|
||||
: QAbstractTableModel(parent), _engine(engine), _debugger(debugger) {
|
||||
Q_ASSERT(engine && debugger);
|
||||
_mod = engine->GetModule("Console", asGM_CREATE_IF_NOT_EXISTS);
|
||||
Q_ASSERT(_mod);
|
||||
}
|
||||
|
||||
void ScriptObjModel::updateData() {
|
||||
this->beginResetModel();
|
||||
_datas.reserve(_engine->GetGlobalPropertyCount() +
|
||||
_mod->GetGlobalVarCount());
|
||||
_datas.clear();
|
||||
|
||||
for (asUINT n = 0; n < _engine->GetGlobalPropertyCount(); n++) {
|
||||
const char *name;
|
||||
int typeId;
|
||||
bool isConst;
|
||||
void *v;
|
||||
|
||||
_engine->GetGlobalPropertyByIndex(n, &name, nullptr, &typeId, &isConst,
|
||||
nullptr, &v);
|
||||
|
||||
Data d;
|
||||
d.name = name;
|
||||
d.type = (isConst ? QStringLiteral(" const ") : QStringLiteral(" ")) +
|
||||
_engine->GetTypeDeclaration(typeId);
|
||||
d.value = _debugger->toString(v, typeId, _engine);
|
||||
|
||||
_datas.append(d);
|
||||
}
|
||||
|
||||
for (asUINT n = 0; n < _mod->GetGlobalVarCount(); n++) {
|
||||
const char *name;
|
||||
int typeId;
|
||||
bool isConst;
|
||||
void *v;
|
||||
|
||||
_mod->GetGlobalVar(n, &name, nullptr, &typeId, &isConst);
|
||||
v = _mod->GetAddressOfGlobalVar(n);
|
||||
|
||||
Data d;
|
||||
d.name = name;
|
||||
d.type = (isConst ? QStringLiteral(" const ") : QStringLiteral(" ")) +
|
||||
_engine->GetTypeDeclaration(typeId);
|
||||
d.value = _debugger->toString(v, typeId, _engine);
|
||||
_datas.append(d);
|
||||
}
|
||||
this->endResetModel();
|
||||
}
|
||||
|
||||
int ScriptObjModel::rowCount(const QModelIndex &parent) const {
|
||||
Q_UNUSED(parent);
|
||||
return _datas.size();
|
||||
}
|
||||
|
||||
int ScriptObjModel::columnCount(const QModelIndex &parent) const {
|
||||
Q_UNUSED(parent);
|
||||
return 3;
|
||||
}
|
||||
|
||||
QVariant ScriptObjModel::data(const QModelIndex &index, int role) const {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
auto d = _datas.at(index.row());
|
||||
switch (index.column()) {
|
||||
case 0:
|
||||
return d.name;
|
||||
case 1:
|
||||
return d.type;
|
||||
case 2:
|
||||
return d.value;
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
case Qt::TextAlignmentRole:
|
||||
return int(Qt::AlignCenter);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ScriptObjModel::headerData(int section, Qt::Orientation orientation,
|
||||
int role) const {
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (orientation == Qt::Horizontal) {
|
||||
switch (section) {
|
||||
case 0:
|
||||
return tr("Name");
|
||||
case 1:
|
||||
return tr("Type");
|
||||
case 2:
|
||||
return tr("Value");
|
||||
}
|
||||
} else {
|
||||
return section + 1;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*==============================================================================
|
||||
** 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 SCRIPTOBJMODEL_H
|
||||
#define SCRIPTOBJMODEL_H
|
||||
|
||||
#include "angelscript.h"
|
||||
#include "class/asdebugger.h"
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
class ScriptObjModel : public QAbstractTableModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ScriptObjModel(asIScriptEngine *engine, asDebugger *debugger,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
void updateData();
|
||||
|
||||
private:
|
||||
struct Data {
|
||||
QString name;
|
||||
QString type;
|
||||
QString value;
|
||||
};
|
||||
|
||||
QList<Data> _datas;
|
||||
|
||||
// QAbstractItemModel interface
|
||||
public:
|
||||
virtual int rowCount(const QModelIndex &parent) const override;
|
||||
virtual int columnCount(const QModelIndex &parent) const override;
|
||||
virtual QVariant data(const QModelIndex &index, int role) const override;
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role) const override;
|
||||
|
||||
private:
|
||||
asIScriptEngine *_engine = nullptr;
|
||||
asDebugger *_debugger = nullptr;
|
||||
asIScriptModule *_mod = nullptr;
|
||||
};
|
||||
|
||||
#endif // SCRIPTOBJMODEL_H
|
Loading…
Reference in New Issue