fix: 修复完善和优化控制台;

This commit is contained in:
寂静的羽夏 2025-02-02 23:11:05 +08:00
parent 6b020b7f70
commit 04551684d2
21 changed files with 1517 additions and 1394 deletions

View File

@ -1841,7 +1841,7 @@ void QEditor::paintEvent(QPaintEvent *e) {
if (!m_doc) if (!m_doc)
return; return;
auto p = new QPainter(viewport()); QPainter p(viewport());
const int yOffset = verticalOffset(); const int yOffset = verticalOffset();
const int xOffset = horizontalOffset(); const int xOffset = horizontalOffset();
@ -1855,7 +1855,7 @@ void QEditor::paintEvent(QPaintEvent *e) {
// qDebug() << r; // qDebug() << r;
// p.setClipping(false); // p.setClipping(false);
p->translate(-xOffset, -yOffset); p.translate(-xOffset, -yOffset);
QDocument::PaintContext ctx; QDocument::PaintContext ctx;
ctx.xoffset = xOffset; ctx.xoffset = xOffset;
@ -1890,30 +1890,29 @@ void QEditor::paintEvent(QPaintEvent *e) {
ctx.extra << m_dragAndDrop.handle(); ctx.extra << m_dragAndDrop.handle();
} }
p->save(); p.save();
m_doc->draw(p, ctx); m_doc->draw(&p, ctx);
p->restore(); p.restore();
if (m_curPlaceHolder >= 0 && m_curPlaceHolder < m_placeHolders.count()) { if (m_curPlaceHolder >= 0 && m_curPlaceHolder < m_placeHolders.count()) {
const PlaceHolder &ph = m_placeHolders.at(m_curPlaceHolder); const PlaceHolder &ph = m_placeHolders.at(m_curPlaceHolder);
p->setPen(Qt::red); p.setPen(Qt::red);
p->drawConvexPolygon(ph.cursor.documentRegion()); p.drawConvexPolygon(ph.cursor.documentRegion());
p->setPen(Qt::yellow); p.setPen(Qt::yellow);
for (const QDocumentCursor &m : ph.mirrors) { for (const QDocumentCursor &m : ph.mirrors) {
if (m.isValid()) if (m.isValid())
p->drawConvexPolygon(m.documentRegion()); p.drawConvexPolygon(m.documentRegion());
} }
} }
if (viewport()->height() > m_doc->height()) { if (viewport()->height() > m_doc->height()) {
p->fillRect(0, m_doc->height(), viewport()->width(), p.fillRect(0, m_doc->height(), viewport()->width(),
viewport()->height() - m_doc->height(), palette().base()); viewport()->height() - m_doc->height(), palette().base());
} }
p->end(); p.end();
delete p;
} }
/*! /*!
@ -2252,7 +2251,7 @@ void QEditor::keyPressEvent(QKeyEvent *e) {
// remanence of matches // remanence of matches
if (m_definition) { if (m_definition) {
m_definition->clearMatches(m_doc); m_definition->clearMatches(m_doc);
viewport()->repaint(); // force repaint in case of crash viewport()->update();
} }
bool hasPH = m_placeHolders.count() && m_curPlaceHolder != -1; bool hasPH = m_placeHolders.count() && m_curPlaceHolder != -1;
@ -2610,7 +2609,7 @@ void QEditor::mouseDoubleClickEvent(QMouseEvent *e) {
repaintCursor(); repaintCursor();
viewport()->repaint(); viewport()->update();
} else { } else {
// qDebug("invalid cursor"); // qDebug("invalid cursor");
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -24,7 +24,17 @@
asBuilder::asBuilder(asIScriptEngine *engine) : AsPreprocesser(engine) {} asBuilder::asBuilder(asIScriptEngine *engine) : AsPreprocesser(engine) {}
asBuilder::~asBuilder() {
if (module) {
module->Discard();
}
}
int asBuilder::StartNewModule(const char *moduleName) { int asBuilder::StartNewModule(const char *moduleName) {
if (module) {
module->Discard();
}
module = engine->GetModule(moduleName, asGM_ALWAYS_CREATE); module = engine->GetModule(moduleName, asGM_ALWAYS_CREATE);
if (module == nullptr) if (module == nullptr)
return -1; return -1;

View File

@ -27,6 +27,7 @@
class asBuilder : public AsPreprocesser { class asBuilder : public AsPreprocesser {
public: public:
explicit asBuilder(asIScriptEngine *engine); explicit asBuilder(asIScriptEngine *engine);
virtual ~asBuilder();
// Start a new module // Start a new module
virtual int StartNewModule(const char *moduleName); virtual int StartNewModule(const char *moduleName);

View File

@ -117,8 +117,11 @@ void asDebugger::lineCallback(asIScriptContext *ctx) {
} }
}; };
qApp->processEvents();
switch (m_action) { switch (m_action) {
case ABORT: case ABORT:
ctx->Abort();
return; return;
case PAUSE: case PAUSE:
break; break;

View File

@ -21,22 +21,52 @@
#include "AngelScript/sdk/angelscript/source/as_tokenizer.h" #include "AngelScript/sdk/angelscript/source/as_tokenizer.h"
QAsCodeParser::QAsCodeParser(asCScriptEngine *engine) : engine(engine) { QAsCodeParser::QAsCodeParser(asCScriptEngine *engine) : engine(engine) {
Q_ASSERT(engine);
checkValidTypes = false;
isParsingAppInterface = false;
}
QAsCodeParser::QAsCodeParser(asIScriptEngine *engine) {
this->engine = dynamic_cast<asCScriptEngine *>(engine);
Q_ASSERT(engine);
checkValidTypes = false; checkValidTypes = false;
isParsingAppInterface = false; isParsingAppInterface = false;
} }
QAsCodeParser::~QAsCodeParser() {} QAsCodeParser::~QAsCodeParser() {}
QAsCodeParser::SymbolTable QAsCodeParser::preParse(const QByteArray &codes) { QAsCodeParser::SymbolTable QAsCodeParser::parse(const QByteArray &codes) {
Reset(); Reset();
code = codes; code = codes;
ParseScript(false); ParseScript(false);
return _symtable;
SymbolTable ret = _symtable;
if (!m_segs.isEmpty()) {
// only add function signature as symbol
// you can extend it with more features
// PRS are welcomed.
for (auto p = m_segs.constKeyValueBegin();
p != m_segs.constKeyValueEnd(); ++p) {
auto v = p->second;
Symbol fn;
fn.type = SymbolType::Function;
fn.name = v.name;
fn.nameInSrc = v.nameInSrc;
fn.content = v.args;
fn.ns = v.ns;
fn.typeStr = v.ret;
ret.insert(p->first, fn);
}
}
return ret;
} }
QAsCodeParser::SymbolTable QAsCodeParser::parse(qsizetype offset, QAsCodeParser::SymbolTable QAsCodeParser::parseIntell(qsizetype offset,
const QByteArray &codes) { const QByteArray &codes) {
preParse(codes); parse(codes);
// then we will parse the symbols we want // then we will parse the symbols we want
SymbolTable ret; SymbolTable ret;

View File

@ -43,6 +43,7 @@
class QAsCodeParser { class QAsCodeParser {
public: public:
QAsCodeParser(asCScriptEngine *engine); QAsCodeParser(asCScriptEngine *engine);
QAsCodeParser(asIScriptEngine *engine);
~QAsCodeParser(); ~QAsCodeParser();
public: public:
@ -100,9 +101,9 @@ private:
QMap<qsizetype, CodeSegment> m_segs; // global functions QMap<qsizetype, CodeSegment> m_segs; // global functions
public: public:
SymbolTable preParse(const QByteArray &codes); SymbolTable parse(const QByteArray &codes);
SymbolTable parse(qsizetype offset, const QByteArray &codes); SymbolTable parseIntell(qsizetype offset, const QByteArray &codes);
private: private:
void ParseScript(bool inBlock); void ParseScript(bool inBlock);

View File

@ -37,6 +37,8 @@ bool ScriptConsoleMachine::executeCode(const QString &code) {
return execString(engine(), code); return execString(engine(), code);
} }
ScriptObjModel *ScriptConsoleMachine::model() const { return _model; }
bool ScriptConsoleMachine::configureEngine(asIScriptEngine *engine) { bool ScriptConsoleMachine::configureEngine(asIScriptEngine *engine) {
_clsfn = std::bind(&ScriptConsoleMachine::onClearConsole, this); _clsfn = std::bind(&ScriptConsoleMachine::onClearConsole, this);
auto r = engine->RegisterGlobalFunction( auto r = engine->RegisterGlobalFunction(
@ -51,34 +53,15 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
auto mod = engine->GetModule("Console", asGM_CREATE_IF_NOT_EXISTS); auto mod = engine->GetModule("Console", asGM_CREATE_IF_NOT_EXISTS);
if (code.startsWith(QStringLiteral("addvar "))) { if (code.startsWith(QStringLiteral("addvar "))) {
auto varcmd = code.mid(7) + QStringLiteral(";"); 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; auto ret = mod->CompileGlobalVar("addvar", varcmd.toUtf8(), 0) >= 0;
_model->updateData(); _model->updateData();
return ret; return ret;
} else if (code.startsWith(QStringLiteral("addfn "))) {
auto fncmd = code.mid(6);
asIScriptFunction *func = nullptr;
int r = mod->CompileFunction("addfn", fncmd.toUtf8(), 0,
asCOMP_ADD_TO_MODULE, &func);
if (r < 0) {
return false;
} else {
// The script engine supports function overloads, but to simplify
// the console we'll disallow multiple functions with the same name.
// We know the function was added, so if GetFunctionByName() fails
// it is because there already was another function with the same
// name.
if (mod->GetFunctionByName(func->GetName()) == 0) {
mod->RemoveFunction(func);
return false;
}
}
// We must release the function object
if (func) {
func->Release();
}
return true;
} else if (code.startsWith(QStringLiteral("rmvar "))) { } else if (code.startsWith(QStringLiteral("rmvar "))) {
if (mod == nullptr || mod->GetGlobalVarCount() == 0) { if (mod == nullptr || mod->GetGlobalVarCount() == 0) {
return false; return false;
@ -95,24 +78,6 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
} }
} }
_model->updateData(); _model->updateData();
return true;
} else if (code.startsWith(QStringLiteral("rmfn "))) {
if (mod == nullptr || mod->GetFunctionCount() == 0) {
return false;
}
// remove the tailing semi-colons
static QRegularExpression re(QStringLiteral(";+$"));
auto fncmd = code.mid(5).remove(re);
for (auto &fn : fncmd.split(' ', Qt::SkipEmptyParts)) {
asIScriptFunction *func = mod->GetFunctionByName(fn.toUtf8());
if (func) {
mod->RemoveFunction(func);
}
}
engine->GarbageCollect();
return true; return true;
} else if (code.startsWith(QStringLiteral("lsfn"))) { } else if (code.startsWith(QStringLiteral("lsfn"))) {
if (code.trimmed().length() != 4) { if (code.trimmed().length() != 4) {
@ -187,90 +152,6 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
emit onOutput(MessageType::Info, info); emit onOutput(MessageType::Info, info);
return true; return true;
} else { } else {
return ExecuteString(engine, code.toUtf8(), mod, immediateContext()) >= return ScriptMachine::executeCode(code);
0;
} }
} }
int ScriptConsoleMachine::ExecuteString(asIScriptEngine *engine,
const char *code, asIScriptModule *mod,
asIScriptContext *ctx) {
return ExecuteString(engine, code, 0, asTYPEID_VOID, mod, ctx);
}
ScriptObjModel *ScriptConsoleMachine::model() const { return _model; }
int ScriptConsoleMachine::ExecuteString(asIScriptEngine *engine,
const char *code, void *ref,
int refTypeId, asIScriptModule *mod,
asIScriptContext *ctx) {
// Wrap the code in a function so that it can be compiled and executed
std::string funcCode = " ExecuteString() {\n";
funcCode += code;
funcCode += "\n}";
// Determine the return type based on the type of the ref arg
funcCode = engine->GetTypeDeclaration(refTypeId, true) + funcCode;
// GetModule will free unused types, so to be on the safe side we'll
// hold on to a reference to the type
asITypeInfo *type = 0;
if (refTypeId & asTYPEID_MASK_OBJECT) {
type = engine->GetTypeInfoById(refTypeId);
if (type)
type->AddRef();
}
// If no module was provided, get a dummy from the engine
asIScriptModule *execMod =
mod ? mod : engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE);
// Now it's ok to release the type
if (type)
type->Release();
// Compile the function that can be executed
asIScriptFunction *func = 0;
int r = execMod->CompileFunction("ExecuteString", funcCode.c_str(), -1, 0,
&func);
if (r < 0)
return r;
// If no context was provided, request a new one from the engine
asIScriptContext *execCtx = ctx ? ctx : engine->RequestContext();
r = execCtx->Prepare(func);
if (r >= 0) {
// Execute the function
r = execCtx->Execute();
// Unless the provided type was void retrieve it's value
if (ref != 0 && refTypeId != asTYPEID_VOID) {
if (refTypeId & asTYPEID_OBJHANDLE) {
// Expect the pointer to be null to start with
assert(*reinterpret_cast<void **>(ref) == 0);
*reinterpret_cast<void **>(ref) = *reinterpret_cast<void **>(
execCtx->GetAddressOfReturnValue());
engine->AddRefScriptObject(*reinterpret_cast<void **>(ref),
engine->GetTypeInfoById(refTypeId));
} else if (refTypeId & asTYPEID_MASK_OBJECT) {
// Use the registered assignment operator to do a value
// assign. This assumes that the ref is pointing to a valid
// object instance.
engine->AssignScriptObject(ref,
execCtx->GetAddressOfReturnValue(),
engine->GetTypeInfoById(refTypeId));
} else {
// Copy the primitive value
memcpy(ref, execCtx->GetAddressOfReturnValue(),
engine->GetSizeOfPrimitiveType(refTypeId));
}
}
}
// Clean up
func->Release();
if (!ctx)
engine->ReturnContext(execCtx);
return r;
}

View File

@ -41,14 +41,6 @@ protected:
private: private:
bool execString(asIScriptEngine *engine, const QString &code); bool execString(asIScriptEngine *engine, const QString &code);
// copy from helper
int ExecuteString(asIScriptEngine *engine, const char *code,
asIScriptModule *mod, asIScriptContext *ctx);
int ExecuteString(asIScriptEngine *engine, const char *code, void *ref,
int refTypeId, asIScriptModule *mod,
asIScriptContext *ctx);
private: private:
ScriptObjModel *_model = nullptr; ScriptObjModel *_model = nullptr;

View File

@ -26,7 +26,10 @@
#include "AngelScript/sdk/add_on/scriptmath/scriptmath.h" #include "AngelScript/sdk/add_on/scriptmath/scriptmath.h"
#include "AngelScript/sdk/add_on/scriptmath/scriptmathcomplex.h" #include "AngelScript/sdk/add_on/scriptmath/scriptmathcomplex.h"
#include "AngelScript/sdk/add_on/weakref/weakref.h" #include "AngelScript/sdk/add_on/weakref/weakref.h"
#include "angelobjstring.h"
#include "class/asbuilder.h" #include "class/asbuilder.h"
#include "class/qascodeparser.h"
#include "define.h" #include "define.h"
#include "plugin/pluginsystem.h" #include "plugin/pluginsystem.h"
#include "scriptaddon/scriptcolor.h" #include "scriptaddon/scriptcolor.h"
@ -34,16 +37,9 @@
#include "scriptaddon/scriptqstring.h" #include "scriptaddon/scriptqstring.h"
#include "scriptaddon/scriptregex.h" #include "scriptaddon/scriptregex.h"
#include "angelobjstring.h"
#include <QProcess> #include <QProcess>
ScriptMachine::~ScriptMachine() { ScriptMachine::~ScriptMachine() {
if (_immediateContext) {
_immediateContext->Release();
_immediateContext = nullptr;
}
if (_ctxMgr) { if (_ctxMgr) {
delete _ctxMgr; delete _ctxMgr;
} }
@ -55,10 +51,6 @@ bool ScriptMachine::inited() { return _engine != nullptr; }
bool ScriptMachine::isRunning() const { return _ctxMgr->isRunning(); } bool ScriptMachine::isRunning() const { return _ctxMgr->isRunning(); }
bool ScriptMachine::isInDebugMode() const {
return _debugger->getEngine() != nullptr;
}
bool ScriptMachine::configureEngine(asIScriptEngine *engine) { bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
if (engine == nullptr) { if (engine == nullptr) {
return false; return false;
@ -75,6 +67,7 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
engine->SetEngineProperty(asEP_ALTER_SYNTAX_NAMED_ARGS, 0); engine->SetEngineProperty(asEP_ALTER_SYNTAX_NAMED_ARGS, 0);
engine->SetEngineProperty(asEP_ALLOW_UNICODE_IDENTIFIERS, true); engine->SetEngineProperty(asEP_ALLOW_UNICODE_IDENTIFIERS, true);
engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, true); // enum class like engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, true); // enum class like
setDebugMode(false);
// The script compiler will send any compiler messages to the callback // The script compiler will send any compiler messages to the callback
auto r = engine->SetMessageCallback(asFUNCTION(messageCallback), this, auto r = engine->SetMessageCallback(asFUNCTION(messageCallback), this,
@ -191,10 +184,6 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
PluginSystem::instance().angelApi()->installAPI(this); PluginSystem::instance().angelApi()->installAPI(this);
_immediateContext = engine->CreateContext();
_immediateContext->SetExceptionCallback(
asMETHOD(ScriptMachine, exceptionCallback), this, asCALL_THISCALL);
return true; return true;
} }
@ -277,6 +266,7 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
// We will only initialize the global variables once we're // We will only initialize the global variables once we're
// ready to execute, so disable the automatic initialization // ready to execute, so disable the automatic initialization
_engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false); _engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false);
setDebugMode(isInDebug);
asBuilder builder(_engine); asBuilder builder(_engine);
@ -348,6 +338,8 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
// The context manager will request the context from the // The context manager will request the context from the
// pool, which will automatically attach the debugger // pool, which will automatically attach the debugger
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true); asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
ctx->SetExceptionCallback(asMETHOD(ScriptMachine, exceptionCallback), this,
asCALL_THISCALL);
// Execute the script until completion // Execute the script until completion
// The script may create co-routines. These will automatically // The script may create co-routines. These will automatically
@ -404,16 +396,23 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
_ctxPool.clear(); _ctxPool.clear();
// Detach debugger // Detach debugger
Q_ASSERT(_debugger);
_debugger->setEngine(nullptr);
if (isInDebug) { if (isInDebug) {
Q_ASSERT(_debugger);
_debugger->setEngine(nullptr);
_debugger->clearBreakPoint(); _debugger->clearBreakPoint();
setDebugMode(false);
emit onDebugFinished(); emit onDebugFinished();
} }
return r >= 0; return r >= 0;
} }
void ScriptMachine::abortScript() {
if (_debugger->getEngine()) {
_debugger->runDebugAction(asDebugger::ABORT);
}
}
void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) { void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) {
MessageType t = MessageType::Print; MessageType t = MessageType::Print;
switch (msg->type) { switch (msg->type) {
@ -1614,17 +1613,141 @@ void ScriptMachine::registerEngineAddon(asIScriptEngine *engine) {
RegisterExceptionRoutines(engine); RegisterExceptionRoutines(engine);
} }
asIScriptEngine *ScriptMachine::engine() const { return _engine; } bool ScriptMachine::isDebugMode() const {
return !_engine->GetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES);
asIScriptContext *ScriptMachine::immediateContext() const {
return _immediateContext;
} }
void ScriptMachine::setDebugMode(bool isDbg) {
_engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, !isDbg);
}
asIScriptEngine *ScriptMachine::engine() const { return _engine; }
asDebugger *ScriptMachine::debugger() const { return _debugger; } asDebugger *ScriptMachine::debugger() const { return _debugger; }
bool ScriptMachine::executeCode(const QString &code) { bool ScriptMachine::executeCode(const QString &code) {
return ExecuteString( // We will only initialize the global variables once we're
_engine, code.toUtf8(), // ready to execute, so disable the automatic initialization
_engine->GetModule("Console", asGM_CREATE_IF_NOT_EXISTS), _engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false);
_immediateContext) >= 0; setDebugMode(false);
asIScriptModule *mod = _engine->GetModule("Console", asGM_ONLY_IF_EXISTS);
if (!mod) {
return false;
}
// first, preparse the code
QAsCodeParser parser(_engine);
auto ccode = code.toUtf8();
asIScriptFunction *func = nullptr;
auto ret = parser.parse(ccode);
// check whether there is any enum/class
if (ret.isEmpty()) {
// ok, wrap the codes
ccode.prepend("void main(){").append("}");
// start to compile
auto r = mod->CompileFunction(nullptr, ccode, -1, 0, &func);
if (r < 0) {
MessageInfo info;
info.message = tr("Script failed to build");
emit onOutput(MessageType::Error, info);
mod->Discard();
return false;
}
} else {
mod->AddScriptSection("Runner", ccode, ccode.size(), 0);
auto r = mod->Build();
if (r < 0) {
MessageInfo info;
info.message = tr("Script failed to build");
emit onOutput(MessageType::Error, info);
mod->Discard();
return false;
}
// Find the main function
func = mod->GetFunctionByDecl("void main()");
if (func == nullptr) {
// Try again with "int main()"
func = mod->GetFunctionByDecl("int main()");
}
if (func == nullptr) {
MessageInfo info;
info.message = tr("Cannot find 'int main()' or 'void main()'");
emit onOutput(MessageType::Error, info);
mod->Discard();
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);
ctx->SetExceptionCallback(asMETHOD(ScriptMachine, exceptionCallback), this,
asCALL_THISCALL);
// Execute the script until completion
// The script may create co-routines. These will automatically
// be managed by the context manager
while (_ctxMgr->ExecuteScripts())
;
// Check if the main script finished normally
int r = ctx->GetState();
if (r != asEXECUTION_FINISHED) {
if (r == asEXECUTION_EXCEPTION) {
MessageInfo info;
info.message = tr("The script failed with an exception") +
QStringLiteral("\n") +
QString::fromStdString(GetExceptionInfo(ctx, true));
emit onOutput(MessageType::Error, info);
r = -1;
} else if (r == asEXECUTION_ABORTED) {
MessageInfo info;
info.message = tr("The script was aborted");
emit onOutput(MessageType::Error, info);
r = -1;
} else {
auto e = QMetaEnum::fromType<asEContextState>();
MessageInfo info;
info.message = tr("The script terminated unexpectedly") +
QStringLiteral(" (") + e.valueToKey(r) +
QStringLiteral(")");
emit onOutput(MessageType::Error, info);
r = -1;
}
} else {
r = 0;
}
// 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 : _ctxPool) {
ctx->Release();
}
_ctxPool.clear();
// Detach debugger
Q_ASSERT(_debugger);
_debugger->setEngine(nullptr);
return r >= 0;
} }

View File

@ -87,12 +87,8 @@ public:
bool isRunning() const; bool isRunning() const;
bool isInDebugMode() const;
asDebugger *debugger() const; asDebugger *debugger() const;
asIScriptContext *immediateContext() const;
asIScriptEngine *engine() const; asIScriptEngine *engine() const;
bool insteadFoundDisabled() const; bool insteadFoundDisabled() const;
@ -100,10 +96,19 @@ public:
static void registerEngineAddon(asIScriptEngine *engine); static void registerEngineAddon(asIScriptEngine *engine);
// debug or release?
bool isDebugMode() const;
void setDebugMode(bool isDbg);
public slots: public slots:
virtual bool executeCode(const QString &code); virtual bool executeCode(const QString &code);
virtual bool executeScript(const QString &script, bool isInDebug = false); virtual bool executeScript(const QString &script, bool isInDebug = false);
void abortScript();
private:
bool execute(const QString &code, bool isInDebug = false);
protected: protected:
virtual bool configureEngine(asIScriptEngine *engine); virtual bool configureEngine(asIScriptEngine *engine);
@ -165,8 +170,6 @@ private:
QVector<asITypeInfo *> _rtypes; QVector<asITypeInfo *> _rtypes;
std::function<QString(void)> _getInputFn; std::function<QString(void)> _getInputFn;
asIScriptContext *_immediateContext = nullptr;
bool m_insteadFoundDisabled = false; bool m_insteadFoundDisabled = false;
}; };

View File

@ -246,6 +246,7 @@ WingCStruct::RegisteredEvents WingCStruct::registeredEvents() const {
RegisteredEvents evs; RegisteredEvents evs;
evs.setFlag(RegisteredEvent::ScriptUnSafeFnRegistering); evs.setFlag(RegisteredEvent::ScriptUnSafeFnRegistering);
evs.setFlag(RegisteredEvent::ScriptPragma); evs.setFlag(RegisteredEvent::ScriptPragma);
evs.setFlag(RegisteredEvent::ScriptPragmaInit);
return evs; return evs;
} }
@ -318,6 +319,8 @@ bool WingCStruct::eventOnScriptPragma(const QString &script,
return false; return false;
} }
void WingCStruct::eventOnScriptPragmaInit() { resetEnv(); }
QHash<QString, WingHex::IWingPlugin::UNSAFE_SCFNPTR> QHash<QString, WingHex::IWingPlugin::UNSAFE_SCFNPTR>
WingCStruct::registeredScriptUnsafeFns() const { WingCStruct::registeredScriptUnsafeFns() const {
return _scriptUnsafe; return _scriptUnsafe;

View File

@ -52,6 +52,7 @@ public:
virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const override; virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const override;
virtual bool eventOnScriptPragma(const QString &script, virtual bool eventOnScriptPragma(const QString &script,
const QStringList &comments) override; const QStringList &comments) override;
virtual void eventOnScriptPragmaInit() override;
virtual QHash<QString, UNSAFE_SCFNPTR> virtual QHash<QString, UNSAFE_SCFNPTR>
registeredScriptUnsafeFns() const override; registeredScriptUnsafeFns() const override;

View File

@ -570,7 +570,7 @@ ErrFile EditorView::save(const QString &workSpaceName, const QString &path,
} }
} }
if (doc->isUndoByteModified() || isNewFile()) { if (doc->isUndoByteModified() || m_fileName != fileName || isNewFile()) {
if (m_docType == DocumentType::Extension) { if (m_docType == DocumentType::Extension) {
if (_dev->isOpen()) { if (_dev->isOpen()) {
_dev->close(); _dev->close();

View File

@ -21,13 +21,9 @@
#include <QApplication> #include <QApplication>
#include <QColor> #include <QColor>
#include <QShortcut> #include <QKeyEvent>
ScriptingConsole::ScriptingConsole(QWidget *parent) : QConsoleWidget(parent) { ScriptingConsole::ScriptingConsole(QWidget *parent) : QConsoleWidget(parent) {}
auto shortCut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_L), this);
connect(shortCut, &QShortcut::activated, this,
&ScriptingConsole::clearConsole);
}
ScriptingConsole::~ScriptingConsole() {} ScriptingConsole::~ScriptingConsole() {}
@ -49,6 +45,8 @@ void ScriptingConsole::init() {
_sp = new ScriptConsoleMachine(_getInputFn, this); _sp = new ScriptConsoleMachine(_getInputFn, this);
connect(_sp, &ScriptConsoleMachine::onClearConsole, this, connect(_sp, &ScriptConsoleMachine::onClearConsole, this,
&ScriptingConsole::clear); &ScriptingConsole::clear);
connect(this, &ScriptingConsole::abortEvaluation, _sp,
&ScriptConsoleMachine::abortScript);
connect(_sp, &ScriptConsoleMachine::onOutput, this, connect(_sp, &ScriptConsoleMachine::onOutput, this,
[=](ScriptConsoleMachine::MessageType type, [=](ScriptConsoleMachine::MessageType type,
@ -157,6 +155,14 @@ QString ScriptingConsole::getInput() {
return instr; return instr;
} }
void ScriptingConsole::keyPressEvent(QKeyEvent *e) {
if (e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_L) {
clearConsole();
} else {
QConsoleWidget::keyPressEvent(e);
}
}
void ScriptingConsole::appendCommandPrompt(bool storeOnly) { void ScriptingConsole::appendCommandPrompt(bool storeOnly) {
QString commandPrompt; QString commandPrompt;
@ -167,7 +173,7 @@ void ScriptingConsole::appendCommandPrompt(bool storeOnly) {
if (!cursor.atBlockStart()) { if (!cursor.atBlockStart()) {
commandPrompt = QStringLiteral("\n"); commandPrompt = QStringLiteral("\n");
} }
if (_sp && _sp->isInDebugMode()) { if (_sp && _sp->isDebugMode()) {
commandPrompt += QStringLiteral("[dbg] > "); commandPrompt += QStringLiteral("[dbg] > ");
} else { } else {
commandPrompt += QStringLiteral("as > "); commandPrompt += QStringLiteral("as > ");

View File

@ -58,6 +58,9 @@ private:
QString getInput(); QString getInput();
protected:
void keyPressEvent(QKeyEvent *e) override;
private: private:
ScriptConsoleMachine *_sp = nullptr; ScriptConsoleMachine *_sp = nullptr;
QTextStream _s; QTextStream _s;

View File

@ -2146,13 +2146,22 @@ void MainWindow::on_saveas() {
return; return;
} }
auto filename = WingFileDialog::getSaveFileName(this, tr("ChooseSaveFile"), QString lastpath;
m_lastusedpath); if (editor->isNewFile() || editor->isExtensionFile() ||
editor->isDriver()) {
lastpath = m_lastusedpath;
} else {
lastpath = editor->fileName();
}
auto filename =
WingFileDialog::getSaveFileName(this, tr("ChooseSaveFile"), lastpath);
if (filename.isEmpty()) if (filename.isEmpty())
return; return;
m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath(); m_lastusedpath = QFileInfo(filename).absoluteDir().absolutePath();
auto res = saveEditor(editor, filename, false); bool isWorkspace = editor->isOriginWorkSpace();
auto res = saveEditor(editor, filename, false, false, isWorkspace);
restart: restart:
switch (res) { switch (res) {
@ -2161,6 +2170,7 @@ restart:
tr("SaveSuccessfully")); tr("SaveSuccessfully"));
RecentFileManager::RecentInfo info; RecentFileManager::RecentInfo info;
info.fileName = filename; info.fileName = filename;
info.isWorkSpace = isWorkspace;
m_recentmanager->addRecentFile(info); m_recentmanager->addRecentFile(info);
break; break;
} }
@ -3704,7 +3714,7 @@ ErrFile MainWindow::saveEditor(EditorView *editor, const QString &filename,
auto oldName = editor->fileName(); auto oldName = editor->fileName();
QString workspace = m_views.value(editor); QString workspace = m_views.value(editor);
if (workspace.isEmpty()) { if (forceWorkspace || workspace.isEmpty()) {
if (forceWorkspace || editor->change2WorkSpace()) { if (forceWorkspace || editor->change2WorkSpace()) {
QString curFile; QString curFile;
if (!editor->isDriver() && !editor->isExtensionFile()) { if (!editor->isDriver() && !editor->isExtensionFile()) {
@ -4048,6 +4058,12 @@ void MainWindow::closeEvent(QCloseEvent *event) {
return; return;
} }
// then checking the scripting console
auto sm = m_scriptConsole->consoleMachine();
if (sm->isRunning()) {
sm->abortScript();
}
// then checking itself // then checking itself
if (!m_views.isEmpty()) { if (!m_views.isEmpty()) {
QStringList unSavedFiles; QStringList unSavedFiles;

View File

@ -27,6 +27,7 @@
#include "class/wingfiledialog.h" #include "class/wingfiledialog.h"
#include "class/wingmessagebox.h" #include "class/wingmessagebox.h"
#include "control/toast.h" #include "control/toast.h"
#include "plugin/pluginsystem.h"
#include "qcodeeditwidget/qeditconfig.h" #include "qcodeeditwidget/qeditconfig.h"
#include "qcodeeditwidget/qformatconfig.h" #include "qcodeeditwidget/qformatconfig.h"
#include "qdocumentline.h" #include "qdocumentline.h"
@ -552,7 +553,7 @@ RibbonTabContent *ScriptingDialog::buildDebugPage(RibbonTabContent *tab) {
bool isPaused = false; bool isPaused = false;
if (runner) { if (runner) {
isRun = runner->isRunning(); isRun = runner->isRunning();
isDbg = runner->isInDebugMode(); isDbg = runner->isDebugMode();
auto dbg = runner->debugger(); auto dbg = runner->debugger();
isPaused = dbg->currentState() == asDebugger::PAUSE; isPaused = dbg->currentState() == asDebugger::PAUSE;
} }
@ -792,7 +793,7 @@ void ScriptingDialog::registerEditorView(ScriptEditor *editor) {
Q_ASSERT(m_views.contains(editor)); Q_ASSERT(m_views.contains(editor));
auto m = m_consoleout->machine(); auto m = m_consoleout->machine();
if (m->isInDebugMode() && _DebugingScript == editor->fileName()) { if (m->isDebugMode() && _DebugingScript == editor->fileName()) {
if (WingMessageBox::warning( if (WingMessageBox::warning(
this, this->windowTitle(), tr("ScriptStillRunning"), this, this->windowTitle(), tr("ScriptStillRunning"),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) {
@ -836,6 +837,7 @@ void ScriptingDialog::registerEditorView(ScriptEditor *editor) {
} }
editor->deleteDockWidget(); editor->deleteDockWidget();
updateEditModeEnabled();
}); });
LangService::instance().applyLanguageSerivce(editor->editor()); LangService::instance().applyLanguageSerivce(editor->editor());
@ -929,7 +931,7 @@ void ScriptingDialog::updateRunDebugMode(bool disable) {
bool isPaused = false; bool isPaused = false;
if (runner) { if (runner) {
isRun = runner->isRunning(); isRun = runner->isRunning();
isDbg = runner->isInDebugMode(); isDbg = runner->isDebugMode();
auto dbg = runner->debugger(); auto dbg = runner->debugger();
isPaused = dbg->currentState() == asDebugger::PAUSE; isPaused = dbg->currentState() == asDebugger::PAUSE;
} }
@ -987,7 +989,7 @@ void ScriptingDialog::setCurrentEditorScale(qreal rate) {
bool ScriptingDialog::isCurrentDebugging() const { bool ScriptingDialog::isCurrentDebugging() const {
auto m = m_consoleout->machine(); auto m = m_consoleout->machine();
return m && m->isInDebugMode(); return m && m->isDebugMode();
} }
ScriptEditor *ScriptingDialog::openFile(const QString &filename) { ScriptEditor *ScriptingDialog::openFile(const QString &filename) {
@ -1014,7 +1016,7 @@ ScriptEditor *ScriptingDialog::openFile(const QString &filename) {
void ScriptingDialog::runDbgCommand(asDebugger::DebugAction action) { void ScriptingDialog::runDbgCommand(asDebugger::DebugAction action) {
updateRunDebugMode(true); updateRunDebugMode(true);
auto machine = m_consoleout->machine(); auto machine = m_consoleout->machine();
if (machine->isInDebugMode()) { if (machine->isDebugMode()) {
auto dbg = machine->debugger(); auto dbg = machine->debugger();
dbg->runDebugAction(action); dbg->runDebugAction(action);
} }
@ -1043,6 +1045,8 @@ void ScriptingDialog::startDebugScript(const QString &fileName) {
m_consoleout->clear(); m_consoleout->clear();
_DebugingScript = fileName; _DebugingScript = fileName;
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::ScriptPragmaInit, {});
m_consoleout->machine()->executeScript(fileName, true); m_consoleout->machine()->executeScript(fileName, true);
updateRunDebugMode(); updateRunDebugMode();
@ -1054,7 +1058,7 @@ void ScriptingDialog::addBreakPoint(QEditor *editor, int lineIndex) {
auto curLine = lineIndex + 1; auto curLine = lineIndex + 1;
auto dbg = m_consoleout->machine()->debugger(); auto dbg = m_consoleout->machine()->debugger();
if (m_consoleout->machine()->isInDebugMode()) { if (m_consoleout->machine()->isDebugMode()) {
auto line = editor->document()->line(lineIndex); auto line = editor->document()->line(lineIndex);
auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint); auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint);
auto curSym = m_symID.value(Symbols::DbgRunCurrentLine); auto curSym = m_symID.value(Symbols::DbgRunCurrentLine);
@ -1084,7 +1088,7 @@ void ScriptingDialog::removeBreakPoint(QEditor *editor, int lineIndex) {
auto curLine = lineIndex + 1; auto curLine = lineIndex + 1;
auto dbg = m_consoleout->machine()->debugger(); auto dbg = m_consoleout->machine()->debugger();
if (m_consoleout->machine()->isInDebugMode()) { if (m_consoleout->machine()->isDebugMode()) {
auto line = editor->document()->line(lineIndex); auto line = editor->document()->line(lineIndex);
auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint); auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint);
auto curSym = m_symID.value(Symbols::DbgRunCurrentLine); auto curSym = m_symID.value(Symbols::DbgRunCurrentLine);
@ -1113,7 +1117,7 @@ void ScriptingDialog::toggleBreakPoint(QEditor *editor, int lineIndex) {
auto curLine = lineIndex + 1; auto curLine = lineIndex + 1;
auto dbg = m_consoleout->machine()->debugger(); auto dbg = m_consoleout->machine()->debugger();
if (m_consoleout->machine()->isInDebugMode()) { if (m_consoleout->machine()->isDebugMode()) {
auto line = editor->document()->line(lineIndex); auto line = editor->document()->line(lineIndex);
auto bpMark = m_symID.value(Symbols::BreakPoint); auto bpMark = m_symID.value(Symbols::BreakPoint);
auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint); auto hitCur = m_symID.value(Symbols::DbgRunHitBreakPoint);
@ -1225,6 +1229,11 @@ void ScriptingDialog::on_save() {
return; return;
} }
if (editor->fileName().isEmpty()) {
on_saveas();
return;
}
auto res = editor->save(); auto res = editor->save();
if (res) { if (res) {
Toast::toast(this, NAMEICONRES(QStringLiteral("save")), Toast::toast(this, NAMEICONRES(QStringLiteral("save")),
@ -1241,6 +1250,11 @@ void ScriptingDialog::on_saveas() {
return; return;
} }
QString lastPath = editor->fileName();
if (lastPath.isEmpty()) {
lastPath = m_lastusedpath;
}
auto filename = WingFileDialog::getSaveFileName( auto filename = WingFileDialog::getSaveFileName(
this, tr("ChooseSaveFile"), m_lastusedpath, this, tr("ChooseSaveFile"), m_lastusedpath,
QStringLiteral("AngelScript (*.as *.angelscript)")); QStringLiteral("AngelScript (*.as *.angelscript)"));
@ -1383,6 +1397,8 @@ void ScriptingDialog::on_runscript() {
return; return;
} }
m_consoleout->clear(); m_consoleout->clear();
PluginSystem::instance().dispatchEvent(
IWingPlugin::RegisteredEvent::ScriptPragmaInit, {});
m_consoleout->machine()->executeScript(e->fileName()); m_consoleout->machine()->executeScript(e->fileName());
updateRunDebugMode(); updateRunDebugMode();
} }

View File

@ -477,6 +477,7 @@ public:
PluginFileOpened = 1u << 9, PluginFileOpened = 1u << 9,
PluginFileClosed = 1u << 10, PluginFileClosed = 1u << 10,
ScriptUnSafeFnRegistering = 1u << 11, ScriptUnSafeFnRegistering = 1u << 11,
ScriptPragmaInit = 1u << 12
}; };
Q_DECLARE_FLAGS(RegisteredEvents, RegisteredEvent) Q_DECLARE_FLAGS(RegisteredEvents, RegisteredEvent)
@ -591,6 +592,8 @@ public:
return false; return false;
} }
virtual void eventOnScriptPragmaInit() {}
signals: signals:
bool existsServiceHost(const QString &puid); bool existsServiceHost(const QString &puid);

View File

@ -475,6 +475,12 @@ bool PluginSystem::dispatchEvent(IWingPlugin::RegisteredEvent event,
} }
return (*r)->eventOnScriptPragma(section, params.at(3).toStringList()); return (*r)->eventOnScriptPragma(section, params.at(3).toStringList());
} break; } break;
case WingHex::IWingPlugin::RegisteredEvent::ScriptPragmaInit: {
Q_ASSERT(params.isEmpty());
for (auto &plg : _evplgs[event]) {
plg->eventOnScriptPragmaInit();
}
} break;
case WingHex::IWingPlugin::RegisteredEvent::PluginFileOpened: { case WingHex::IWingPlugin::RegisteredEvent::PluginFileOpened: {
Q_ASSERT(params.size() == 4); Q_ASSERT(params.size() == 4);
auto plg = auto plg =
@ -893,6 +899,10 @@ void PluginSystem::registerEvents(IWingPlugin *plg) {
_evplgs[IWingPlugin::RegisteredEvent::ScriptPragma].append(plg); _evplgs[IWingPlugin::RegisteredEvent::ScriptPragma].append(plg);
} }
if (evs.testFlag(IWingPlugin::RegisteredEvent::ScriptPragmaInit)) {
_evplgs[IWingPlugin::RegisteredEvent::ScriptPragmaInit].append(plg);
}
if (evs.testFlag(IWingPlugin::RegisteredEvent::PluginFileOpened)) { if (evs.testFlag(IWingPlugin::RegisteredEvent::PluginFileOpened)) {
_evplgs[IWingPlugin::RegisteredEvent::PluginFileOpened].append(plg); _evplgs[IWingPlugin::RegisteredEvent::PluginFileOpened].append(plg);
} }