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

View File

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

View File

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

View File

@ -21,22 +21,52 @@
#include "AngelScript/sdk/angelscript/source/as_tokenizer.h"
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;
isParsingAppInterface = false;
}
QAsCodeParser::~QAsCodeParser() {}
QAsCodeParser::SymbolTable QAsCodeParser::preParse(const QByteArray &codes) {
QAsCodeParser::SymbolTable QAsCodeParser::parse(const QByteArray &codes) {
Reset();
code = codes;
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,
const QByteArray &codes) {
preParse(codes);
QAsCodeParser::SymbolTable QAsCodeParser::parseIntell(qsizetype offset,
const QByteArray &codes) {
parse(codes);
// then we will parse the symbols we want
SymbolTable ret;

View File

@ -43,6 +43,7 @@
class QAsCodeParser {
public:
QAsCodeParser(asCScriptEngine *engine);
QAsCodeParser(asIScriptEngine *engine);
~QAsCodeParser();
public:
@ -100,9 +101,9 @@ private:
QMap<qsizetype, CodeSegment> m_segs; // global functions
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:
void ParseScript(bool inBlock);

View File

@ -37,6 +37,8 @@ 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(
@ -51,34 +53,15 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
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("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 "))) {
if (mod == nullptr || mod->GetGlobalVarCount() == 0) {
return false;
@ -95,24 +78,6 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
}
}
_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;
} else if (code.startsWith(QStringLiteral("lsfn"))) {
if (code.trimmed().length() != 4) {
@ -187,90 +152,6 @@ bool ScriptConsoleMachine::execString(asIScriptEngine *engine,
emit onOutput(MessageType::Info, info);
return true;
} else {
return ExecuteString(engine, code.toUtf8(), mod, immediateContext()) >=
0;
return ScriptMachine::executeCode(code);
}
}
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:
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:
ScriptObjModel *_model = nullptr;

View File

@ -26,7 +26,10 @@
#include "AngelScript/sdk/add_on/scriptmath/scriptmath.h"
#include "AngelScript/sdk/add_on/scriptmath/scriptmathcomplex.h"
#include "AngelScript/sdk/add_on/weakref/weakref.h"
#include "angelobjstring.h"
#include "class/asbuilder.h"
#include "class/qascodeparser.h"
#include "define.h"
#include "plugin/pluginsystem.h"
#include "scriptaddon/scriptcolor.h"
@ -34,16 +37,9 @@
#include "scriptaddon/scriptqstring.h"
#include "scriptaddon/scriptregex.h"
#include "angelobjstring.h"
#include <QProcess>
ScriptMachine::~ScriptMachine() {
if (_immediateContext) {
_immediateContext->Release();
_immediateContext = nullptr;
}
if (_ctxMgr) {
delete _ctxMgr;
}
@ -55,10 +51,6 @@ bool ScriptMachine::inited() { return _engine != nullptr; }
bool ScriptMachine::isRunning() const { return _ctxMgr->isRunning(); }
bool ScriptMachine::isInDebugMode() const {
return _debugger->getEngine() != nullptr;
}
bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
if (engine == nullptr) {
return false;
@ -75,6 +67,7 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
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);
// The script compiler will send any compiler messages to the callback
auto r = engine->SetMessageCallback(asFUNCTION(messageCallback), this,
@ -191,10 +184,6 @@ bool ScriptMachine::configureEngine(asIScriptEngine *engine) {
PluginSystem::instance().angelApi()->installAPI(this);
_immediateContext = engine->CreateContext();
_immediateContext->SetExceptionCallback(
asMETHOD(ScriptMachine, exceptionCallback), this, asCALL_THISCALL);
return true;
}
@ -277,6 +266,7 @@ 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);
asBuilder builder(_engine);
@ -348,6 +338,8 @@ 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->SetExceptionCallback(asMETHOD(ScriptMachine, exceptionCallback), this,
asCALL_THISCALL);
// Execute the script until completion
// The script may create co-routines. These will automatically
@ -404,16 +396,23 @@ bool ScriptMachine::executeScript(const QString &script, bool isInDebug) {
_ctxPool.clear();
// Detach debugger
Q_ASSERT(_debugger);
_debugger->setEngine(nullptr);
if (isInDebug) {
Q_ASSERT(_debugger);
_debugger->setEngine(nullptr);
_debugger->clearBreakPoint();
setDebugMode(false);
emit onDebugFinished();
}
return r >= 0;
}
void ScriptMachine::abortScript() {
if (_debugger->getEngine()) {
_debugger->runDebugAction(asDebugger::ABORT);
}
}
void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) {
MessageType t = MessageType::Print;
switch (msg->type) {
@ -1614,17 +1613,141 @@ void ScriptMachine::registerEngineAddon(asIScriptEngine *engine) {
RegisterExceptionRoutines(engine);
}
asIScriptEngine *ScriptMachine::engine() const { return _engine; }
asIScriptContext *ScriptMachine::immediateContext() const {
return _immediateContext;
bool ScriptMachine::isDebugMode() const {
return !_engine->GetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES);
}
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; }
bool ScriptMachine::executeCode(const QString &code) {
return ExecuteString(
_engine, code.toUtf8(),
_engine->GetModule("Console", asGM_CREATE_IF_NOT_EXISTS),
_immediateContext) >= 0;
// 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);
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 isInDebugMode() const;
asDebugger *debugger() const;
asIScriptContext *immediateContext() const;
asIScriptEngine *engine() const;
bool insteadFoundDisabled() const;
@ -100,10 +96,19 @@ public:
static void registerEngineAddon(asIScriptEngine *engine);
// debug or release?
bool isDebugMode() const;
void setDebugMode(bool isDbg);
public slots:
virtual bool executeCode(const QString &code);
virtual bool executeScript(const QString &script, bool isInDebug = false);
void abortScript();
private:
bool execute(const QString &code, bool isInDebug = false);
protected:
virtual bool configureEngine(asIScriptEngine *engine);
@ -165,8 +170,6 @@ private:
QVector<asITypeInfo *> _rtypes;
std::function<QString(void)> _getInputFn;
asIScriptContext *_immediateContext = nullptr;
bool m_insteadFoundDisabled = false;
};

View File

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

View File

@ -52,6 +52,7 @@ public:
virtual QHash<QString, ScriptFnInfo> registeredScriptFns() const override;
virtual bool eventOnScriptPragma(const QString &script,
const QStringList &comments) override;
virtual void eventOnScriptPragmaInit() override;
virtual QHash<QString, UNSAFE_SCFNPTR>
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 (_dev->isOpen()) {
_dev->close();

View File

@ -21,13 +21,9 @@
#include <QApplication>
#include <QColor>
#include <QShortcut>
#include <QKeyEvent>
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(QWidget *parent) : QConsoleWidget(parent) {}
ScriptingConsole::~ScriptingConsole() {}
@ -49,6 +45,8 @@ void ScriptingConsole::init() {
_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,
@ -157,6 +155,14 @@ QString ScriptingConsole::getInput() {
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) {
QString commandPrompt;
@ -167,7 +173,7 @@ void ScriptingConsole::appendCommandPrompt(bool storeOnly) {
if (!cursor.atBlockStart()) {
commandPrompt = QStringLiteral("\n");
}
if (_sp && _sp->isInDebugMode()) {
if (_sp && _sp->isDebugMode()) {
commandPrompt += QStringLiteral("[dbg] > ");
} else {
commandPrompt += QStringLiteral("as > ");

View File

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

View File

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

View File

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

View File

@ -477,6 +477,7 @@ public:
PluginFileOpened = 1u << 9,
PluginFileClosed = 1u << 10,
ScriptUnSafeFnRegistering = 1u << 11,
ScriptPragmaInit = 1u << 12
};
Q_DECLARE_FLAGS(RegisteredEvents, RegisteredEvent)
@ -591,6 +592,8 @@ public:
return false;
}
virtual void eventOnScriptPragmaInit() {}
signals:
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());
} break;
case WingHex::IWingPlugin::RegisteredEvent::ScriptPragmaInit: {
Q_ASSERT(params.isEmpty());
for (auto &plg : _evplgs[event]) {
plg->eventOnScriptPragmaInit();
}
} break;
case WingHex::IWingPlugin::RegisteredEvent::PluginFileOpened: {
Q_ASSERT(params.size() == 4);
auto plg =
@ -893,6 +899,10 @@ void PluginSystem::registerEvents(IWingPlugin *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)) {
_evplgs[IWingPlugin::RegisteredEvent::PluginFileOpened].append(plg);
}