feat: 一些 Bug 修复和脚本处理相关
This commit is contained in:
parent
d8069aedde
commit
c01ca038a3
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -25,43 +25,49 @@
|
|||
|
||||
AngelObjString::AngelObjString() {}
|
||||
|
||||
QString AngelObjString::stringToString(void *obj, asDebugger *dbg) {
|
||||
QString AngelObjString::stringToString(void *obj, asDebugger *dbg, asUINT tag) {
|
||||
Q_UNUSED(dbg);
|
||||
|
||||
// We know the received object is a string
|
||||
QString val = *reinterpret_cast<QString *>(obj);
|
||||
if (tag == 1) {
|
||||
val.prepend('"').append('"');
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
QString AngelObjString::arrayToString(void *obj, asDebugger *dbg) {
|
||||
QString AngelObjString::arrayToString(void *obj, asDebugger *dbg, asUINT tag) {
|
||||
CScriptArray *arr = reinterpret_cast<CScriptArray *>(obj);
|
||||
|
||||
QString str;
|
||||
QTextStream s(&str);
|
||||
s << tr("(len=") << arr->GetSize() << QStringLiteral(")");
|
||||
|
||||
s << QStringLiteral(" [");
|
||||
s << QStringLiteral("{");
|
||||
for (asUINT n = 0; n < arr->GetSize(); n++) {
|
||||
s << dbg->toString(arr->At(n), arr->GetElementTypeId(),
|
||||
arr->GetArrayObjectType()->GetEngine());
|
||||
arr->GetArrayObjectType()->GetEngine(), 1);
|
||||
if (n < arr->GetSize() - 1)
|
||||
s << ", ";
|
||||
}
|
||||
s << QStringLiteral("]");
|
||||
s << QStringLiteral("}");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
QString AngelObjString::charToString(void *obj, asDebugger *dbg) {
|
||||
QString AngelObjString::charToString(void *obj, asDebugger *dbg, asUINT tag) {
|
||||
|
||||
Q_UNUSED(dbg);
|
||||
|
||||
// We know the received object is a char
|
||||
QChar *val = reinterpret_cast<QChar *>(obj);
|
||||
return QString(*val);
|
||||
auto ret = QString(*val);
|
||||
if (tag == 1) {
|
||||
ret.prepend('\'').append('\'');
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) {
|
||||
QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg,
|
||||
asUINT tag) {
|
||||
CScriptDictionary *dic = reinterpret_cast<CScriptDictionary *>(obj);
|
||||
|
||||
QString str;
|
||||
|
@ -69,11 +75,11 @@ QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) {
|
|||
|
||||
auto engine = dic->GetEngine();
|
||||
|
||||
s << " {";
|
||||
s << QStringLiteral("{");
|
||||
asUINT n = 0;
|
||||
for (CScriptDictionary::CIterator it = dic->begin(); it != dic->end();
|
||||
it++, n++) {
|
||||
s << "[" << it.GetKey() << "] = ";
|
||||
s << QStringLiteral("[") << it.GetKey() << QStringLiteral("] = ");
|
||||
|
||||
// Get the type and address of the value
|
||||
const void *val = it.GetAddressOfValue();
|
||||
|
@ -83,17 +89,17 @@ QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) {
|
|||
// active, the debugger will use the engine held inside it by
|
||||
// default, but in an environment where there multiple engines this
|
||||
// might not be the correct instance).
|
||||
s << dbg->toString(const_cast<void *>(val), typeId, engine);
|
||||
s << dbg->toString(const_cast<void *>(val), typeId, engine, 1);
|
||||
|
||||
if (n < dic->GetSize() - 1)
|
||||
s << ", ";
|
||||
s << QStringLiteral(", ");
|
||||
}
|
||||
s << "}";
|
||||
s << QStringLiteral("}");
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
QString AngelObjString::colorToString(void *obj, asDebugger *dbg) {
|
||||
QString AngelObjString::colorToString(void *obj, asDebugger *dbg, asUINT tag) {
|
||||
Q_UNUSED(dbg);
|
||||
|
||||
auto color = reinterpret_cast<QColor *>(obj);
|
||||
|
|
|
@ -28,16 +28,15 @@ class AngelObjString : public QObject {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// for debugger use
|
||||
static QString stringToString(void *obj, asDebugger *dbg);
|
||||
static QString stringToString(void *obj, asDebugger *dbg, asUINT tag);
|
||||
|
||||
static QString arrayToString(void *obj, asDebugger *dbg);
|
||||
static QString arrayToString(void *obj, asDebugger *dbg, asUINT tag);
|
||||
|
||||
static QString charToString(void *obj, asDebugger *dbg);
|
||||
static QString charToString(void *obj, asDebugger *dbg, asUINT tag);
|
||||
|
||||
static QString dictionaryToString(void *obj, asDebugger *dbg);
|
||||
static QString dictionaryToString(void *obj, asDebugger *dbg, asUINT tag);
|
||||
|
||||
static QString colorToString(void *obj, asDebugger *dbg);
|
||||
static QString colorToString(void *obj, asDebugger *dbg, asUINT tag);
|
||||
|
||||
public:
|
||||
// ==================================================
|
||||
|
|
|
@ -143,8 +143,9 @@ AppManager::AppManager(int &argc, char *argv[])
|
|||
}
|
||||
|
||||
AppManager::~AppManager() {
|
||||
InspectQtLogHelper::instance().destory();
|
||||
ClangFormatManager::instance().save();
|
||||
ScriptMachine::instance().deleteLater();
|
||||
InspectQtLogHelper::instance().destory();
|
||||
CommandHistoryManager::save(QConsoleWidget::history().strings_);
|
||||
|
||||
delete _w;
|
||||
|
@ -155,7 +156,7 @@ AppManager *AppManager::instance() { return _instance; }
|
|||
|
||||
MainWindow *AppManager::mainWindow() const { return _w; }
|
||||
|
||||
uint AppManager::currentMSecsSinceEpoch() { return _timer.elapsed(); }
|
||||
quint64 AppManager::currentMSecsSinceEpoch() { return _timer.elapsed(); }
|
||||
|
||||
void AppManager::openFile(const QString &file, bool autoDetect) {
|
||||
EditorView *editor = nullptr;
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
QApplication::tr("WingCloudStudio");
|
||||
}
|
||||
|
||||
uint currentMSecsSinceEpoch();
|
||||
quint64 currentMSecsSinceEpoch();
|
||||
|
||||
public slots:
|
||||
void openFile(const QString &file, bool autoDetect = true);
|
||||
|
|
|
@ -414,6 +414,10 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
|
|||
// first preprocess the code
|
||||
AsPreprocesser prepc(engine);
|
||||
prepc.setIncludeCallback(&AsCompletion::includeCallBack, this);
|
||||
prepc.setPragmaCallback([](const QByteArray &, AsPreprocesser *,
|
||||
const QString &,
|
||||
void *) -> int { return asSUCCESS; },
|
||||
nullptr);
|
||||
|
||||
auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"),
|
||||
code.toUtf8());
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*/
|
||||
|
||||
#include "asdebugger.h"
|
||||
#include "class/appmanager.h"
|
||||
#include "define.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
@ -78,6 +79,40 @@ void asDebugger::lineCallback(asIScriptContext *ctx) {
|
|||
if (ctx == nullptr)
|
||||
return;
|
||||
|
||||
// By default we ignore callbacks when the context is not active.
|
||||
// An application might override this to for example disconnect the
|
||||
// debugger as the execution finished.
|
||||
if (ctx->GetState() != asEXECUTION_ACTIVE)
|
||||
return;
|
||||
|
||||
auto now = AppManager::instance()->currentMSecsSinceEpoch();
|
||||
auto timer = reinterpret_cast<asPWORD>(
|
||||
ctx->GetUserData(AsUserDataType::UserData_Timer));
|
||||
auto mode = ScriptMachine::ConsoleMode(reinterpret_cast<asPWORD>(
|
||||
ctx->GetUserData(AsUserDataType::UserData_ContextMode)));
|
||||
|
||||
bool timeOut = false;
|
||||
if (timer < 0) {
|
||||
timeOut = true;
|
||||
} else {
|
||||
if (mode == ScriptMachine::DefineEvaluator) {
|
||||
timeOut = (now - timer) > 3000; // 3 s
|
||||
} else {
|
||||
timeOut = (now - timer) > 600000; // 10 min
|
||||
}
|
||||
}
|
||||
|
||||
if (timeOut) {
|
||||
auto timeOut = tr("ScriptTimedOut");
|
||||
ScriptMachine::MessageInfo info;
|
||||
info.message = timeOut;
|
||||
info.mode = mode;
|
||||
info.type = ScriptMachine::MessageType::Error;
|
||||
ScriptMachine::instance().outputMessage(info);
|
||||
ctx->Abort();
|
||||
return;
|
||||
}
|
||||
|
||||
auto isDbg = reinterpret_cast<asPWORD>(
|
||||
ctx->GetUserData(AsUserDataType::UserData_isDbg));
|
||||
if (!isDbg) {
|
||||
|
@ -107,12 +142,6 @@ void asDebugger::lineCallback(asIScriptContext *ctx) {
|
|||
}
|
||||
}
|
||||
|
||||
// By default we ignore callbacks when the context is not active.
|
||||
// An application might override this to for example disconnect the
|
||||
// debugger as the execution finished.
|
||||
if (ctx->GetState() != asEXECUTION_ACTIVE)
|
||||
return;
|
||||
|
||||
auto dbgContext = reinterpret_cast<ContextDbgInfo *>(ctx->GetUserData());
|
||||
Q_ASSERT(dbgContext);
|
||||
|
||||
|
@ -368,7 +397,7 @@ bool asDebugger::checkBreakPoint(asIScriptContext *ctx) {
|
|||
}
|
||||
|
||||
QString asDebugger::toString(void *value, asUINT typeId,
|
||||
asIScriptEngine *engine) {
|
||||
asIScriptEngine *engine, asUINT tag) {
|
||||
if (value == nullptr)
|
||||
return QStringLiteral("<null>");
|
||||
|
||||
|
@ -445,7 +474,8 @@ QString asDebugger::toString(void *value, asUINT typeId,
|
|||
s << name /*type->GetPropertyDeclaration(n)*/
|
||||
<< QStringLiteral(" = ")
|
||||
<< toString(obj->GetAddressOfProperty(n),
|
||||
obj->GetPropertyTypeId(n), type->GetEngine());
|
||||
obj->GetPropertyTypeId(n), type->GetEngine(),
|
||||
1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -482,7 +512,7 @@ QString asDebugger::toString(void *value, asUINT typeId,
|
|||
|
||||
// Invoke the callback to get the string representation of
|
||||
// this type
|
||||
s << it.value()(value, this);
|
||||
s << it.value()(value, this, tag);
|
||||
} else {
|
||||
// Unknown type: type + address
|
||||
s << type->GetName() << '(' << value << ')';
|
||||
|
|
|
@ -84,7 +84,7 @@ public:
|
|||
virtual ~asDebugger();
|
||||
|
||||
// Register callbacks to handle to-string conversions of application types
|
||||
typedef QString (*ToStringCallback)(void *obj, asDebugger *dbg);
|
||||
typedef QString (*ToStringCallback)(void *obj, asDebugger *dbg, asUINT tag);
|
||||
|
||||
void registerToStringCallback(const asITypeInfo *ti,
|
||||
ToStringCallback callback);
|
||||
|
@ -108,8 +108,9 @@ public:
|
|||
// Line callback invoked by context
|
||||
void lineCallback(asIScriptContext *ctx);
|
||||
|
||||
// tag = 1 : string should be printed with quotes
|
||||
QString toString(void *value, asUINT typeId,
|
||||
asIScriptEngine *engine = nullptr);
|
||||
asIScriptEngine *engine = nullptr, asUINT tag = 0);
|
||||
|
||||
GCStatistic gcStatistics();
|
||||
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
*/
|
||||
|
||||
#include "aspreprocesser.h"
|
||||
#include "class/scriptmachine.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QStack>
|
||||
|
||||
Q_GLOBAL_STATIC_WITH_ARGS(
|
||||
QStringList, DEFAULT_MARCO,
|
||||
|
@ -36,7 +38,9 @@ AsPreprocesser::AsPreprocesser(asIScriptEngine *engine) : engine(engine) {
|
|||
pragmaCallback = nullptr;
|
||||
pragmaParam = nullptr;
|
||||
|
||||
definedWords = *DEFAULT_MARCO;
|
||||
for (auto &m : *DEFAULT_MARCO) {
|
||||
definedWords.insert(m, {});
|
||||
}
|
||||
}
|
||||
|
||||
AsPreprocesser::~AsPreprocesser() { void ClearAll(); }
|
||||
|
@ -85,9 +89,10 @@ void AsPreprocesser::setPragmaCallback(PRAGMACALLBACK_t callback,
|
|||
pragmaParam = userParam;
|
||||
}
|
||||
|
||||
void AsPreprocesser::defineWord(const QString &word) {
|
||||
void AsPreprocesser::defineWord(const QString &word,
|
||||
const DefineValueType &value) {
|
||||
if (!definedWords.contains(word)) {
|
||||
definedWords.append(word);
|
||||
definedWords.insert(word, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +119,8 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
|
|||
// shouldn't be compiled
|
||||
QByteArray::size_type pos = 0;
|
||||
|
||||
int nested = 0;
|
||||
QStack<std::optional<bool>> m_condtionStack;
|
||||
|
||||
while (pos < modifiedScript.size()) {
|
||||
asUINT len = 0;
|
||||
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
|
@ -128,10 +134,14 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
|
|||
modifiedScript.size() - pos, &len);
|
||||
Q_UNUSED(t);
|
||||
|
||||
QByteArray token = modifiedScript.mid(pos, len);
|
||||
QByteArray token = modifiedScript.sliced(pos, len);
|
||||
pos += len;
|
||||
|
||||
if (token == "if") {
|
||||
bool isIf = token == QStringLiteral("if");
|
||||
bool isIfDef = token == QStringLiteral("ifdef");
|
||||
bool isIfnDef = token == QStringLiteral("ifndef");
|
||||
|
||||
if (isIf || isIfDef || isIfnDef) {
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_WHITESPACE) {
|
||||
|
@ -140,34 +150,87 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
|
|||
modifiedScript.size() - pos, &len);
|
||||
}
|
||||
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
QByteArray word = modifiedScript.mid(pos, len);
|
||||
if (isIfDef || isIfnDef) {
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
QByteArray word = modifiedScript.sliced(pos, len);
|
||||
|
||||
// Overwrite the #if directive with space characters to
|
||||
// avoid compiler error
|
||||
pos += len;
|
||||
overwriteCode(modifiedScript, start, pos - start);
|
||||
// Overwrite the directive with space characters to
|
||||
// avoid compiler error
|
||||
pos += len;
|
||||
overwriteCode(modifiedScript, start, pos - start);
|
||||
|
||||
// Has this identifier been defined by the application or
|
||||
// not?
|
||||
if (!definedWords.contains(word)) {
|
||||
// Exclude all the code until and including the #endif
|
||||
pos = excludeCode(modifiedScript, pos);
|
||||
// Has this identifier been defined by the application
|
||||
// or not?
|
||||
if ((isIfDef && !definedWords.contains(word)) ||
|
||||
(isIfnDef && definedWords.contains(word))) {
|
||||
// Exclude all the code until and including the
|
||||
// #endif
|
||||
pos = excludeCode(modifiedScript, pos);
|
||||
m_condtionStack.push(false);
|
||||
} else {
|
||||
m_condtionStack.push(true);
|
||||
}
|
||||
qDebug().noquote() << modifiedScript;
|
||||
}
|
||||
} else {
|
||||
// evalutate the string
|
||||
auto npos = modifiedScript.indexOf('\n', pos);
|
||||
auto codes = modifiedScript.sliced(pos, npos - pos);
|
||||
overwriteCode(modifiedScript, start, npos - start);
|
||||
|
||||
auto &sm = ScriptMachine::instance();
|
||||
bool ok = false;
|
||||
auto ret = sm.evaluateDefine(codes, ok);
|
||||
|
||||
if (ret < 0) {
|
||||
return asERROR;
|
||||
} else {
|
||||
nested++;
|
||||
if (ok) {
|
||||
m_condtionStack.push(true);
|
||||
} else {
|
||||
pos = excludeCode(modifiedScript, npos);
|
||||
m_condtionStack.push(false);
|
||||
}
|
||||
}
|
||||
|
||||
qDebug().noquote() << modifiedScript;
|
||||
}
|
||||
} else if (token == "else") {
|
||||
if (m_condtionStack.isEmpty()) {
|
||||
// TODO
|
||||
return asERROR;
|
||||
} else {
|
||||
overwriteCode(modifiedScript, start, pos - start);
|
||||
auto opBool = m_condtionStack.top();
|
||||
if (opBool) {
|
||||
if (opBool.value()) {
|
||||
pos = excludeCode(modifiedScript, pos);
|
||||
m_condtionStack.top().reset();
|
||||
}
|
||||
} else {
|
||||
// TODO
|
||||
return asERROR;
|
||||
}
|
||||
}
|
||||
qDebug().noquote() << modifiedScript;
|
||||
} else if (token == "endif") {
|
||||
// Only remove the #endif if there was a matching #if
|
||||
if (nested > 0) {
|
||||
if (m_condtionStack.isEmpty()) {
|
||||
// TODO
|
||||
return asERROR;
|
||||
} else {
|
||||
overwriteCode(modifiedScript, start, pos - start);
|
||||
nested--;
|
||||
m_condtionStack.pop();
|
||||
}
|
||||
qDebug().noquote() << modifiedScript;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug().noquote() << modifiedScript;
|
||||
|
||||
// Then check for pre-processor directives
|
||||
pos = 0;
|
||||
while (pos >= 0 && pos < modifiedScript.size()) {
|
||||
|
@ -178,7 +241,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
|
|||
pos += len;
|
||||
continue;
|
||||
}
|
||||
QString token = modifiedScript.mid(pos, len);
|
||||
QString token = modifiedScript.sliced(pos, len);
|
||||
|
||||
// Skip possible decorators before class and interface declarations
|
||||
if (token == "shared" || token == "abstract" || token == "mixin" ||
|
||||
|
@ -194,7 +257,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
|
|||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (t == asTC_IDENTIFIER) {
|
||||
token = modifiedScript.mid(pos, len);
|
||||
token = modifiedScript.sliced(pos, len);
|
||||
if (token == "include") {
|
||||
pos += len;
|
||||
t = engine->ParseToken(modifiedScript.data() + pos,
|
||||
|
@ -211,7 +274,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
|
|||
modifiedScript[pos] == '\'')) {
|
||||
// Get the include file
|
||||
QString includefile =
|
||||
modifiedScript.mid(pos + 1, len - 2);
|
||||
modifiedScript.sliced(pos + 1, len - 2);
|
||||
pos += len;
|
||||
|
||||
// Make sure the includeFile doesn't contain any
|
||||
|
@ -255,7 +318,8 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
|
|||
|
||||
if (found) {
|
||||
QString includefile =
|
||||
modifiedScript.mid(pos, rpos - pos).trimmed();
|
||||
modifiedScript.sliced(pos, rpos - pos)
|
||||
.trimmed();
|
||||
|
||||
pos = rpos + 1;
|
||||
|
||||
|
@ -303,7 +367,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
|
|||
|
||||
// Call the pragma callback
|
||||
auto pragmaText =
|
||||
modifiedScript.mid(start + 7, pos - start - 7);
|
||||
modifiedScript.sliced(start + 7, pos - start - 7);
|
||||
|
||||
// Overwrite the pragma directive with space characters
|
||||
// to avoid compiler error
|
||||
|
@ -449,27 +513,32 @@ int AsPreprocesser::skipStatement(const QByteArray &modifiedScript, int pos) {
|
|||
|
||||
int AsPreprocesser::excludeCode(QByteArray &modifiedScript, int pos) {
|
||||
asUINT len = 0;
|
||||
int nested = 0;
|
||||
int nested = 1;
|
||||
while (pos < (int)modifiedScript.size()) {
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
if (modifiedScript[pos] == '#') {
|
||||
modifiedScript[pos] = ' ';
|
||||
auto sharpPos = pos;
|
||||
pos++;
|
||||
|
||||
// Is it an #if or #endif directive?
|
||||
engine->ParseToken(modifiedScript.data() + pos,
|
||||
modifiedScript.size() - pos, &len);
|
||||
QString token = modifiedScript.mid(pos, len);
|
||||
overwriteCode(modifiedScript, pos, len);
|
||||
QString token = modifiedScript.sliced(pos, len);
|
||||
|
||||
if (token == "if") {
|
||||
if (token == "if" || token == "ifdef" || token == "ifndef") {
|
||||
modifiedScript[sharpPos] = ' ';
|
||||
overwriteCode(modifiedScript, pos, len);
|
||||
nested++;
|
||||
} else if (token == "endif") {
|
||||
} else if (token == "endif" || token == "else") {
|
||||
if (nested-- == 0) {
|
||||
pos += len;
|
||||
pos = sharpPos - 1;
|
||||
break;
|
||||
}
|
||||
modifiedScript[sharpPos] = ' ';
|
||||
overwriteCode(modifiedScript, pos, len);
|
||||
} else {
|
||||
modifiedScript[sharpPos] = ' ';
|
||||
overwriteCode(modifiedScript, pos, len);
|
||||
}
|
||||
} else if (modifiedScript[pos] != '\n') {
|
||||
overwriteCode(modifiedScript, pos, len);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#pragma warning(disable : 4786)
|
||||
#endif
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QVector>
|
||||
|
@ -62,6 +63,16 @@ typedef int (*PRAGMACALLBACK_t)(const QByteArray &pragmaText,
|
|||
// Helper class for loading and pre-processing script files to
|
||||
// support include directives declarations
|
||||
|
||||
/** for macros, we support:
|
||||
* * #if <conditions>
|
||||
* * #else
|
||||
* * #endif
|
||||
* * #define <word>
|
||||
* * #define <word> <string|int64|double>
|
||||
* * #undef <word>
|
||||
* * #ifdef <word>
|
||||
* * #ifundef <word>
|
||||
*/
|
||||
class AsPreprocesser {
|
||||
public:
|
||||
explicit AsPreprocesser(asIScriptEngine *engine);
|
||||
|
@ -73,6 +84,9 @@ public:
|
|||
QByteArray script;
|
||||
};
|
||||
|
||||
using DefineValueType =
|
||||
std::variant<std::monostate, QString, qint64, double>;
|
||||
|
||||
public:
|
||||
// Load a script section from a file on disk
|
||||
// Returns 1 if the file was included
|
||||
|
@ -93,7 +107,7 @@ public:
|
|||
void setPragmaCallback(PRAGMACALLBACK_t callback, void *userParam);
|
||||
|
||||
// Add a pre-processor define for conditional compilation
|
||||
void defineWord(const QString &word);
|
||||
void defineWord(const QString &word, const DefineValueType &value = {});
|
||||
|
||||
// Enumerate included script sections
|
||||
unsigned int sectionCount() const;
|
||||
|
@ -124,7 +138,8 @@ protected:
|
|||
|
||||
QStringList includedScripts;
|
||||
|
||||
QStringList definedWords;
|
||||
QEventLoop waitLoop;
|
||||
QHash<QString, DefineValueType> definedWords;
|
||||
};
|
||||
|
||||
#endif // ASPREPROCESSER_H
|
||||
|
|
|
@ -43,7 +43,75 @@
|
|||
#include <QProcess>
|
||||
#include <QScopeGuard>
|
||||
|
||||
ScriptMachine::~ScriptMachine() { destoryMachine(); }
|
||||
class StringFormatter {
|
||||
public:
|
||||
static QString format(const QString &input, uint indentSize = 4) {
|
||||
QString output;
|
||||
int level = 0;
|
||||
bool inString = false;
|
||||
QChar stringDelim;
|
||||
bool escape = false;
|
||||
|
||||
for (int i = 0; i < input.size(); ++i) {
|
||||
QChar c = input[i];
|
||||
|
||||
if (inString) {
|
||||
output += c;
|
||||
if (escape) {
|
||||
escape = false;
|
||||
} else if (c == '\\') {
|
||||
escape = true;
|
||||
} else if (c == stringDelim) {
|
||||
inString = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isQuote(c)) {
|
||||
inString = true;
|
||||
stringDelim = c;
|
||||
output += c;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (c.unicode()) {
|
||||
case '{':
|
||||
output += QStringLiteral("{\n");
|
||||
++level;
|
||||
output += QString(level * indentSize, ' ');
|
||||
break;
|
||||
|
||||
case '}':
|
||||
output += QStringLiteral("\n");
|
||||
--level;
|
||||
output +=
|
||||
QString(level * indentSize, ' ') + QStringLiteral("}");
|
||||
break;
|
||||
|
||||
case ',':
|
||||
output +=
|
||||
QStringLiteral(",\n") + QString(level * indentSize, ' ');
|
||||
break;
|
||||
|
||||
default:
|
||||
if (c.isSpace()) {
|
||||
// collapse multiple spaces outside strings
|
||||
if (!output.isEmpty() && !output.endsWith(' ')) {
|
||||
output += ' ';
|
||||
}
|
||||
} else {
|
||||
output += c;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool isQuote(QChar c) { return c == '"' || c == '\''; }
|
||||
};
|
||||
|
||||
bool ScriptMachine::init() {
|
||||
if (isInited()) {
|
||||
|
@ -77,6 +145,8 @@ bool ScriptMachine::configureEngine() {
|
|||
return false;
|
||||
}
|
||||
|
||||
_engine->SetDefaultAccessMask(0x1);
|
||||
|
||||
// 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);
|
||||
|
@ -155,6 +225,22 @@ bool ScriptMachine::configureEngine() {
|
|||
return false;
|
||||
}
|
||||
|
||||
r = _engine->RegisterGlobalFunction("string stringify(? &in obj)",
|
||||
asMETHOD(ScriptMachine, stringify),
|
||||
asCALL_THISCALL_ASGLOBAL, this);
|
||||
Q_ASSERT(r >= 0);
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r = _engine->RegisterGlobalFunction(
|
||||
"string beautify(const string &in str, uint indent = 4)",
|
||||
asFUNCTION(beautify), asCALL_CDECL);
|
||||
Q_ASSERT(r >= 0);
|
||||
if (r < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
r = _engine->RegisterGlobalFunction(
|
||||
"int exec(string &out output, const string &in exe, "
|
||||
"const string &in params = \"\", int timeout = 3000)",
|
||||
|
@ -198,7 +284,8 @@ bool ScriptMachine::configureEngine() {
|
|||
PluginSystem::instance().angelApi()->installAPI(this);
|
||||
|
||||
// create module for Console
|
||||
_engine->GetModule("WINGCONSOLE", asGM_ALWAYS_CREATE);
|
||||
auto mod = _engine->GetModule("WINGCONSOLE", asGM_ALWAYS_CREATE);
|
||||
mod->SetAccessMask(0x1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -317,8 +404,21 @@ int ScriptMachine::execSystemCmd(QString &out, const QString &exe,
|
|||
}
|
||||
}
|
||||
|
||||
QString ScriptMachine::beautify(const QString &str, uint indent) {
|
||||
return StringFormatter::format(str, indent);
|
||||
}
|
||||
|
||||
QString ScriptMachine::stringify(void *ref, int typeId) {
|
||||
return _debugger->toString(ref, typeId, _engine);
|
||||
}
|
||||
|
||||
bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
|
||||
bool isInDebug) {
|
||||
bool isInDebug, int *retCode) {
|
||||
Q_ASSERT(mode != Interactive && mode != DefineEvaluator);
|
||||
if (script.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compile the script
|
||||
auto mod = createModule(mode);
|
||||
// script-running is not allowed in interactive mode
|
||||
|
@ -326,13 +426,11 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
|
|||
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();
|
||||
}
|
||||
QScopeGuard guard([mod]() {
|
||||
// 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;
|
||||
|
@ -353,12 +451,13 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
|
|||
builder.setPragmaCallback(&ScriptMachine::pragmaCallback, this);
|
||||
builder.setIncludeCallback(&ScriptMachine::includeCallback, this);
|
||||
|
||||
_curMode = mode;
|
||||
auto r = builder.loadSectionFromFile(script.toUtf8());
|
||||
if (r < 0) {
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
_curMode = mode;
|
||||
r = builder.build(mod);
|
||||
if (r < 0) {
|
||||
MessageInfo info;
|
||||
|
@ -414,6 +513,9 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
|
|||
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
|
||||
_ctx[mode] = ctx;
|
||||
|
||||
ctx->SetUserData(reinterpret_cast<void *>(
|
||||
AppManager::instance()->currentMSecsSinceEpoch()),
|
||||
AsUserDataType::UserData_Timer);
|
||||
ctx->SetUserData(reinterpret_cast<void *>(isDbg),
|
||||
AsUserDataType::UserData_isDbg);
|
||||
|
||||
|
@ -492,9 +594,79 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
|
|||
_debugger->clearBreakPoint();
|
||||
emit onDebugFinished();
|
||||
}
|
||||
|
||||
if (retCode) {
|
||||
*retCode = r;
|
||||
}
|
||||
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
int ScriptMachine::evaluateDefine(const QString &code, bool &result) {
|
||||
auto mod = createModuleIfNotExist(DefineEvaluator);
|
||||
if (mod) {
|
||||
asIScriptFunction *func = nullptr;
|
||||
|
||||
auto ccode = code;
|
||||
ccode.prepend("bool f(){ return (").append(");}");
|
||||
// start to compile
|
||||
_curMode = DefineEvaluator;
|
||||
auto cr = mod->CompileFunction(nullptr, ccode.toUtf8(), 0, 0, &func);
|
||||
if (cr < 0) {
|
||||
return cr;
|
||||
}
|
||||
|
||||
// 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[DefineEvaluator] = ctx;
|
||||
|
||||
ctx->SetUserData(reinterpret_cast<void *>(asPWORD(
|
||||
AppManager::instance()->currentMSecsSinceEpoch())),
|
||||
AsUserDataType::UserData_Timer);
|
||||
|
||||
asPWORD isDbg = 0;
|
||||
ctx->SetUserData(reinterpret_cast<void *>(isDbg),
|
||||
AsUserDataType::UserData_isDbg);
|
||||
mod->SetUserData(reinterpret_cast<void *>(isDbg),
|
||||
AsUserDataType::UserData_isDbg);
|
||||
|
||||
asPWORD umode = asPWORD(DefineEvaluator);
|
||||
ctx->SetUserData(reinterpret_cast<void *>(umode),
|
||||
AsUserDataType::UserData_ContextMode);
|
||||
|
||||
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()) {
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
_ctx[DefineEvaluator] = nullptr;
|
||||
|
||||
// Check if the main script finished normally
|
||||
int r = ctx->GetState();
|
||||
if (r != asEXECUTION_FINISHED) {
|
||||
r = -1;
|
||||
} else {
|
||||
result = bool(ctx->GetReturnByte());
|
||||
r = 0;
|
||||
}
|
||||
|
||||
func->Release();
|
||||
|
||||
// Return the context after retrieving the return value
|
||||
_ctxMgr->DoneWithContext(ctx);
|
||||
_engine->GarbageCollect();
|
||||
return r;
|
||||
}
|
||||
return asERROR;
|
||||
}
|
||||
|
||||
void ScriptMachine::abortDbgScript() {
|
||||
if (_debugger->getEngine()) {
|
||||
_debugger->runDebugAction(asDebugger::ABORT);
|
||||
|
@ -573,29 +745,51 @@ asIScriptModule *ScriptMachine::createModule(ConsoleMode mode) {
|
|||
if (isModuleExists(mode)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
asIScriptModule *mod = nullptr;
|
||||
|
||||
switch (mode) {
|
||||
case Interactive:
|
||||
return nullptr;
|
||||
mod = nullptr;
|
||||
case Scripting:
|
||||
return _engine->GetModule("WINGSCRIPT", asGM_ALWAYS_CREATE);
|
||||
mod = _engine->GetModule("WINGSCRIPT", asGM_ALWAYS_CREATE);
|
||||
mod->SetAccessMask(0x1);
|
||||
break;
|
||||
case Background:
|
||||
return _engine->GetModule("WINGSRV", asGM_ALWAYS_CREATE);
|
||||
mod = _engine->GetModule("WINGSRV", asGM_ALWAYS_CREATE);
|
||||
mod->SetAccessMask(0x1);
|
||||
break;
|
||||
case DefineEvaluator:
|
||||
mod = _engine->GetModule("WINGDEF", asGM_ALWAYS_CREATE);
|
||||
mod->SetAccessMask(0x2);
|
||||
break;
|
||||
}
|
||||
// should not go there
|
||||
return nullptr;
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
asIScriptModule *ScriptMachine::createModuleIfNotExist(ConsoleMode mode) {
|
||||
asIScriptModule *mod = nullptr;
|
||||
switch (mode) {
|
||||
case Interactive:
|
||||
return _engine->GetModule("WINGCONSOLE", asGM_ONLY_IF_EXISTS);
|
||||
mod = _engine->GetModule("WINGCONSOLE", asGM_ONLY_IF_EXISTS);
|
||||
mod->SetAccessMask(0x1);
|
||||
break;
|
||||
case Scripting:
|
||||
return _engine->GetModule("WINGSCRIPT", asGM_CREATE_IF_NOT_EXISTS);
|
||||
mod = _engine->GetModule("WINGSCRIPT", asGM_CREATE_IF_NOT_EXISTS);
|
||||
mod->SetAccessMask(0x1);
|
||||
break;
|
||||
case Background:
|
||||
return _engine->GetModule("WINGSRV", asGM_CREATE_IF_NOT_EXISTS);
|
||||
mod = _engine->GetModule("WINGSRV", asGM_CREATE_IF_NOT_EXISTS);
|
||||
mod->SetAccessMask(0x1);
|
||||
break;
|
||||
case DefineEvaluator:
|
||||
mod = _engine->GetModule("WINGDEF", asGM_ALWAYS_CREATE);
|
||||
mod->SetAccessMask(0x2);
|
||||
break;
|
||||
}
|
||||
// should not go there
|
||||
return nullptr;
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
asIScriptModule *ScriptMachine::module(ConsoleMode mode) {
|
||||
|
@ -606,6 +800,8 @@ asIScriptModule *ScriptMachine::module(ConsoleMode mode) {
|
|||
return _engine->GetModule("WINGSCRIPT", asGM_ONLY_IF_EXISTS);
|
||||
case Background:
|
||||
return _engine->GetModule("WINGSRV", asGM_ONLY_IF_EXISTS);
|
||||
case DefineEvaluator:
|
||||
return _engine->GetModule("WINGDEF", asGM_ONLY_IF_EXISTS);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1832,6 +2028,10 @@ asIScriptEngine *ScriptMachine::engine() const { return _engine; }
|
|||
asDebugger *ScriptMachine::debugger() const { return _debugger; }
|
||||
|
||||
bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
|
||||
if (code.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
asIScriptModule *mod = createModuleIfNotExist(mode);
|
||||
_engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, false);
|
||||
|
||||
|
@ -1841,26 +2041,30 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
|
|||
|
||||
asIScriptFunction *func = nullptr;
|
||||
|
||||
auto ret = parser.parse(ccode);
|
||||
QList<QAsCodeParser::CodeSegment> ret;
|
||||
if (mode != DefineEvaluator) {
|
||||
ret = parser.parse(ccode);
|
||||
}
|
||||
|
||||
// check whether there is any enum/class
|
||||
if (std::find_if(ret.begin(), ret.end(),
|
||||
[](const QAsCodeParser::CodeSegment &seg) {
|
||||
switch (seg.type) {
|
||||
case QAsCodeParser::SymbolType::Enum:
|
||||
case QAsCodeParser::SymbolType::Class:
|
||||
case QAsCodeParser::SymbolType::Function:
|
||||
case QAsCodeParser::SymbolType::Interface:
|
||||
case QAsCodeParser::SymbolType::Import:
|
||||
case QAsCodeParser::SymbolType::Variable:
|
||||
return false;
|
||||
case QAsCodeParser::SymbolType::Invalid:
|
||||
case QAsCodeParser::SymbolType::TypeDef:
|
||||
case QAsCodeParser::SymbolType::FnDef:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}) != ret.end()) {
|
||||
if (ret.isEmpty() ||
|
||||
std::any_of(ret.begin(), ret.end(),
|
||||
[](const QAsCodeParser::CodeSegment &seg) {
|
||||
switch (seg.type) {
|
||||
case QAsCodeParser::SymbolType::Enum:
|
||||
case QAsCodeParser::SymbolType::Class:
|
||||
case QAsCodeParser::SymbolType::Function:
|
||||
case QAsCodeParser::SymbolType::Interface:
|
||||
case QAsCodeParser::SymbolType::Import:
|
||||
case QAsCodeParser::SymbolType::Variable:
|
||||
return false;
|
||||
case QAsCodeParser::SymbolType::Invalid:
|
||||
case QAsCodeParser::SymbolType::TypeDef:
|
||||
case QAsCodeParser::SymbolType::FnDef:
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
})) {
|
||||
// ok, wrap the codes
|
||||
ccode.prepend("void f(){").append("}");
|
||||
// start to compile
|
||||
|
@ -1881,6 +2085,10 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
|
|||
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
|
||||
_ctx[mode] = ctx;
|
||||
|
||||
ctx->SetUserData(reinterpret_cast<void *>(asPWORD(
|
||||
AppManager::instance()->currentMSecsSinceEpoch())),
|
||||
AsUserDataType::UserData_Timer);
|
||||
|
||||
asPWORD isDbg = 0;
|
||||
ctx->SetUserData(reinterpret_cast<void *>(isDbg),
|
||||
AsUserDataType::UserData_isDbg);
|
||||
|
|
|
@ -36,9 +36,10 @@ private:
|
|||
public:
|
||||
// we have three console modes
|
||||
enum ConsoleMode {
|
||||
Interactive, // in a shell
|
||||
Scripting, // in scripting dialog
|
||||
Background // run codes from other way
|
||||
Interactive, // in a shell
|
||||
Scripting, // in scripting dialog
|
||||
Background, // run codes from other way
|
||||
DefineEvaluator // define result calculator
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -108,8 +109,7 @@ public:
|
|||
asIScriptModule *module(ConsoleMode mode);
|
||||
|
||||
static ScriptMachine &instance();
|
||||
|
||||
virtual ~ScriptMachine();
|
||||
void destoryMachine();
|
||||
|
||||
public:
|
||||
bool init();
|
||||
|
@ -126,6 +126,8 @@ public:
|
|||
|
||||
asIScriptEngine *engine() const;
|
||||
|
||||
void outputMessage(const MessageInfo &info);
|
||||
|
||||
public:
|
||||
static void scriptAssert(bool b);
|
||||
static void scriptAssert_X(bool b, const QString &msg);
|
||||
|
@ -144,7 +146,9 @@ public slots:
|
|||
bool executeCode(ConsoleMode mode, const QString &code);
|
||||
// only scripting mode can be debugged
|
||||
bool executeScript(ConsoleMode mode, const QString &script,
|
||||
bool isInDebug = false);
|
||||
bool isInDebug = false, int *retCode = nullptr);
|
||||
|
||||
int evaluateDefine(const QString &code, bool &result);
|
||||
|
||||
void abortDbgScript();
|
||||
void abortScript(ConsoleMode mode);
|
||||
|
@ -155,19 +159,19 @@ protected:
|
|||
|
||||
QString getCallStack(asIScriptContext *context);
|
||||
|
||||
void destoryMachine();
|
||||
|
||||
private:
|
||||
void print(void *ref, int typeId);
|
||||
QString getInput();
|
||||
|
||||
void outputMessage(const MessageInfo &info);
|
||||
|
||||
bool isType(asITypeInfo *tinfo, RegisteredType type);
|
||||
|
||||
static int execSystemCmd(QString &out, const QString &exe,
|
||||
const QString ¶ms, int timeout);
|
||||
|
||||
static QString beautify(const QString &str, uint indent);
|
||||
|
||||
QString stringify(void *ref, int typeId);
|
||||
|
||||
private:
|
||||
static void messageCallback(const asSMessageInfo *msg, void *param);
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ void GotoWidget::handleLineChanged() {
|
|||
ui->lineEdit->setStyleSheet(QString());
|
||||
emit jumpToLine(p, isline);
|
||||
} else {
|
||||
ui->lineEdit->setStyleSheet(QStringLiteral("color: red;"));
|
||||
ui->lineEdit->setStyleSheet(QStringLiteral("QLineEdit{color: red}"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -439,6 +439,12 @@ void ScriptingConsole::paste() {
|
|||
}
|
||||
}
|
||||
|
||||
bool ScriptingConsole::isTerminal() const { return _isTerminal; }
|
||||
|
||||
void ScriptingConsole::setIsTerminal(bool newIsTerminal) {
|
||||
_isTerminal = newIsTerminal;
|
||||
}
|
||||
|
||||
QString ScriptingConsole::currentCodes() const {
|
||||
QTextCursor textCursor = this->textCursor();
|
||||
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
|
||||
|
@ -457,15 +463,18 @@ void ScriptingConsole::contextMenuEvent(QContextMenuEvent *event) {
|
|||
menu.addAction(QIcon(QStringLiteral(":/qeditor/paste.png")), tr("Paste"),
|
||||
QKeySequence(QKeySequence::Paste), this,
|
||||
&ScriptingConsole::paste);
|
||||
menu.addAction(ICONRES(QStringLiteral("del")), tr("Clear"),
|
||||
QKeySequence(Qt::ControlModifier | Qt::Key_L), this,
|
||||
&ScriptingConsole::clearConsole);
|
||||
menu.addSeparator();
|
||||
menu.addAction(ICONRES(QStringLiteral("dbgstop")), tr("AbortScript"),
|
||||
QKeySequence(Qt::ControlModifier | Qt::Key_Q), []() {
|
||||
ScriptMachine::instance().abortScript(
|
||||
ScriptMachine::Background);
|
||||
});
|
||||
|
||||
if (_isTerminal) {
|
||||
menu.addAction(ICONRES(QStringLiteral("del")), tr("Clear"),
|
||||
QKeySequence(Qt::ControlModifier | Qt::Key_L), this,
|
||||
&ScriptingConsole::clearConsole);
|
||||
menu.addSeparator();
|
||||
menu.addAction(ICONRES(QStringLiteral("dbgstop")), tr("AbortScript"),
|
||||
QKeySequence(Qt::ControlModifier | Qt::Key_Q), []() {
|
||||
ScriptMachine::instance().abortScript(
|
||||
ScriptMachine::Background);
|
||||
});
|
||||
}
|
||||
|
||||
menu.exec(event->globalPos());
|
||||
}
|
||||
|
|
|
@ -40,6 +40,10 @@ signals:
|
|||
public:
|
||||
QString getInput();
|
||||
|
||||
bool isTerminal() const;
|
||||
|
||||
void setIsTerminal(bool newIsTerminal);
|
||||
|
||||
public slots:
|
||||
void init();
|
||||
|
||||
|
@ -71,6 +75,7 @@ protected slots:
|
|||
private:
|
||||
QString _codes;
|
||||
|
||||
bool _isTerminal = true;
|
||||
bool _isWaitingRead = false;
|
||||
std::function<QString(void)> _getInputFn;
|
||||
};
|
||||
|
|
|
@ -19,18 +19,47 @@ ScriptingConsoleBase::ScriptingConsoleBase(QWidget *parent)
|
|||
}
|
||||
|
||||
void ScriptingConsoleBase::stdOut(const QString &str) {
|
||||
writeStdOut(str);
|
||||
dontHighlightLastLine(true);
|
||||
auto lines = str.split('\n');
|
||||
if (lines.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
writeStdOut(lines.takeFirst());
|
||||
dontHighlightLastLine(false);
|
||||
for (auto &l : lines) {
|
||||
newLine();
|
||||
writeStdOut(l);
|
||||
dontHighlightLastLine(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingConsoleBase::stdErr(const QString &str) {
|
||||
writeStdErr(str);
|
||||
auto lines = str.split('\n');
|
||||
if (lines.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
writeStdErr(lines.takeFirst());
|
||||
dontHighlightLastLine(false);
|
||||
for (auto &l : lines) {
|
||||
newLine();
|
||||
writeStdErr(l);
|
||||
dontHighlightLastLine(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingConsoleBase::stdWarn(const QString &str) {
|
||||
write(str, _warnCharFmt);
|
||||
auto lines = str.split('\n');
|
||||
if (lines.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
write(lines.takeFirst(), _warnCharFmt);
|
||||
dontHighlightLastLine(false);
|
||||
for (auto &l : lines) {
|
||||
newLine();
|
||||
write(l, _warnCharFmt);
|
||||
dontHighlightLastLine(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingConsoleBase::newLine() { _s << Qt::endl; }
|
||||
|
|
|
@ -16,6 +16,8 @@ enum AsUserDataType {
|
|||
UserData_PluginFn,
|
||||
UserData_isDbg,
|
||||
UserData_ContextMode,
|
||||
UserData_Timer,
|
||||
UserData_TimeOut
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -607,6 +607,22 @@ ads::CDockAreaWidget *MainWindow::buildUpLogDock(ads::CDockManager *dock,
|
|||
m_logbrowser->setOpenExternalLinks(true);
|
||||
m_logbrowser->setUndoRedoEnabled(false);
|
||||
|
||||
m_logbrowser->addAction(newAction(
|
||||
ICONRES("copy"), tr("Copy"), [=]() { m_logbrowser->copy(); },
|
||||
QKeySequence::Copy));
|
||||
|
||||
auto a = new QAction(this);
|
||||
a->setSeparator(true);
|
||||
m_logbrowser->addAction(a);
|
||||
|
||||
m_logbrowser->addAction(newAction(ICONRES(QStringLiteral("log")),
|
||||
tr("ExportLog"),
|
||||
&MainWindow::on_exportlog));
|
||||
m_logbrowser->addAction(newAction(ICONRES(QStringLiteral("clearhis")),
|
||||
tr("ClearLog"), &MainWindow::on_clslog));
|
||||
|
||||
m_logbrowser->setContextMenuPolicy(Qt::ActionsContextMenu);
|
||||
|
||||
auto dw =
|
||||
buildDockWidget(dock, QStringLiteral("Log"), tr("Log"), m_logbrowser);
|
||||
return dock->addDockWidget(area, dw, areaw);
|
||||
|
@ -803,9 +819,7 @@ MainWindow::buildUpHashResultDock(ads::CDockManager *dock,
|
|||
m_hashtable->setContextMenuPolicy(
|
||||
Qt::ContextMenuPolicy::ActionsContextMenu);
|
||||
|
||||
auto a = new QAction(m_hashtable);
|
||||
a->setText(tr("Copy"));
|
||||
connect(a, &QAction::triggered, this, [=] {
|
||||
auto a = newAction(ICONRES(QStringLiteral("copy")), tr("Copy"), [=] {
|
||||
auto r = m_hashtable->currentIndex();
|
||||
qApp->clipboard()->setText(
|
||||
_hashModel->checkSumData(QCryptographicHash::Algorithm(r.row())));
|
||||
|
@ -813,6 +827,9 @@ MainWindow::buildUpHashResultDock(ads::CDockManager *dock,
|
|||
tr("CopyToClipBoard"));
|
||||
});
|
||||
m_hashtable->addAction(a);
|
||||
a = newAction(QStringLiteral("del"), tr("Clear"),
|
||||
[=]() { _hashModel->clearData(); });
|
||||
m_hashtable->addAction(a);
|
||||
connect(m_hashtable->selectionModel(),
|
||||
&QItemSelectionModel::currentRowChanged, a,
|
||||
[=](const QModelIndex ¤t, const QModelIndex &) {
|
||||
|
|
|
@ -360,7 +360,7 @@ private:
|
|||
template <typename Func>
|
||||
inline QAction *newAction(const QString &title, Func &&slot,
|
||||
const QKeySequence &shortcut = QKeySequence()) {
|
||||
auto a = new QAction;
|
||||
auto a = new QAction(this);
|
||||
a->setText(title);
|
||||
a->setShortcutVisibleInContextMenu(true);
|
||||
a->setShortcut(shortcut);
|
||||
|
|
|
@ -583,6 +583,7 @@ ScriptingDialog::buildUpOutputShowDock(ads::CDockManager *dock,
|
|||
ads::CDockAreaWidget *areaw) {
|
||||
m_consoleout = new ScriptingConsole(this);
|
||||
m_consoleout->setMode(ScriptingConsole::Output);
|
||||
m_consoleout->setIsTerminal(false);
|
||||
auto dw = buildDockWidget(dock, QStringLiteral("ConsoleOutput"),
|
||||
tr("ConsoleOutput"), m_consoleout);
|
||||
return dock->addDockWidget(area, dw, areaw);
|
||||
|
|
|
@ -170,7 +170,7 @@ private:
|
|||
template <typename Func>
|
||||
inline QAction *newAction(const QString &title, Func &&slot,
|
||||
const QKeySequence &shortcut = QKeySequence()) {
|
||||
auto a = new QAction;
|
||||
auto a = new QAction(this);
|
||||
a->setText(title);
|
||||
a->setShortcutVisibleInContextMenu(true);
|
||||
a->setShortcut(shortcut);
|
||||
|
|
Loading…
Reference in New Issue