feat: 脚本引擎单例化;更合理的格式化参数;

This commit is contained in:
寂静的羽夏 2025-04-09 13:59:12 +08:00
parent 7597663d76
commit d6680e3f11
35 changed files with 2333 additions and 2598 deletions

View File

@ -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)

2
3rdparty/cpptrace vendored

@ -1 +1 @@
Subproject commit fac4d08fd0473a94d99c143c6ba6b1f9e0bd7636
Subproject commit ce639ebfcec47a7c74233b4bab50017cb34e615b

View File

@ -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

View File

@ -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());

View File

@ -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

View File

@ -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);

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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:

View File

@ -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;
}

View File

@ -24,7 +24,7 @@ class asContextMgr : public CContextMgr {
public:
asContextMgr();
bool isRunning() const;
bool findThreadWithUserData(asPWORD index, void *data) const;
};
#endif // ASCONTEXTMGR_H

View File

@ -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);

View File

@ -116,6 +116,7 @@ public:
void runDebugAction(DebugAction action);
DebugAction currentState() const;
void resetState();
static void deleteDbgContextInfo(void *info);

View File

@ -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);

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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, &section);
msg.type = asMSGTYPE_ERROR;
msg.message = message;
emit onOutput(MessageType::Error, msg);
const char *section;
MessageInfo msg;
msg.row = context->GetExceptionLineNumber(&msg.col, &section);
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;
}

View File

@ -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)

View File

@ -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 {

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -13,6 +13,8 @@ enum AsUserDataType {
UserData_ContextDbgInfo,
UserData_API,
UserData_PluginFn,
UserData_isDbg,
UserData_ContextMode,
};
}

View File

@ -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()) {

View File

@ -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;

View File

@ -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) {

View File

@ -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();
}

View File

@ -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