feat: 一些 Bug 修复和脚本处理相关

This commit is contained in:
寂静的羽夏 2025-04-30 17:25:39 +08:00
parent d8069aedde
commit c01ca038a3
22 changed files with 1862 additions and 1460 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -25,43 +25,49 @@
AngelObjString::AngelObjString() {} AngelObjString::AngelObjString() {}
QString AngelObjString::stringToString(void *obj, asDebugger *dbg) { QString AngelObjString::stringToString(void *obj, asDebugger *dbg, asUINT tag) {
Q_UNUSED(dbg); Q_UNUSED(dbg);
// We know the received object is a string // We know the received object is a string
QString val = *reinterpret_cast<QString *>(obj); QString val = *reinterpret_cast<QString *>(obj);
if (tag == 1) {
val.prepend('"').append('"');
}
return val; return val;
} }
QString AngelObjString::arrayToString(void *obj, asDebugger *dbg) { QString AngelObjString::arrayToString(void *obj, asDebugger *dbg, asUINT tag) {
CScriptArray *arr = reinterpret_cast<CScriptArray *>(obj); CScriptArray *arr = reinterpret_cast<CScriptArray *>(obj);
QString str; QString str;
QTextStream s(&str); QTextStream s(&str);
s << tr("(len=") << arr->GetSize() << QStringLiteral(")"); s << QStringLiteral("{");
s << QStringLiteral(" [");
for (asUINT n = 0; n < arr->GetSize(); n++) { for (asUINT n = 0; n < arr->GetSize(); n++) {
s << dbg->toString(arr->At(n), arr->GetElementTypeId(), s << dbg->toString(arr->At(n), arr->GetElementTypeId(),
arr->GetArrayObjectType()->GetEngine()); arr->GetArrayObjectType()->GetEngine(), 1);
if (n < arr->GetSize() - 1) if (n < arr->GetSize() - 1)
s << ", "; s << ", ";
} }
s << QStringLiteral("]"); s << QStringLiteral("}");
return str; return str;
} }
QString AngelObjString::charToString(void *obj, asDebugger *dbg) { QString AngelObjString::charToString(void *obj, asDebugger *dbg, asUINT tag) {
Q_UNUSED(dbg); Q_UNUSED(dbg);
// We know the received object is a char // We know the received object is a char
QChar *val = reinterpret_cast<QChar *>(obj); 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); CScriptDictionary *dic = reinterpret_cast<CScriptDictionary *>(obj);
QString str; QString str;
@ -69,11 +75,11 @@ QString AngelObjString::dictionaryToString(void *obj, asDebugger *dbg) {
auto engine = dic->GetEngine(); auto engine = dic->GetEngine();
s << " {"; s << QStringLiteral("{");
asUINT n = 0; asUINT n = 0;
for (CScriptDictionary::CIterator it = dic->begin(); it != dic->end(); for (CScriptDictionary::CIterator it = dic->begin(); it != dic->end();
it++, n++) { it++, n++) {
s << "[" << it.GetKey() << "] = "; s << QStringLiteral("[") << it.GetKey() << QStringLiteral("] = ");
// Get the type and address of the value // Get the type and address of the value
const void *val = it.GetAddressOfValue(); 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 // active, the debugger will use the engine held inside it by
// default, but in an environment where there multiple engines this // default, but in an environment where there multiple engines this
// might not be the correct instance). // 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) if (n < dic->GetSize() - 1)
s << ", "; s << QStringLiteral(", ");
} }
s << "}"; s << QStringLiteral("}");
return str; return str;
} }
QString AngelObjString::colorToString(void *obj, asDebugger *dbg) { QString AngelObjString::colorToString(void *obj, asDebugger *dbg, asUINT tag) {
Q_UNUSED(dbg); Q_UNUSED(dbg);
auto color = reinterpret_cast<QColor *>(obj); auto color = reinterpret_cast<QColor *>(obj);

View File

@ -28,16 +28,15 @@ class AngelObjString : public QObject {
Q_OBJECT Q_OBJECT
public: public:
// for debugger use static QString stringToString(void *obj, asDebugger *dbg, asUINT tag);
static QString stringToString(void *obj, asDebugger *dbg);
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: public:
// ================================================== // ==================================================

View File

@ -143,8 +143,9 @@ AppManager::AppManager(int &argc, char *argv[])
} }
AppManager::~AppManager() { AppManager::~AppManager() {
InspectQtLogHelper::instance().destory();
ClangFormatManager::instance().save(); ClangFormatManager::instance().save();
ScriptMachine::instance().deleteLater();
InspectQtLogHelper::instance().destory();
CommandHistoryManager::save(QConsoleWidget::history().strings_); CommandHistoryManager::save(QConsoleWidget::history().strings_);
delete _w; delete _w;
@ -155,7 +156,7 @@ AppManager *AppManager::instance() { return _instance; }
MainWindow *AppManager::mainWindow() const { return _w; } 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) { void AppManager::openFile(const QString &file, bool autoDetect) {
EditorView *editor = nullptr; EditorView *editor = nullptr;

View File

@ -38,7 +38,7 @@ public:
QApplication::tr("WingCloudStudio"); QApplication::tr("WingCloudStudio");
} }
uint currentMSecsSinceEpoch(); quint64 currentMSecsSinceEpoch();
public slots: public slots:
void openFile(const QString &file, bool autoDetect = true); void openFile(const QString &file, bool autoDetect = true);

View File

@ -414,6 +414,10 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
// first preprocess the code // first preprocess the code
AsPreprocesser prepc(engine); AsPreprocesser prepc(engine);
prepc.setIncludeCallback(&AsCompletion::includeCallBack, this); prepc.setIncludeCallback(&AsCompletion::includeCallBack, this);
prepc.setPragmaCallback([](const QByteArray &, AsPreprocesser *,
const QString &,
void *) -> int { return asSUCCESS; },
nullptr);
auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"), auto r = prepc.loadSectionFromMemory(QStringLiteral("ASCOMPLETION"),
code.toUtf8()); code.toUtf8());

View File

@ -16,6 +16,7 @@
*/ */
#include "asdebugger.h" #include "asdebugger.h"
#include "class/appmanager.h"
#include "define.h" #include "define.h"
#include <QApplication> #include <QApplication>
@ -78,6 +79,40 @@ void asDebugger::lineCallback(asIScriptContext *ctx) {
if (ctx == nullptr) if (ctx == nullptr)
return; 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>( auto isDbg = reinterpret_cast<asPWORD>(
ctx->GetUserData(AsUserDataType::UserData_isDbg)); ctx->GetUserData(AsUserDataType::UserData_isDbg));
if (!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()); auto dbgContext = reinterpret_cast<ContextDbgInfo *>(ctx->GetUserData());
Q_ASSERT(dbgContext); Q_ASSERT(dbgContext);
@ -368,7 +397,7 @@ bool asDebugger::checkBreakPoint(asIScriptContext *ctx) {
} }
QString asDebugger::toString(void *value, asUINT typeId, QString asDebugger::toString(void *value, asUINT typeId,
asIScriptEngine *engine) { asIScriptEngine *engine, asUINT tag) {
if (value == nullptr) if (value == nullptr)
return QStringLiteral("<null>"); return QStringLiteral("<null>");
@ -445,7 +474,8 @@ QString asDebugger::toString(void *value, asUINT typeId,
s << name /*type->GetPropertyDeclaration(n)*/ s << name /*type->GetPropertyDeclaration(n)*/
<< QStringLiteral(" = ") << QStringLiteral(" = ")
<< toString(obj->GetAddressOfProperty(n), << 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 // Invoke the callback to get the string representation of
// this type // this type
s << it.value()(value, this); s << it.value()(value, this, tag);
} else { } else {
// Unknown type: type + address // Unknown type: type + address
s << type->GetName() << '(' << value << ')'; s << type->GetName() << '(' << value << ')';

View File

@ -84,7 +84,7 @@ public:
virtual ~asDebugger(); virtual ~asDebugger();
// Register callbacks to handle to-string conversions of application types // 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, void registerToStringCallback(const asITypeInfo *ti,
ToStringCallback callback); ToStringCallback callback);
@ -108,8 +108,9 @@ public:
// Line callback invoked by context // Line callback invoked by context
void lineCallback(asIScriptContext *ctx); void lineCallback(asIScriptContext *ctx);
// tag = 1 : string should be printed with quotes
QString toString(void *value, asUINT typeId, QString toString(void *value, asUINT typeId,
asIScriptEngine *engine = nullptr); asIScriptEngine *engine = nullptr, asUINT tag = 0);
GCStatistic gcStatistics(); GCStatistic gcStatistics();

View File

@ -16,9 +16,11 @@
*/ */
#include "aspreprocesser.h" #include "aspreprocesser.h"
#include "class/scriptmachine.h"
#include <QDir> #include <QDir>
#include <QFileInfo> #include <QFileInfo>
#include <QStack>
Q_GLOBAL_STATIC_WITH_ARGS( Q_GLOBAL_STATIC_WITH_ARGS(
QStringList, DEFAULT_MARCO, QStringList, DEFAULT_MARCO,
@ -36,7 +38,9 @@ AsPreprocesser::AsPreprocesser(asIScriptEngine *engine) : engine(engine) {
pragmaCallback = nullptr; pragmaCallback = nullptr;
pragmaParam = nullptr; pragmaParam = nullptr;
definedWords = *DEFAULT_MARCO; for (auto &m : *DEFAULT_MARCO) {
definedWords.insert(m, {});
}
} }
AsPreprocesser::~AsPreprocesser() { void ClearAll(); } AsPreprocesser::~AsPreprocesser() { void ClearAll(); }
@ -85,9 +89,10 @@ void AsPreprocesser::setPragmaCallback(PRAGMACALLBACK_t callback,
pragmaParam = userParam; pragmaParam = userParam;
} }
void AsPreprocesser::defineWord(const QString &word) { void AsPreprocesser::defineWord(const QString &word,
const DefineValueType &value) {
if (!definedWords.contains(word)) { 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 // shouldn't be compiled
QByteArray::size_type pos = 0; QByteArray::size_type pos = 0;
int nested = 0; QStack<std::optional<bool>> m_condtionStack;
while (pos < modifiedScript.size()) { while (pos < modifiedScript.size()) {
asUINT len = 0; asUINT len = 0;
asETokenClass t = engine->ParseToken(modifiedScript.data() + pos, asETokenClass t = engine->ParseToken(modifiedScript.data() + pos,
@ -128,10 +134,14 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
modifiedScript.size() - pos, &len); modifiedScript.size() - pos, &len);
Q_UNUSED(t); Q_UNUSED(t);
QByteArray token = modifiedScript.mid(pos, len); QByteArray token = modifiedScript.sliced(pos, len);
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, t = engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len); modifiedScript.size() - pos, &len);
if (t == asTC_WHITESPACE) { if (t == asTC_WHITESPACE) {
@ -140,34 +150,87 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
modifiedScript.size() - pos, &len); modifiedScript.size() - pos, &len);
} }
if (t == asTC_IDENTIFIER) { if (isIfDef || isIfnDef) {
QByteArray word = modifiedScript.mid(pos, len); if (t == asTC_IDENTIFIER) {
QByteArray word = modifiedScript.sliced(pos, len);
// Overwrite the #if directive with space characters to // Overwrite the directive with space characters to
// avoid compiler error // avoid compiler error
pos += len; pos += len;
overwriteCode(modifiedScript, start, pos - start); overwriteCode(modifiedScript, start, pos - start);
// Has this identifier been defined by the application or // Has this identifier been defined by the application
// not? // or not?
if (!definedWords.contains(word)) { if ((isIfDef && !definedWords.contains(word)) ||
// Exclude all the code until and including the #endif (isIfnDef && definedWords.contains(word))) {
pos = excludeCode(modifiedScript, pos); // 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 { } 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") { } else if (token == "endif") {
// Only remove the #endif if there was a matching #if // 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); overwriteCode(modifiedScript, start, pos - start);
nested--; m_condtionStack.pop();
} }
qDebug().noquote() << modifiedScript;
} }
} else } else {
pos += len; pos += len;
}
} }
qDebug().noquote() << modifiedScript;
// Then check for pre-processor directives // Then check for pre-processor directives
pos = 0; pos = 0;
while (pos >= 0 && pos < modifiedScript.size()) { while (pos >= 0 && pos < modifiedScript.size()) {
@ -178,7 +241,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
pos += len; pos += len;
continue; continue;
} }
QString token = modifiedScript.mid(pos, len); QString token = modifiedScript.sliced(pos, len);
// Skip possible decorators before class and interface declarations // Skip possible decorators before class and interface declarations
if (token == "shared" || token == "abstract" || token == "mixin" || if (token == "shared" || token == "abstract" || token == "mixin" ||
@ -194,7 +257,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
t = engine->ParseToken(modifiedScript.data() + pos, t = engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len); modifiedScript.size() - pos, &len);
if (t == asTC_IDENTIFIER) { if (t == asTC_IDENTIFIER) {
token = modifiedScript.mid(pos, len); token = modifiedScript.sliced(pos, len);
if (token == "include") { if (token == "include") {
pos += len; pos += len;
t = engine->ParseToken(modifiedScript.data() + pos, t = engine->ParseToken(modifiedScript.data() + pos,
@ -211,7 +274,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
modifiedScript[pos] == '\'')) { modifiedScript[pos] == '\'')) {
// Get the include file // Get the include file
QString includefile = QString includefile =
modifiedScript.mid(pos + 1, len - 2); modifiedScript.sliced(pos + 1, len - 2);
pos += len; pos += len;
// Make sure the includeFile doesn't contain any // Make sure the includeFile doesn't contain any
@ -255,7 +318,8 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
if (found) { if (found) {
QString includefile = QString includefile =
modifiedScript.mid(pos, rpos - pos).trimmed(); modifiedScript.sliced(pos, rpos - pos)
.trimmed();
pos = rpos + 1; pos = rpos + 1;
@ -303,7 +367,7 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// Call the pragma callback // Call the pragma callback
auto pragmaText = auto pragmaText =
modifiedScript.mid(start + 7, pos - start - 7); modifiedScript.sliced(start + 7, pos - start - 7);
// Overwrite the pragma directive with space characters // Overwrite the pragma directive with space characters
// to avoid compiler error // to avoid compiler error
@ -449,27 +513,32 @@ int AsPreprocesser::skipStatement(const QByteArray &modifiedScript, int pos) {
int AsPreprocesser::excludeCode(QByteArray &modifiedScript, int pos) { int AsPreprocesser::excludeCode(QByteArray &modifiedScript, int pos) {
asUINT len = 0; asUINT len = 0;
int nested = 0; int nested = 1;
while (pos < (int)modifiedScript.size()) { while (pos < (int)modifiedScript.size()) {
engine->ParseToken(modifiedScript.data() + pos, engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len); modifiedScript.size() - pos, &len);
if (modifiedScript[pos] == '#') { if (modifiedScript[pos] == '#') {
modifiedScript[pos] = ' '; auto sharpPos = pos;
pos++; pos++;
// Is it an #if or #endif directive? // Is it an #if or #endif directive?
engine->ParseToken(modifiedScript.data() + pos, engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len); modifiedScript.size() - pos, &len);
QString token = modifiedScript.mid(pos, len); QString token = modifiedScript.sliced(pos, len);
overwriteCode(modifiedScript, pos, len);
if (token == "if") { if (token == "if" || token == "ifdef" || token == "ifndef") {
modifiedScript[sharpPos] = ' ';
overwriteCode(modifiedScript, pos, len);
nested++; nested++;
} else if (token == "endif") { } else if (token == "endif" || token == "else") {
if (nested-- == 0) { if (nested-- == 0) {
pos += len; pos = sharpPos - 1;
break; break;
} }
modifiedScript[sharpPos] = ' ';
overwriteCode(modifiedScript, pos, len);
} else {
modifiedScript[sharpPos] = ' ';
overwriteCode(modifiedScript, pos, len);
} }
} else if (modifiedScript[pos] != '\n') { } else if (modifiedScript[pos] != '\n') {
overwriteCode(modifiedScript, pos, len); overwriteCode(modifiedScript, pos, len);

View File

@ -35,6 +35,7 @@
#pragma warning(disable : 4786) #pragma warning(disable : 4786)
#endif #endif
#include <QEventLoop>
#include <QMap> #include <QMap>
#include <QSet> #include <QSet>
#include <QVector> #include <QVector>
@ -62,6 +63,16 @@ typedef int (*PRAGMACALLBACK_t)(const QByteArray &pragmaText,
// Helper class for loading and pre-processing script files to // Helper class for loading and pre-processing script files to
// support include directives declarations // 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 { class AsPreprocesser {
public: public:
explicit AsPreprocesser(asIScriptEngine *engine); explicit AsPreprocesser(asIScriptEngine *engine);
@ -73,6 +84,9 @@ public:
QByteArray script; QByteArray script;
}; };
using DefineValueType =
std::variant<std::monostate, QString, qint64, double>;
public: public:
// Load a script section from a file on disk // Load a script section from a file on disk
// Returns 1 if the file was included // Returns 1 if the file was included
@ -93,7 +107,7 @@ public:
void setPragmaCallback(PRAGMACALLBACK_t callback, void *userParam); void setPragmaCallback(PRAGMACALLBACK_t callback, void *userParam);
// Add a pre-processor define for conditional compilation // 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 // Enumerate included script sections
unsigned int sectionCount() const; unsigned int sectionCount() const;
@ -124,7 +138,8 @@ protected:
QStringList includedScripts; QStringList includedScripts;
QStringList definedWords; QEventLoop waitLoop;
QHash<QString, DefineValueType> definedWords;
}; };
#endif // ASPREPROCESSER_H #endif // ASPREPROCESSER_H

View File

@ -43,7 +43,75 @@
#include <QProcess> #include <QProcess>
#include <QScopeGuard> #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() { bool ScriptMachine::init() {
if (isInited()) { if (isInited()) {
@ -77,6 +145,8 @@ bool ScriptMachine::configureEngine() {
return false; return false;
} }
_engine->SetDefaultAccessMask(0x1);
// we need utf8, the default is what we want // we need utf8, the default is what we want
_engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true); _engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true);
_engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, true); _engine->SetEngineProperty(asEP_DISALLOW_EMPTY_LIST_ELEMENTS, true);
@ -155,6 +225,22 @@ bool ScriptMachine::configureEngine() {
return false; 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( r = _engine->RegisterGlobalFunction(
"int exec(string &out output, const string &in exe, " "int exec(string &out output, const string &in exe, "
"const string &in params = \"\", int timeout = 3000)", "const string &in params = \"\", int timeout = 3000)",
@ -198,7 +284,8 @@ bool ScriptMachine::configureEngine() {
PluginSystem::instance().angelApi()->installAPI(this); PluginSystem::instance().angelApi()->installAPI(this);
// create module for Console // create module for Console
_engine->GetModule("WINGCONSOLE", asGM_ALWAYS_CREATE); auto mod = _engine->GetModule("WINGCONSOLE", asGM_ALWAYS_CREATE);
mod->SetAccessMask(0x1);
return true; 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 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 // Compile the script
auto mod = createModule(mode); auto mod = createModule(mode);
// script-running is not allowed in interactive mode // script-running is not allowed in interactive mode
@ -326,13 +426,11 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
return false; return false;
} }
QScopeGuard guard([mod, mode]() { QScopeGuard guard([mod]() {
if (mode != ConsoleMode::Interactive) { // Before leaving, allow the engine to clean up remaining objects by
// Before leaving, allow the engine to clean up remaining objects by // discarding the module and doing a full garbage collection so that
// discarding the module and doing a full garbage collection so that // this can also be debugged if desired
// this can also be debugged if desired mod->Discard();
mod->Discard();
}
}); });
asPWORD isDbg = 0; asPWORD isDbg = 0;
@ -353,12 +451,13 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
builder.setPragmaCallback(&ScriptMachine::pragmaCallback, this); builder.setPragmaCallback(&ScriptMachine::pragmaCallback, this);
builder.setIncludeCallback(&ScriptMachine::includeCallback, this); builder.setIncludeCallback(&ScriptMachine::includeCallback, this);
_curMode = mode;
auto r = builder.loadSectionFromFile(script.toUtf8()); auto r = builder.loadSectionFromFile(script.toUtf8());
if (r < 0) { if (r < 0) {
// TODO
return false; return false;
} }
_curMode = mode;
r = builder.build(mod); r = builder.build(mod);
if (r < 0) { if (r < 0) {
MessageInfo info; MessageInfo info;
@ -414,6 +513,9 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true); asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
_ctx[mode] = ctx; _ctx[mode] = ctx;
ctx->SetUserData(reinterpret_cast<void *>(
AppManager::instance()->currentMSecsSinceEpoch()),
AsUserDataType::UserData_Timer);
ctx->SetUserData(reinterpret_cast<void *>(isDbg), ctx->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg); AsUserDataType::UserData_isDbg);
@ -492,9 +594,79 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
_debugger->clearBreakPoint(); _debugger->clearBreakPoint();
emit onDebugFinished(); emit onDebugFinished();
} }
if (retCode) {
*retCode = r;
}
return r >= 0; 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() { void ScriptMachine::abortDbgScript() {
if (_debugger->getEngine()) { if (_debugger->getEngine()) {
_debugger->runDebugAction(asDebugger::ABORT); _debugger->runDebugAction(asDebugger::ABORT);
@ -573,29 +745,51 @@ asIScriptModule *ScriptMachine::createModule(ConsoleMode mode) {
if (isModuleExists(mode)) { if (isModuleExists(mode)) {
return nullptr; return nullptr;
} }
asIScriptModule *mod = nullptr;
switch (mode) { switch (mode) {
case Interactive: case Interactive:
return nullptr; mod = nullptr;
case Scripting: case Scripting:
return _engine->GetModule("WINGSCRIPT", asGM_ALWAYS_CREATE); mod = _engine->GetModule("WINGSCRIPT", asGM_ALWAYS_CREATE);
mod->SetAccessMask(0x1);
break;
case Background: 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 *ScriptMachine::createModuleIfNotExist(ConsoleMode mode) {
asIScriptModule *mod = nullptr;
switch (mode) { switch (mode) {
case Interactive: case Interactive:
return _engine->GetModule("WINGCONSOLE", asGM_ONLY_IF_EXISTS); mod = _engine->GetModule("WINGCONSOLE", asGM_ONLY_IF_EXISTS);
mod->SetAccessMask(0x1);
break;
case Scripting: 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: 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) { asIScriptModule *ScriptMachine::module(ConsoleMode mode) {
@ -606,6 +800,8 @@ asIScriptModule *ScriptMachine::module(ConsoleMode mode) {
return _engine->GetModule("WINGSCRIPT", asGM_ONLY_IF_EXISTS); return _engine->GetModule("WINGSCRIPT", asGM_ONLY_IF_EXISTS);
case Background: case Background:
return _engine->GetModule("WINGSRV", asGM_ONLY_IF_EXISTS); return _engine->GetModule("WINGSRV", asGM_ONLY_IF_EXISTS);
case DefineEvaluator:
return _engine->GetModule("WINGDEF", asGM_ONLY_IF_EXISTS);
} }
return nullptr; return nullptr;
} }
@ -1832,6 +2028,10 @@ asIScriptEngine *ScriptMachine::engine() const { return _engine; }
asDebugger *ScriptMachine::debugger() const { return _debugger; } asDebugger *ScriptMachine::debugger() const { return _debugger; }
bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) { bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
if (code.isEmpty()) {
return true;
}
asIScriptModule *mod = createModuleIfNotExist(mode); asIScriptModule *mod = createModuleIfNotExist(mode);
_engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, false); _engine->SetEngineProperty(asEP_BUILD_WITHOUT_LINE_CUES, false);
@ -1841,26 +2041,30 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
asIScriptFunction *func = nullptr; 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 // check whether there is any enum/class
if (std::find_if(ret.begin(), ret.end(), if (ret.isEmpty() ||
[](const QAsCodeParser::CodeSegment &seg) { std::any_of(ret.begin(), ret.end(),
switch (seg.type) { [](const QAsCodeParser::CodeSegment &seg) {
case QAsCodeParser::SymbolType::Enum: switch (seg.type) {
case QAsCodeParser::SymbolType::Class: case QAsCodeParser::SymbolType::Enum:
case QAsCodeParser::SymbolType::Function: case QAsCodeParser::SymbolType::Class:
case QAsCodeParser::SymbolType::Interface: case QAsCodeParser::SymbolType::Function:
case QAsCodeParser::SymbolType::Import: case QAsCodeParser::SymbolType::Interface:
case QAsCodeParser::SymbolType::Variable: case QAsCodeParser::SymbolType::Import:
return false; case QAsCodeParser::SymbolType::Variable:
case QAsCodeParser::SymbolType::Invalid: return false;
case QAsCodeParser::SymbolType::TypeDef: case QAsCodeParser::SymbolType::Invalid:
case QAsCodeParser::SymbolType::FnDef: case QAsCodeParser::SymbolType::TypeDef:
return true; case QAsCodeParser::SymbolType::FnDef:
} return true;
return true; }
}) != ret.end()) { return true;
})) {
// ok, wrap the codes // ok, wrap the codes
ccode.prepend("void f(){").append("}"); ccode.prepend("void f(){").append("}");
// start to compile // start to compile
@ -1881,6 +2085,10 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true); asIScriptContext *ctx = _ctxMgr->AddContext(_engine, func, true);
_ctx[mode] = ctx; _ctx[mode] = ctx;
ctx->SetUserData(reinterpret_cast<void *>(asPWORD(
AppManager::instance()->currentMSecsSinceEpoch())),
AsUserDataType::UserData_Timer);
asPWORD isDbg = 0; asPWORD isDbg = 0;
ctx->SetUserData(reinterpret_cast<void *>(isDbg), ctx->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg); AsUserDataType::UserData_isDbg);

View File

@ -36,9 +36,10 @@ private:
public: public:
// we have three console modes // we have three console modes
enum ConsoleMode { enum ConsoleMode {
Interactive, // in a shell Interactive, // in a shell
Scripting, // in scripting dialog Scripting, // in scripting dialog
Background // run codes from other way Background, // run codes from other way
DefineEvaluator // define result calculator
}; };
public: public:
@ -108,8 +109,7 @@ public:
asIScriptModule *module(ConsoleMode mode); asIScriptModule *module(ConsoleMode mode);
static ScriptMachine &instance(); static ScriptMachine &instance();
void destoryMachine();
virtual ~ScriptMachine();
public: public:
bool init(); bool init();
@ -126,6 +126,8 @@ public:
asIScriptEngine *engine() const; asIScriptEngine *engine() const;
void outputMessage(const MessageInfo &info);
public: public:
static void scriptAssert(bool b); static void scriptAssert(bool b);
static void scriptAssert_X(bool b, const QString &msg); static void scriptAssert_X(bool b, const QString &msg);
@ -144,7 +146,9 @@ public slots:
bool executeCode(ConsoleMode mode, const QString &code); bool executeCode(ConsoleMode mode, const QString &code);
// only scripting mode can be debugged // only scripting mode can be debugged
bool executeScript(ConsoleMode mode, const QString &script, 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 abortDbgScript();
void abortScript(ConsoleMode mode); void abortScript(ConsoleMode mode);
@ -155,19 +159,19 @@ protected:
QString getCallStack(asIScriptContext *context); QString getCallStack(asIScriptContext *context);
void destoryMachine();
private: private:
void print(void *ref, int typeId); void print(void *ref, int typeId);
QString getInput(); QString getInput();
void outputMessage(const MessageInfo &info);
bool isType(asITypeInfo *tinfo, RegisteredType type); bool isType(asITypeInfo *tinfo, RegisteredType type);
static int execSystemCmd(QString &out, const QString &exe, static int execSystemCmd(QString &out, const QString &exe,
const QString &params, int timeout); const QString &params, int timeout);
static QString beautify(const QString &str, uint indent);
QString stringify(void *ref, int typeId);
private: private:
static void messageCallback(const asSMessageInfo *msg, void *param); static void messageCallback(const asSMessageInfo *msg, void *param);

View File

@ -57,7 +57,7 @@ void GotoWidget::handleLineChanged() {
ui->lineEdit->setStyleSheet(QString()); ui->lineEdit->setStyleSheet(QString());
emit jumpToLine(p, isline); emit jumpToLine(p, isline);
} else { } else {
ui->lineEdit->setStyleSheet(QStringLiteral("color: red;")); ui->lineEdit->setStyleSheet(QStringLiteral("QLineEdit{color: red}"));
} }
} }

View File

@ -439,6 +439,12 @@ void ScriptingConsole::paste() {
} }
} }
bool ScriptingConsole::isTerminal() const { return _isTerminal; }
void ScriptingConsole::setIsTerminal(bool newIsTerminal) {
_isTerminal = newIsTerminal;
}
QString ScriptingConsole::currentCodes() const { QString ScriptingConsole::currentCodes() const {
QTextCursor textCursor = this->textCursor(); QTextCursor textCursor = this->textCursor();
textCursor.setPosition(inpos_, QTextCursor::KeepAnchor); textCursor.setPosition(inpos_, QTextCursor::KeepAnchor);
@ -457,15 +463,18 @@ void ScriptingConsole::contextMenuEvent(QContextMenuEvent *event) {
menu.addAction(QIcon(QStringLiteral(":/qeditor/paste.png")), tr("Paste"), menu.addAction(QIcon(QStringLiteral(":/qeditor/paste.png")), tr("Paste"),
QKeySequence(QKeySequence::Paste), this, QKeySequence(QKeySequence::Paste), this,
&ScriptingConsole::paste); &ScriptingConsole::paste);
menu.addAction(ICONRES(QStringLiteral("del")), tr("Clear"),
QKeySequence(Qt::ControlModifier | Qt::Key_L), this, if (_isTerminal) {
&ScriptingConsole::clearConsole); menu.addAction(ICONRES(QStringLiteral("del")), tr("Clear"),
menu.addSeparator(); QKeySequence(Qt::ControlModifier | Qt::Key_L), this,
menu.addAction(ICONRES(QStringLiteral("dbgstop")), tr("AbortScript"), &ScriptingConsole::clearConsole);
QKeySequence(Qt::ControlModifier | Qt::Key_Q), []() { menu.addSeparator();
ScriptMachine::instance().abortScript( menu.addAction(ICONRES(QStringLiteral("dbgstop")), tr("AbortScript"),
ScriptMachine::Background); QKeySequence(Qt::ControlModifier | Qt::Key_Q), []() {
}); ScriptMachine::instance().abortScript(
ScriptMachine::Background);
});
}
menu.exec(event->globalPos()); menu.exec(event->globalPos());
} }

View File

@ -40,6 +40,10 @@ signals:
public: public:
QString getInput(); QString getInput();
bool isTerminal() const;
void setIsTerminal(bool newIsTerminal);
public slots: public slots:
void init(); void init();
@ -71,6 +75,7 @@ protected slots:
private: private:
QString _codes; QString _codes;
bool _isTerminal = true;
bool _isWaitingRead = false; bool _isWaitingRead = false;
std::function<QString(void)> _getInputFn; std::function<QString(void)> _getInputFn;
}; };

View File

@ -19,18 +19,47 @@ ScriptingConsoleBase::ScriptingConsoleBase(QWidget *parent)
} }
void ScriptingConsoleBase::stdOut(const QString &str) { void ScriptingConsoleBase::stdOut(const QString &str) {
writeStdOut(str); auto lines = str.split('\n');
dontHighlightLastLine(true); if (lines.isEmpty()) {
return;
}
writeStdOut(lines.takeFirst());
dontHighlightLastLine(false);
for (auto &l : lines) {
newLine();
writeStdOut(l);
dontHighlightLastLine(true);
}
} }
void ScriptingConsoleBase::stdErr(const QString &str) { void ScriptingConsoleBase::stdErr(const QString &str) {
writeStdErr(str); auto lines = str.split('\n');
if (lines.isEmpty()) {
return;
}
writeStdErr(lines.takeFirst());
dontHighlightLastLine(false); dontHighlightLastLine(false);
for (auto &l : lines) {
newLine();
writeStdErr(l);
dontHighlightLastLine(false);
}
} }
void ScriptingConsoleBase::stdWarn(const QString &str) { void ScriptingConsoleBase::stdWarn(const QString &str) {
write(str, _warnCharFmt); auto lines = str.split('\n');
if (lines.isEmpty()) {
return;
}
write(lines.takeFirst(), _warnCharFmt);
dontHighlightLastLine(false); dontHighlightLastLine(false);
for (auto &l : lines) {
newLine();
write(l, _warnCharFmt);
dontHighlightLastLine(false);
}
} }
void ScriptingConsoleBase::newLine() { _s << Qt::endl; } void ScriptingConsoleBase::newLine() { _s << Qt::endl; }

View File

@ -16,6 +16,8 @@ enum AsUserDataType {
UserData_PluginFn, UserData_PluginFn,
UserData_isDbg, UserData_isDbg,
UserData_ContextMode, UserData_ContextMode,
UserData_Timer,
UserData_TimeOut
}; };
} }

View File

@ -607,6 +607,22 @@ ads::CDockAreaWidget *MainWindow::buildUpLogDock(ads::CDockManager *dock,
m_logbrowser->setOpenExternalLinks(true); m_logbrowser->setOpenExternalLinks(true);
m_logbrowser->setUndoRedoEnabled(false); 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 = auto dw =
buildDockWidget(dock, QStringLiteral("Log"), tr("Log"), m_logbrowser); buildDockWidget(dock, QStringLiteral("Log"), tr("Log"), m_logbrowser);
return dock->addDockWidget(area, dw, areaw); return dock->addDockWidget(area, dw, areaw);
@ -803,9 +819,7 @@ MainWindow::buildUpHashResultDock(ads::CDockManager *dock,
m_hashtable->setContextMenuPolicy( m_hashtable->setContextMenuPolicy(
Qt::ContextMenuPolicy::ActionsContextMenu); Qt::ContextMenuPolicy::ActionsContextMenu);
auto a = new QAction(m_hashtable); auto a = newAction(ICONRES(QStringLiteral("copy")), tr("Copy"), [=] {
a->setText(tr("Copy"));
connect(a, &QAction::triggered, this, [=] {
auto r = m_hashtable->currentIndex(); auto r = m_hashtable->currentIndex();
qApp->clipboard()->setText( qApp->clipboard()->setText(
_hashModel->checkSumData(QCryptographicHash::Algorithm(r.row()))); _hashModel->checkSumData(QCryptographicHash::Algorithm(r.row())));
@ -813,6 +827,9 @@ MainWindow::buildUpHashResultDock(ads::CDockManager *dock,
tr("CopyToClipBoard")); tr("CopyToClipBoard"));
}); });
m_hashtable->addAction(a); m_hashtable->addAction(a);
a = newAction(QStringLiteral("del"), tr("Clear"),
[=]() { _hashModel->clearData(); });
m_hashtable->addAction(a);
connect(m_hashtable->selectionModel(), connect(m_hashtable->selectionModel(),
&QItemSelectionModel::currentRowChanged, a, &QItemSelectionModel::currentRowChanged, a,
[=](const QModelIndex &current, const QModelIndex &) { [=](const QModelIndex &current, const QModelIndex &) {

View File

@ -360,7 +360,7 @@ private:
template <typename Func> template <typename Func>
inline QAction *newAction(const QString &title, Func &&slot, inline QAction *newAction(const QString &title, Func &&slot,
const QKeySequence &shortcut = QKeySequence()) { const QKeySequence &shortcut = QKeySequence()) {
auto a = new QAction; auto a = new QAction(this);
a->setText(title); a->setText(title);
a->setShortcutVisibleInContextMenu(true); a->setShortcutVisibleInContextMenu(true);
a->setShortcut(shortcut); a->setShortcut(shortcut);

View File

@ -583,6 +583,7 @@ ScriptingDialog::buildUpOutputShowDock(ads::CDockManager *dock,
ads::CDockAreaWidget *areaw) { ads::CDockAreaWidget *areaw) {
m_consoleout = new ScriptingConsole(this); m_consoleout = new ScriptingConsole(this);
m_consoleout->setMode(ScriptingConsole::Output); m_consoleout->setMode(ScriptingConsole::Output);
m_consoleout->setIsTerminal(false);
auto dw = buildDockWidget(dock, QStringLiteral("ConsoleOutput"), auto dw = buildDockWidget(dock, QStringLiteral("ConsoleOutput"),
tr("ConsoleOutput"), m_consoleout); tr("ConsoleOutput"), m_consoleout);
return dock->addDockWidget(area, dw, areaw); return dock->addDockWidget(area, dw, areaw);

View File

@ -170,7 +170,7 @@ private:
template <typename Func> template <typename Func>
inline QAction *newAction(const QString &title, Func &&slot, inline QAction *newAction(const QString &title, Func &&slot,
const QKeySequence &shortcut = QKeySequence()) { const QKeySequence &shortcut = QKeySequence()) {
auto a = new QAction; auto a = new QAction(this);
a->setText(title); a->setText(title);
a->setShortcutVisibleInContextMenu(true); a->setShortcutVisibleInContextMenu(true);
a->setShortcut(shortcut); a->setShortcut(shortcut);