feat: 代码填充完善;脚本功能增强;

This commit is contained in:
寂静的羽夏 2025-05-02 14:02:31 +08:00
parent c01ca038a3
commit 32e27ba543
21 changed files with 982 additions and 250 deletions

View File

@ -80,7 +80,7 @@
<HlCOct attribute="Octal" context="#stay"/>
<HlCHex attribute="Hex" context="#stay"/>
<Int attribute="Decimal" context="Int Suffixes"/>
<HlCChar attribute="Char" context="#stay"/>
<DetectChar attribute="Char" context="String" char="&apos;"/>
<StringDetect attribute="Text Block" context="TextBlock" String="&quot;&quot;&quot;"/>
<DetectChar attribute="String" context="String" char="&quot;"/>
<Detect2Chars attribute="Comment" context="MatchComment" char="/" char1="/" lookAhead="true"/>
@ -105,6 +105,7 @@
<context attribute="String" lineEndContext="#pop" name="String">
<DetectChar context="StringEscapedChar" char="\" lookAhead="1"/>
<DetectChar attribute="String" context="#pop" char="&quot;"/>
<DetectChar attribute="Char" context="#pop" char="&apos;"/>
</context>
<context attribute="String" lineEndContext="#pop" name="StringEscapedChar">
<HlCStringChar attribute="String Char" context="#pop"/>
@ -144,7 +145,7 @@
<itemData name="Octal" defStyleNum="dsBaseN"/>
<itemData name="Hex" defStyleNum="dsBaseN"/>
<itemData name="Float" defStyleNum="dsFloat"/>
<itemData name="Char" defStyleNum="dsChar"/>
<itemData name="Char" defStyleNum="dsString"/>
<itemData name="String" defStyleNum="dsString"/>
<itemData name="Text Block" defStyleNum="dsString"/>
<itemData name="String Char" defStyleNum="dsSpecialChar"/>

View File

@ -40,6 +40,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, DOT_TRIGGER, ("."))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, DBL_COLON_TRIGGER, ("::"))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, LEFT_PARE_TRIGGER, ("("))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SEMI_COLON_TRIGGER, (";"))
Q_GLOBAL_STATIC_WITH_ARGS(QByteArray, SHARP_TRIGGER, ("#"))
AsCompletion::AsCompletion(WingCodeEdit *p)
: WingCompleter(p), parser(ScriptMachine::instance().engine()) {
@ -47,7 +48,9 @@ AsCompletion::AsCompletion(WingCodeEdit *p)
// unleash the power of call tips
*LEFT_PARE_TRIGGER,
// clear the tips
*SEMI_COLON_TRIGGER});
*SEMI_COLON_TRIGGER,
// for marcos
*SHARP_TRIGGER});
setTriggerAmount(3);
connect(this, QOverload<const QModelIndex &>::of(&AsCompletion::activated),
@ -168,12 +171,20 @@ int AsCompletion::includeCallBack(const QString &include, bool quotedInclude,
void AsCompletion::clearFunctionTip() { emit onFunctionTip({}); }
QString AsCompletion::wordSeperators() const {
static QString eow(QStringLiteral("~!@#$%^&*()_+{}|\"<>?,/;'[]\\-="));
static QString eow(QStringLiteral("~!@$%^&*()_+{}|\"<>?,/;'[]\\-="));
return eow;
}
bool AsCompletion::processTrigger(const QString &trigger,
const QString &content) {
QList<CodeInfoTip> nodes;
if (trigger == *SHARP_TRIGGER) {
setModel(new CodeCompletionModel(parseMarcos(), this));
setCompletionPrefix({});
return true;
}
if (content.isEmpty()) {
return false;
}
@ -186,8 +197,6 @@ bool AsCompletion::processTrigger(const QString &trigger,
auto len = content.length();
auto code = content.toUtf8();
QList<CodeInfoTip> nodes;
if (!trigger.isEmpty() && trigger != *DOT_TRIGGER) {
clearFunctionTip();
}
@ -257,6 +266,7 @@ bool AsCompletion::processTrigger(const QString &trigger,
auto etoken = tokens.back();
// it can not be any trigger, so take the last as prefix
QString prefix = etoken.content;
if (etoken.type == asTC_VALUE || etoken.type == asTC_COMMENT ||
etoken.type == asTC_UNKNOWN) {
popup()->hide();
@ -268,6 +278,15 @@ bool AsCompletion::processTrigger(const QString &trigger,
return true;
}
if (trigger.isEmpty() && tokens.length() > 1) {
auto t = std::next(tokens.rbegin());
if (t->content == "#") {
setModel(new CodeCompletionModel(parseMarcos(), this));
setCompletionPrefix(prefix);
return true;
}
}
QList<CodeInfoTip> docNodes = parseDocument();
// if trigger is empty, it's making editing
@ -413,11 +432,8 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
// first preprocess the code
AsPreprocesser prepc(engine);
prepc.setIsCodeCompleteMode(true);
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());
@ -428,6 +444,15 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
auto data = prepc.scriptData();
QList<CodeInfoTip> ret;
auto marcos = prepc.definedMacros();
for (auto pkey = marcos.keyBegin(); pkey != marcos.keyEnd(); pkey++) {
CodeInfoTip tip;
tip.type = CodeInfoTip::Type::KeyWord;
tip.dontAddGlobal = true;
tip.name = *pkey;
ret.append(tip);
}
for (auto &d : data) {
qsizetype offset = -1;
if (d.section == QStringLiteral("ASCOMPLETION")) {
@ -439,6 +464,22 @@ QList<CodeInfoTip> AsCompletion::parseDocument() {
return ret;
}
QList<CodeInfoTip> AsCompletion::parseMarcos() {
static QList<CodeInfoTip> marcos;
if (marcos.isEmpty()) {
QStringList m{"define", "undef", "if", "else",
"endif", "ifdef", "ifndef"};
for (auto &i : m) {
CodeInfoTip tip;
tip.name = i;
tip.dontAddGlobal = true;
tip.type = CodeInfoTip::Type::KeyWord;
marcos.append(tip);
}
}
return marcos;
}
QList<CodeInfoTip> AsCompletion::parseScriptData(qsizetype offset,
const QByteArray &code) {
QList<CodeInfoTip> ret;

View File

@ -42,6 +42,8 @@ protected:
virtual QList<CodeInfoTip> parseDocument();
virtual QList<CodeInfoTip> parseMarcos();
QList<CodeInfoTip> parseScriptData(qsizetype offset,
const QByteArray &code);

View File

@ -87,3 +87,22 @@ QList<CodeInfoTip> AsConsoleCompletion::parseDocument() {
return citips;
}
}
QList<CodeInfoTip> AsConsoleCompletion::parseMarcos() {
static QList<CodeInfoTip> marcos;
if (marcos.isEmpty()) {
QStringList m{
"ls",
"del",
"cls",
};
for (auto &i : m) {
CodeInfoTip tip;
tip.name = i;
tip.dontAddGlobal = true;
tip.type = CodeInfoTip::Type::KeyWord;
marcos.append(tip);
}
}
return marcos;
}

View File

@ -29,7 +29,8 @@ public:
virtual ~AsConsoleCompletion() = default;
protected:
virtual QList<CodeInfoTip> parseDocument();
virtual QList<CodeInfoTip> parseDocument() override;
virtual QList<CodeInfoTip> parseMarcos() override;
private:
ScriptingConsole *_console;

View File

@ -88,6 +88,8 @@ void asDebugger::lineCallback(asIScriptContext *ctx) {
auto now = AppManager::instance()->currentMSecsSinceEpoch();
auto timer = reinterpret_cast<asPWORD>(
ctx->GetUserData(AsUserDataType::UserData_Timer));
auto timeOutTime = reinterpret_cast<asPWORD>(
ctx->GetUserData(AsUserDataType::UserData_TimeOut));
auto mode = ScriptMachine::ConsoleMode(reinterpret_cast<asPWORD>(
ctx->GetUserData(AsUserDataType::UserData_ContextMode)));
@ -98,7 +100,9 @@ void asDebugger::lineCallback(asIScriptContext *ctx) {
if (mode == ScriptMachine::DefineEvaluator) {
timeOut = (now - timer) > 3000; // 3 s
} else {
timeOut = (now - timer) > 600000; // 10 min
if (timeOutTime) {
timeOut = (now - timer) > timeOutTime; // 10 min
}
}
}

View File

@ -16,6 +16,7 @@
*/
#include "aspreprocesser.h"
#include "class/qascodeparser.h"
#include "class/scriptmachine.h"
#include <QDir>
@ -23,7 +24,7 @@
#include <QStack>
Q_GLOBAL_STATIC_WITH_ARGS(
QStringList, DEFAULT_MARCO,
QByteArrayList, DEFAULT_MARCO,
({"__AS_ARRAY__", "__AS_ANY__", "__AS_GRID__", "__AS_HANDLE__",
"__AS_MATH__", "__AS_WEAKREF__", "__AS_COROUTINE__", "__WING_FILE__",
"__WING_STRING__", "__WING_COLOR__", "__WING_JSON__", "__WING_REGEX__",
@ -89,11 +90,13 @@ void AsPreprocesser::setPragmaCallback(PRAGMACALLBACK_t callback,
pragmaParam = userParam;
}
void AsPreprocesser::defineWord(const QString &word,
const DefineValueType &value) {
if (!definedWords.contains(word)) {
definedWords.insert(word, value);
bool AsPreprocesser::defineWord(const QString &word, const QByteArray &value) {
// try to modify system marco is not allowed
if (DEFAULT_MARCO->contains(word)) {
return false;
}
definedWords.insert(word, value);
return true;
}
unsigned int AsPreprocesser::sectionCount() const {
@ -111,6 +114,9 @@ void AsPreprocesser::clearAll() { includedScripts.clear(); }
int AsPreprocesser::processScriptSection(const QByteArray &script,
const QString &sectionname) {
// #define DBG_CODEP // debug macro for pre-process
QVector<QPair<QString, bool>> includes;
QByteArray modifiedScript = script;
@ -140,17 +146,43 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
bool isIf = token == QStringLiteral("if");
bool isIfDef = token == QStringLiteral("ifdef");
bool isIfnDef = token == QStringLiteral("ifndef");
bool isDef = token == QStringLiteral("define");
bool isUnDef = token == QStringLiteral("undef");
if (isIf || isIfDef || isIfnDef) {
if (isIf || isIfDef || isIfnDef || isDef || isUnDef) {
t = engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len);
if (t == asTC_WHITESPACE) {
if (std::any_of(modifiedScript.data() + pos,
modifiedScript.data() + pos + len,
[](char ch) { return ch == '\n'; })) {
if (_isCodeCompleteMode) {
pos = modifiedScript.indexOf('\n', pos);
continue;
}
auto str = QObject::tr("IfDefNoWord");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
pos += len;
t = engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len);
}
if (isIfDef || isIfnDef) {
if (_isCodeCompleteMode) {
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start - 1);
} else {
overwriteCode(modifiedScript, start, pos - start);
}
continue;
}
if (t == asTC_IDENTIFIER) {
QByteArray word = modifiedScript.sliced(pos, len);
@ -165,17 +197,49 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
(isIfnDef && definedWords.contains(word))) {
// Exclude all the code until and including the
// #endif
pos = excludeCode(modifiedScript, pos);
pos = excludeIfCode(modifiedScript, pos);
m_condtionStack.push(false);
} else {
m_condtionStack.push(true);
}
#ifdef DBG_CODEP
qDebug().noquote() << modifiedScript;
#endif
} else {
auto str = QObject::tr("IfDefInvalidWord");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
// ensure end line
if (endLinePassFailed(modifiedScript, pos)) {
auto str = QObject::tr("UnexceptedToken");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
} else if (isIf) {
if (_isCodeCompleteMode) {
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start - 1);
} else {
overwriteCode(modifiedScript, start, pos - start);
}
continue;
}
} else {
// evalutate the string
auto npos = modifiedScript.indexOf('\n', pos);
auto codes = modifiedScript.sliced(pos, npos - pos);
QByteArray codes;
if (npos >= 0) {
codes = modifiedScript.sliced(pos, npos - pos);
} else {
codes = modifiedScript.sliced(pos);
}
overwriteCode(modifiedScript, start, npos - start);
auto &sm = ScriptMachine::instance();
@ -183,53 +247,249 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
auto ret = sm.evaluateDefine(codes, ok);
if (ret < 0) {
auto str = QObject::tr("CalIfFailed");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
} else {
if (ok) {
m_condtionStack.push(true);
} else {
pos = excludeCode(modifiedScript, npos);
pos = excludeIfCode(modifiedScript, npos);
m_condtionStack.push(false);
}
}
#ifdef DBG_CODEP
qDebug().noquote() << modifiedScript;
#endif
} else if (isDef) {
if (t == asTC_IDENTIFIER) {
QByteArray word = modifiedScript.sliced(pos, len);
pos += len;
if (_isCodeCompleteMode) {
defineWord(word, {});
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start -
1);
} else {
overwriteCode(modifiedScript, start,
pos - start);
}
continue;
}
t = engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos,
&len);
if (t == asTC_WHITESPACE) {
// line break?
if (std::any_of(
modifiedScript.data() + pos,
modifiedScript.data() + pos + len,
[](char ch) { return ch == '\n'; })) {
defineWord(word, {});
} else {
pos += len;
size_t total = 0;
auto v = QAsCodeParser::getToken(
engine, modifiedScript.data() + pos,
modifiedScript.size() - pos, &total);
// only support these things
switch (v) {
case ttIdentifier:
case ttIntConstant:
case ttFloatConstant:
case ttDoubleConstant:
case ttBitsConstant:
case ttStringConstant: {
auto v = modifiedScript.sliced(pos, total);
defineWord(word, v);
} break;
default:
auto str = QObject::tr("UnexceptedToken");
engine->WriteMessage(
sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
pos += total;
}
overwriteCode(modifiedScript, start, pos - start);
}
// ensure end line
if (endLinePassFailed(modifiedScript, pos)) {
auto str = QObject::tr("UnexceptedToken");
engine->WriteMessage(
sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
} else {
if (_isCodeCompleteMode) {
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start -
1);
} else {
overwriteCode(modifiedScript, start,
pos - start);
}
continue;
}
auto str = QObject::tr("InvalidDef");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
} else if (isUnDef) {
if (_isCodeCompleteMode) {
auto pos = modifiedScript.indexOf('\n', start);
if (pos < 0) {
overwriteCode(modifiedScript, start,
modifiedScript.size() - start - 1);
} else {
overwriteCode(modifiedScript, start, pos - start);
}
continue;
}
if (t == asTC_IDENTIFIER) {
QByteArray word = modifiedScript.sliced(pos, len);
// Overwrite the directive with space characters to
// avoid compiler error
pos += len;
overwriteCode(modifiedScript, start, pos - start);
constexpr auto PREFIX = "__";
if (word.startsWith(PREFIX) && word.endsWith(PREFIX)) {
// Warning
auto str = QObject::tr("ReservedMarcoType");
engine->WriteMessage(
sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_WARNING, str.toUtf8());
} else {
if (!definedWords.remove(word)) {
auto str = QObject::tr("MarcoNotFound:") + word;
engine->WriteMessage(
sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_WARNING, str.toUtf8());
}
}
// ensure end line
if (endLinePassFailed(modifiedScript, pos)) {
auto str = QObject::tr("UnexceptedToken");
engine->WriteMessage(
sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
} else {
auto str = QObject::tr("InvalidDef");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
}
} else if (token == "else") {
if (_isCodeCompleteMode) {
overwriteCode(modifiedScript, start, pos - start);
continue;
}
if (m_condtionStack.isEmpty()) {
// TODO
auto str = QObject::tr("NoMatchingIf");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
} else {
overwriteCode(modifiedScript, start, pos - start);
auto opBool = m_condtionStack.top();
if (opBool) {
if (opBool.value()) {
pos = excludeCode(modifiedScript, pos);
pos = excludeElseCode(modifiedScript, pos);
m_condtionStack.top().reset();
}
// ensure end line
if (endLinePassFailed(modifiedScript, pos - 1)) {
auto str = QObject::tr("UnexceptedToken");
engine->WriteMessage(
sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
} else {
// TODO
auto str = QObject::tr("DupElseDef");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos),
1, asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
}
#ifdef DBG_CODEP
qDebug().noquote() << modifiedScript;
#endif
} else if (token == "endif") {
if (_isCodeCompleteMode) {
overwriteCode(modifiedScript, start, pos - start);
continue;
}
// Only remove the #endif if there was a matching #if
if (m_condtionStack.isEmpty()) {
// TODO
auto str = QObject::tr("NoMatchingIf");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
} else {
overwriteCode(modifiedScript, start, pos - start);
m_condtionStack.pop();
}
// ensure end line
if (endLinePassFailed(modifiedScript, pos)) {
auto str = QObject::tr("UnexceptedToken");
engine->WriteMessage(sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
return asERROR;
}
#ifdef DBG_CODEP
qDebug().noquote() << modifiedScript;
#endif
}
} else {
if (t == asTC_IDENTIFIER) {
// define replace
auto word = modifiedScript.sliced(pos, len);
auto rword = findReplaceResult(word);
if (word != rword) {
modifiedScript.replace(pos, len, rword);
len = rword.length();
}
}
pos += len;
}
}
#ifdef DBG_CODEP
qDebug().noquote() << modifiedScript;
#endif
// Then check for pre-processor directives
pos = 0;
@ -281,15 +541,15 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// line breaks
auto p = includefile.indexOf('\n');
if (p >= 0) {
// TODO: Show the correct line number for the
// error
auto str =
QObject::tr("Invalid file name for #include; "
"it contains a line-break: ") +
QStringLiteral("'") + includefile.left(p) +
QStringLiteral("'");
engine->WriteMessage(sectionname.toUtf8(), 0, 0,
asMSGTYPE_ERROR, str.toUtf8());
engine->WriteMessage(
sectionname.toUtf8(),
getLineCount(modifiedScript, pos), 1,
asMSGTYPE_ERROR, str.toUtf8());
} else {
// Store it for later processing
includes.append({includefile, true});
@ -298,9 +558,8 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// characters to avoid compiler error
overwriteCode(modifiedScript, start, pos - start);
}
}
if (t == asTC_KEYWORD && modifiedScript[pos] == '<') {
} else if (t == asTC_KEYWORD &&
modifiedScript[pos] == '<') {
pos += len;
// find the next '>'
@ -373,16 +632,19 @@ int AsPreprocesser::processScriptSection(const QByteArray &script,
// to avoid compiler error
overwriteCode(modifiedScript, start, pos - start);
int r = pragmaCallback
? pragmaCallback(pragmaText, this, sectionname,
pragmaParam)
: -1;
if (r < 0) {
// TODO: Report the correct line number
engine->WriteMessage(
sectionname.toUtf8(), 0, 0, asMSGTYPE_ERROR,
QObject::tr("Invalid #pragma directive").toUtf8());
return r;
if (!_isCodeCompleteMode) {
int r = pragmaCallback
? pragmaCallback(pragmaText, this,
sectionname, pragmaParam)
: -1;
if (r < 0) {
// TODO: Report the correct line number
engine->WriteMessage(
sectionname.toUtf8(), 0, 0, asMSGTYPE_ERROR,
QObject::tr("Invalid #pragma directive")
.toUtf8());
return r;
}
}
}
}
@ -476,7 +738,7 @@ bool AsPreprocesser::includeIfNotAlreadyIncluded(const QString &filename) {
return true;
}
int AsPreprocesser::skipStatement(const QByteArray &modifiedScript, int pos) {
int AsPreprocesser::skipStatement(QByteArray &modifiedScript, int pos) {
asUINT len = 0;
// Skip until ; or { whichever comes first
@ -502,18 +764,18 @@ int AsPreprocesser::skipStatement(const QByteArray &modifiedScript, int pos) {
else if (modifiedScript[pos] == '}')
level--;
}
pos += len;
}
} else
} else {
pos += 1;
}
return pos;
}
int AsPreprocesser::excludeCode(QByteArray &modifiedScript, int pos) {
int AsPreprocesser::excludeIfCode(QByteArray &modifiedScript, int pos) {
asUINT len = 0;
int nested = 1;
int nested = 0;
while (pos < (int)modifiedScript.size()) {
engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len);
@ -526,20 +788,50 @@ int AsPreprocesser::excludeCode(QByteArray &modifiedScript, int pos) {
QString token = modifiedScript.sliced(pos, len);
if (token == "if" || token == "ifdef" || token == "ifndef") {
modifiedScript[sharpPos] = ' ';
overwriteCode(modifiedScript, pos, len);
nested++;
} else if (token == "endif" || token == "else") {
} else if (token == "else") {
if (nested-- == 0) {
pos = sharpPos - 1;
pos = sharpPos;
break;
}
modifiedScript[sharpPos] = ' ';
overwriteCode(modifiedScript, pos, len);
} else {
modifiedScript[sharpPos] = ' ';
overwriteCode(modifiedScript, pos, len);
}
modifiedScript[sharpPos] = ' ';
overwriteCode(modifiedScript, pos, len);
} else if (modifiedScript[pos] != '\n') {
overwriteCode(modifiedScript, pos, len);
}
pos += len;
}
return pos;
}
int AsPreprocesser::excludeElseCode(QByteArray &modifiedScript, int pos) {
asUINT len = 0;
int nested = 0;
while (pos < (int)modifiedScript.size()) {
engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len);
if (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.sliced(pos, len);
if (token == "if" || token == "ifdef" || token == "ifndef") {
nested++;
} else if (token == "endif") {
if (nested-- == 0) {
pos = sharpPos;
break;
}
}
modifiedScript[sharpPos] = ' ';
overwriteCode(modifiedScript, pos, len);
} else if (modifiedScript[pos] != '\n') {
overwriteCode(modifiedScript, pos, len);
}
@ -559,6 +851,56 @@ void AsPreprocesser::overwriteCode(QByteArray &modifiedScript, int start,
}
}
int AsPreprocesser::getLineCount(const QByteArray &modifiedScript,
int pos) const {
pos = qBound(0, pos, int(modifiedScript.size()));
return std::count_if(modifiedScript.begin(),
std::next(modifiedScript.begin(), pos),
[](char ch) -> bool { return ch == '\n'; }) +
1;
}
bool AsPreprocesser::endLinePassFailed(const QByteArray &modifiedScript,
int pos) { // ensure '\n' end line
bool endError = false;
asUINT len = 0;
auto t = engine->ParseToken(modifiedScript.data() + pos,
modifiedScript.size() - pos, &len);
if (t == asTC_WHITESPACE) {
if (!std::any_of(modifiedScript.data() + pos,
modifiedScript.data() + pos + len,
[](char ch) { return ch == '\n'; })) {
endError = true;
}
} else {
if (len != 0) {
endError = true;
}
}
return endError;
}
QByteArray AsPreprocesser::findReplaceResult(const QByteArray &v) {
QByteArray r = v;
while (definedWords.contains(r)) {
r = definedWords.value(r);
if (r.isEmpty()) {
break;
}
}
return r;
}
bool AsPreprocesser::isCodeCompleteMode() const { return _isCodeCompleteMode; }
void AsPreprocesser::setIsCodeCompleteMode(bool newIsCodeCompleteMode) {
_isCodeCompleteMode = newIsCodeCompleteMode;
}
QHash<QString, QByteArray> AsPreprocesser::definedMacros() const {
return definedWords;
}
void AsPreprocesser::addScriptSection(const QString &section,
const QByteArray &code) {
ScriptData data;

View File

@ -71,7 +71,7 @@ typedef int (*PRAGMACALLBACK_t)(const QByteArray &pragmaText,
* * #define <word> <string|int64|double>
* * #undef <word>
* * #ifdef <word>
* * #ifundef <word>
* * #ifndef <word>
*/
class AsPreprocesser {
public:
@ -84,9 +84,6 @@ 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
@ -95,6 +92,8 @@ public:
int loadSectionFromFile(const QString &filename);
int loadSectionFromMemory(const QString &section, const QByteArray &code);
void addScriptSection(const QString &section, const QByteArray &code);
QList<ScriptData> scriptData() const;
// Returns the engine
@ -107,25 +106,39 @@ public:
void setPragmaCallback(PRAGMACALLBACK_t callback, void *userParam);
// Add a pre-processor define for conditional compilation
void defineWord(const QString &word, const DefineValueType &value = {});
bool defineWord(const QString &word, const QByteArray &value = {});
// Enumerate included script sections
unsigned int sectionCount() const;
QString sectionName(unsigned int idx) const;
bool isCodeCompleteMode() const;
void setIsCodeCompleteMode(bool newIsCodeCompleteMode);
QHash<QString, QByteArray> definedMacros() const;
protected:
QString translate(const char *str);
protected:
void clearAll();
void addScriptSection(const QString &section, const QByteArray &code);
int processScriptSection(const QByteArray &script,
const QString &sectionname);
int loadScriptSection(const QString &filename);
bool includeIfNotAlreadyIncluded(const QString &filename);
int skipStatement(const QByteArray &modifiedScript, int pos);
int skipStatement(QByteArray &modifiedScript, int pos);
int excludeCode(QByteArray &modifiedScript, int pos);
int excludeIfCode(QByteArray &modifiedScript, int pos);
int excludeElseCode(QByteArray &modifiedScript, int pos);
void overwriteCode(QByteArray &modifiedScript, int start, int len);
int getLineCount(const QByteArray &modifiedScript, int pos) const;
bool endLinePassFailed(const QByteArray &modifiedScript, int pos);
QByteArray findReplaceResult(const QByteArray &v);
asIScriptEngine *engine;
QList<ScriptData> modifiedScripts;
@ -138,8 +151,10 @@ protected:
QStringList includedScripts;
QEventLoop waitLoop;
QHash<QString, DefineValueType> definedWords;
QHash<QString, QByteArray> definedWords;
private:
bool _isCodeCompleteMode = false;
};
#endif // ASPREPROCESSER_H

View File

@ -53,6 +53,15 @@ QAsCodeParser::parse(const QByteArray &codes) {
return parseScript(false);
}
eTokenType QAsCodeParser::getToken(asIScriptEngine *engine, const char *string,
size_t stringLength, size_t *tokenLength) {
auto e = dynamic_cast<asCScriptEngine *>(engine);
if (e) {
return e->tok.GetToken(string, stringLength, tokenLength, nullptr);
}
return ttUnrecognizedToken;
}
QList<QAsCodeParser::Symbol>
QAsCodeParser::parseAndIntell(qsizetype offset, const QByteArray &codes) {
return parseIntell(offset, parse(codes));
@ -572,7 +581,7 @@ QAsCodeParser::parseStatementBlock(const QByteArrayList &ns,
rewindTo(&t1);
if (isVarDecl()) {
syms.top().append(parseDeclaration(ns));
syms.top().append(parseDeclaration(end, ns));
} else {
_isSyntaxError = true;
}
@ -1069,8 +1078,8 @@ void QAsCodeParser::superficiallyParseVarInit() {
}
QList<QAsCodeParser::Symbol>
QAsCodeParser::parseDeclaration(const QByteArrayList &ns, bool isClassProp,
bool isGlobalVar) {
QAsCodeParser::parseDeclaration(qsizetype end, const QByteArrayList &ns,
bool isClassProp, bool isGlobalVar) {
QList<QAsCodeParser::Symbol> ret;
Symbol sym;
@ -1097,6 +1106,10 @@ QAsCodeParser::parseDeclaration(const QByteArrayList &ns, bool isClassProp,
for (;;) {
// Parse identifier
auto id = parseIdentifier();
if (end >= 0 && id.pos > end) {
return ret;
}
if (_isSyntaxError)
return ret;
@ -1438,7 +1451,7 @@ QList<QAsCodeParser::Symbol>
QAsCodeParser::parseGlobalVarDecls(const QByteArrayList &ns,
const QByteArray &code) {
_code = code;
return parseDeclaration(ns, false, true);
return parseDeclaration(-1, ns, false, true);
}
QAsCodeParser::CodeSegment QAsCodeParser::parseFunctionMethod(Visiblity &vis) {
@ -1625,7 +1638,7 @@ QAsCodeParser::parseClassContent(qsizetype offset, const QByteArrayList &ns,
auto vp = parseVirtualPropertyDecl(true, false);
syms.append(vp);
} else if (isVarDecl()) {
auto decl = parseDeclaration(ns, true);
auto decl = parseDeclaration(offset, ns, true);
syms.append(decl);
} else if (t.type == ttEndStatement)
// Skip empty declarations
@ -2303,66 +2316,6 @@ bool QAsCodeParser::findTokenAfterType(
return true;
}
bool QAsCodeParser::isConstant(int tokenType) {
if (tokenType == ttIntConstant || tokenType == ttFloatConstant ||
tokenType == ttDoubleConstant || tokenType == ttStringConstant ||
tokenType == ttMultilineStringConstant ||
tokenType == ttHeredocStringConstant || tokenType == ttTrue ||
tokenType == ttFalse || tokenType == ttBitsConstant ||
tokenType == ttNull)
return true;
return false;
}
bool QAsCodeParser::isOperator(int tokenType) {
if (tokenType == ttPlus || tokenType == ttMinus || tokenType == ttStar ||
tokenType == ttSlash || tokenType == ttPercent ||
tokenType == ttStarStar || tokenType == ttAnd || tokenType == ttOr ||
tokenType == ttXor || tokenType == ttEqual || tokenType == ttNotEqual ||
tokenType == ttLessThan || tokenType == ttLessThanOrEqual ||
tokenType == ttGreaterThan || tokenType == ttGreaterThanOrEqual ||
tokenType == ttAmp || tokenType == ttBitOr || tokenType == ttBitXor ||
tokenType == ttBitShiftLeft || tokenType == ttBitShiftRight ||
tokenType == ttBitShiftRightArith || tokenType == ttIs ||
tokenType == ttNotIs)
return true;
return false;
}
bool QAsCodeParser::isPreOperator(int tokenType) {
if (tokenType == ttMinus || tokenType == ttPlus || tokenType == ttNot ||
tokenType == ttInc || tokenType == ttDec || tokenType == ttBitNot ||
tokenType == ttHandle)
return true;
return false;
}
bool QAsCodeParser::isPostOperator(int tokenType) {
if (tokenType == ttInc || // post increment
tokenType == ttDec || // post decrement
tokenType == ttDot || // member access
tokenType == ttOpenBracket || // index operator
tokenType ==
ttOpenParenthesis) // argument list for call on function pointer
return true;
return false;
}
bool QAsCodeParser::isAssignOperator(int tokenType) {
if (tokenType == ttAssignment || tokenType == ttAddAssign ||
tokenType == ttSubAssign || tokenType == ttMulAssign ||
tokenType == ttDivAssign || tokenType == ttModAssign ||
tokenType == ttPowAssign || tokenType == ttAndAssign ||
tokenType == ttOrAssign || tokenType == ttXorAssign ||
tokenType == ttShiftLeftAssign || tokenType == ttShiftRightLAssign ||
tokenType == ttShiftRightAAssign)
return true;
return false;
}
bool QAsCodeParser::typeExist(const QString &t) {
Q_UNUSED(t);
// TODO: don't check

View File

@ -106,12 +106,8 @@ public:
QList<Symbol> parseAndIntell(qsizetype offset, const QByteArray &codes);
public:
// utilities
static bool isConstant(int tokenType);
static bool isOperator(int tokenType);
static bool isPreOperator(int tokenType);
static bool isPostOperator(int tokenType);
static bool isAssignOperator(int tokenType);
static eTokenType getToken(asIScriptEngine *engine, const char *string,
size_t stringLength, size_t *tokenLength);
private:
QList<QAsCodeParser::CodeSegment> parseScript(bool inBlock);
@ -161,7 +157,7 @@ private:
QByteArrayList parseOptionalScope();
QList<Symbol> parseDeclaration(const QByteArrayList &ns,
QList<Symbol> parseDeclaration(qsizetype end, const QByteArrayList &ns,
bool isClassProp = false,
bool isGlobalVar = false);

View File

@ -31,8 +31,10 @@
#include "angelobjstring.h"
#include "class/appmanager.h"
#include "class/asbuilder.h"
#include "class/logger.h"
#include "class/pluginsystem.h"
#include "class/qascodeparser.h"
#include "class/settingmanager.h"
#include "define.h"
#include "scriptaddon/scriptcolor.h"
#include "scriptaddon/scriptfile.h"
@ -415,6 +417,11 @@ QString ScriptMachine::stringify(void *ref, int typeId) {
bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
bool isInDebug, int *retCode) {
Q_ASSERT(mode != Interactive && mode != DefineEvaluator);
if (QThread::currentThread() != qApp->thread()) {
Logger::warning(tr("Code must be exec in the main thread"));
return false;
}
if (script.isEmpty()) {
return true;
}
@ -451,10 +458,14 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
builder.setPragmaCallback(&ScriptMachine::pragmaCallback, this);
builder.setIncludeCallback(&ScriptMachine::includeCallback, this);
_curMode = mode;
_curMsgMode = mode;
auto r = builder.loadSectionFromFile(script.toUtf8());
if (r < 0) {
// TODO
MessageInfo info;
info.mode = mode;
info.message = tr("Script failed to pre-processed");
info.type = MessageType::Error;
outputMessage(info);
return false;
}
@ -519,6 +530,11 @@ bool ScriptMachine::executeScript(ConsoleMode mode, const QString &script,
ctx->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg);
auto timeOutRaw = SettingManager::instance().scriptTimeout();
auto timeOut = asPWORD(timeOutRaw) * 6000; // min -> ms
ctx->SetUserData(reinterpret_cast<void *>(timeOut),
AsUserDataType::UserData_TimeOut);
mod->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg);
@ -607,10 +623,14 @@ int ScriptMachine::evaluateDefine(const QString &code, bool &result) {
if (mod) {
asIScriptFunction *func = nullptr;
auto oldMode = _curMsgMode;
QScopeGuard guard([this, oldMode]() { _curMsgMode = oldMode; });
auto ccode = code;
ccode.prepend("bool f(){ return (").append(");}");
// start to compile
_curMode = DefineEvaluator;
_curMsgMode = DefineEvaluator;
auto cr = mod->CompileFunction(nullptr, ccode.toUtf8(), 0, 0, &func);
if (cr < 0) {
return cr;
@ -706,7 +726,7 @@ void ScriptMachine::messageCallback(const asSMessageInfo *msg, void *param) {
return;
}
MessageInfo info;
info.mode = ins->_curMode;
info.mode = ins->_curMsgMode;
info.row = msg->row;
info.col = msg->col;
info.section = msg->section;
@ -839,19 +859,21 @@ void ScriptMachine::returnContextCallback(asIScriptEngine *engine,
asIScriptContext *ctx, void *param) {
Q_UNUSED(engine);
// We can also check for possible script exceptions here if so desired
if (ctx) {
// We can also check for possible script exceptions here if so desired
// Unprepare the context to free any objects it may still hold (e.g. return
// value) This must be done before making the context available for re-use,
// as the clean up may trigger other script executions, e.g. if a destructor
// needs to call a function.
ctx->Unprepare();
// Unprepare the context to free any objects it may still hold (e.g.
// return value) This must be done before making the context available
// for re-use, as the clean up may trigger other script executions, e.g.
// if a destructor needs to call a function.
ctx->Unprepare();
auto p = reinterpret_cast<ScriptMachine *>(param);
Q_ASSERT(p);
auto p = reinterpret_cast<ScriptMachine *>(param);
Q_ASSERT(p);
// Place the context into the pool for when it will be needed again
p->_ctxPool.push_back(ctx);
// Place the context into the pool for when it will be needed again
p->_ctxPool.push_back(ctx);
}
}
int ScriptMachine::pragmaCallback(const QByteArray &pragmaText,
@ -2028,6 +2050,11 @@ asIScriptEngine *ScriptMachine::engine() const { return _engine; }
asDebugger *ScriptMachine::debugger() const { return _debugger; }
bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
if (QThread::currentThread() != qApp->thread()) {
Logger::warning(tr("Code must be exec in the main thread"));
return false;
}
if (code.isEmpty()) {
return true;
}
@ -2068,7 +2095,7 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
// ok, wrap the codes
ccode.prepend("void f(){").append("}");
// start to compile
_curMode = mode;
_curMsgMode = mode;
auto cr = mod->CompileFunction(nullptr, ccode, 0, 0, &func);
if (cr < 0) {
MessageInfo info;
@ -2095,6 +2122,11 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
mod->SetUserData(reinterpret_cast<void *>(isDbg),
AsUserDataType::UserData_isDbg);
auto timeOutRaw = SettingManager::instance().scriptTimeout();
auto timeOut = asPWORD(timeOutRaw) * 6000; // min -> ms
ctx->SetUserData(reinterpret_cast<void *>(timeOut),
AsUserDataType::UserData_TimeOut);
asPWORD umode = asPWORD(mode);
ctx->SetUserData(reinterpret_cast<void *>(umode),
AsUserDataType::UserData_ContextMode);
@ -2159,7 +2191,7 @@ bool ScriptMachine::executeCode(ConsoleMode mode, const QString &code) {
return seg.type ==
QAsCodeParser::SymbolType::Variable;
})) {
_curMode = mode;
_curMsgMode = mode;
for (auto &s : ret) {
auto r = mod->CompileGlobalVar(nullptr, s.codes, 0);

View File

@ -212,7 +212,7 @@ private:
QVector<asITypeInfo *> _rtypes;
QMap<ConsoleMode, RegCallBacks> _regcalls;
QMap<ConsoleMode, asIScriptContext *> _ctx;
ConsoleMode _curMode = ConsoleMode::Background;
ConsoleMode _curMsgMode = ConsoleMode::Background;
};
Q_DECLARE_METATYPE(ScriptMachine::MessageInfo)

View File

@ -59,6 +59,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_RECENTFILES, ("script.recentfiles"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_ALLOW_USRSCRIPT_INROOT,
("script.allowUsrScriptRoot"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_ENABLE, ("script.enable"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_TIMEOUT, ("script.timeout"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_USRHIDECATS, ("script.usrHideCats"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, SCRIPT_SYSHIDECATS, ("script.sysHideCats"))
Q_GLOBAL_STATIC_WITH_ARGS(QString, OTHER_USESYS_FILEDIALOG,
@ -146,6 +147,8 @@ void SettingManager::load() {
READ_CONFIG_BOOL(m_scriptEnabled, SCRIPT_ENABLE, true);
READ_CONFIG_BOOL(m_allowUsrScriptInRoot, SCRIPT_ALLOW_USRSCRIPT_INROOT,
false);
READ_CONFIG_INT(m_scriptTimeout, SCRIPT_TIMEOUT, 10);
m_scriptTimeout = qBound(0, m_scriptTimeout, 312480);
m_usrHideCats =
READ_CONFIG(SCRIPT_USRHIDECATS, QStringList()).toStringList();
m_sysHideCats =
@ -185,6 +188,16 @@ QVariantList SettingManager::getVarList(
return varlist;
}
int SettingManager::scriptTimeout() const { return m_scriptTimeout; }
void SettingManager::setScriptTimeout(int newScriptTimeout) {
newScriptTimeout = qBound(0, newScriptTimeout, 312480);
if (m_scriptTimeout != newScriptTimeout) {
m_scriptTimeout = newScriptTimeout;
_setUnsaved.setFlag(SETTING_ITEM::SCRIPT_TIMEOUT);
}
}
qsizetype SettingManager::logCount() const { return m_logCount; }
void SettingManager::setLogCount(qsizetype newLogCount) {
@ -392,6 +405,7 @@ void SettingManager::save(SETTINGS cat) {
}
if (cat.testFlag(SETTING::SCRIPT)) {
WRITE_CONFIG_SET(SCRIPT_ENABLE, m_scriptEnabled);
WRITE_CONFIG_SET(SCRIPT_TIMEOUT, m_scriptTimeout);
WRITE_CONFIG_SET(SCRIPT_ALLOW_USRSCRIPT_INROOT, m_allowUsrScriptInRoot);
WRITE_CONFIG_SET(SCRIPT_USRHIDECATS, m_usrHideCats);
WRITE_CONFIG_SET(SCRIPT_SYSHIDECATS, m_sysHideCats);
@ -432,6 +446,7 @@ void SettingManager::reset(SETTINGS cat) {
}
if (cat.testFlag(SETTING::SCRIPT)) {
WRITE_CONFIG_SET(SCRIPT_ENABLE, true);
WRITE_CONFIG_SET(SCRIPT_TIMEOUT, 10);
WRITE_CONFIG_SET(SCRIPT_ALLOW_USRSCRIPT_INROOT, false);
WRITE_CONFIG_SET(SCRIPT_USRHIDECATS, QStringList());
WRITE_CONFIG_SET(SCRIPT_SYSHIDECATS, QStringList());

View File

@ -59,7 +59,7 @@ private:
EDITOR_SHOW_ADDR = 1u << 11,
EDITOR_SHOW_COL = 1u << 12,
EDITOR_SHOW_TEXT = 1u << 13,
// EDITOR_ENCODING = 1u << 14, // Reserved
SCRIPT_TIMEOUT = 1u << 14,
EDITOR_FIND_MAXCOUNT = 1u << 15,
EDITOR_COPY_LIMIT = 1u << 16,
EDITOR_DECSTRLIMIT = 1u << 17,
@ -172,6 +172,9 @@ public:
qsizetype logCount() const;
void setLogCount(qsizetype newLogCount);
int scriptTimeout() const;
void setScriptTimeout(int newScriptTimeout);
public:
void checkWriteableAndWarn();
@ -229,6 +232,8 @@ private:
int m_logLevel = 0;
qsizetype m_logCount = 20;
int m_scriptTimeout = 60; // min
private:
QFont _defaultFont;
SETTING_ITEMS _setUnsaved;

View File

@ -1899,20 +1899,43 @@ bool WingAngelAPI::execScriptCode(const WingHex::SenderInfo &sender,
bool WingAngelAPI::execScript(const WingHex::SenderInfo &sender,
const QString &fileName) {
auto handles = _handles;
auto ret = ScriptMachine::instance().executeScript(
ScriptMachine::Background, fileName);
cleanUpHandles(handles);
return ret;
auto exec = [this, fileName]() -> bool {
auto handles = _handles;
auto ret = ScriptMachine::instance().executeScript(
ScriptMachine::Background, fileName);
cleanUpHandles(handles);
return ret;
};
if (QThread::currentThread() != qApp->thread()) {
bool ret = false;
QMetaObject::invokeMethod(qApp, exec, Qt::BlockingQueuedConnection,
&ret);
return ret;
} else {
return exec();
}
}
bool WingAngelAPI::execCode(const WingHex::SenderInfo &sender,
const QString &code) {
auto handles = _handles;
auto ret =
ScriptMachine::instance().executeCode(ScriptMachine::Background, code);
cleanUpHandles(handles);
return ret;
auto exec = [this, code]() -> bool {
auto handles = _handles;
auto ret = ScriptMachine::instance().executeCode(
ScriptMachine::Background, code);
cleanUpHandles(handles);
return ret;
};
if (QThread::currentThread() != qApp->thread()) {
bool ret = false;
QMetaObject::invokeMethod(qApp, exec, Qt::BlockingQueuedConnection,
&ret);
return ret;
} else {
return exec();
}
}
QVector<void *> WingAngelAPI::retriveAsCArray(const WingHex::SenderInfo &sender,

View File

@ -36,6 +36,7 @@ GotoLineWidget::GotoLineWidget(QWidget *parent)
m_sbline = new QSpinBox(this);
m_sbline->setRange(1, 1);
m_sbline->setContextMenuPolicy(Qt::NoContextMenu);
m_sbline->setMinimumWidth(120);
connect(m_sbline, &QSpinBox::valueChanged, this,
&GotoLineWidget::onGotoLine);

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<width>412</width>
<height>50</height>
</rect>
</property>
@ -44,7 +44,7 @@
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -60,7 +60,7 @@
<string>GoTo:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<set>Qt::AlignmentFlag::AlignCenter</set>
</property>
</widget>
</item>
@ -78,6 +78,9 @@
<height>16777215</height>
</size>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ContextMenuPolicy::NoContextMenu</enum>
</property>
</widget>
</item>
<item>

View File

@ -255,32 +255,28 @@ void ScriptingConsole::runConsoleCommand(const QString &code) {
auto &ins = ScriptMachine::instance();
auto mod = ins.module(ScriptMachine::Interactive);
if (mod) {
QList<QPair<QByteArray, QByteArray>> vars;
auto total = mod->GetGlobalVarCount();
// generate codes to print
QString codes;
setMode(Output);
if (total == 0) {
codes = QStringLiteral("print(\"<none>\");");
stdOut("<none>");
} else {
auto &sm = ScriptMachine::instance();
for (asUINT i = 0; i < total; ++i) {
const char *name;
int typeId;
int typeID;
auto decl = mod->GetGlobalVarDeclaration(i);
if (decl && mod->GetGlobalVar(i, &name) == asSUCCESS) {
vars.emplaceBack(decl, name);
if (decl && mod->GetGlobalVar(i, &name, nullptr, &typeID) ==
asSUCCESS) {
auto value = sm.debugger()->toString(
mod->GetAddressOfGlobalVar(i), typeID, sm.engine(),
1);
stdOut(decl + QStringLiteral(" = ") + value);
}
}
for (auto &var : vars) {
codes.append("print(\"" + var.first + " = \");print(" +
var.second + ");print(\";\\n\");");
}
}
setMode(Output);
ScriptMachine::instance().executeCode(ScriptMachine::Interactive,
codes);
_codes.clear();
appendCommandPrompt();
setMode(Input);
@ -329,11 +325,13 @@ void ScriptingConsole::runConsoleCommand(const QString &code) {
auto mod = ins.module(ScriptMachine::Interactive);
if (mod) {
auto total = mod->GetGlobalVarCount();
asUINT i = total;
do {
--i;
mod->RemoveGlobalVar(i);
} while (i);
if (total) {
asUINT i = total;
do {
--i;
mod->RemoveGlobalVar(i);
} while (i);
}
}
_codes.clear();
appendCommandPrompt();

View File

@ -16,6 +16,7 @@
*/
#include "scriptqstring.h"
#include "AngelScript/sdk/add_on/autowrapper/aswrappedcall.h"
#include "AngelScript/sdk/add_on/scriptarray/scriptarray.h"
#include "angelscript.h"
#include "class/angelscripthelper.h"
@ -141,7 +142,7 @@ public:
}
};
static CQStringFactoryCleaner cleaner;
Q_GLOBAL_STATIC(CQStringFactoryCleaner, cleaner)
static void ConstructString(QString *thisPointer) {
new (thisPointer) QString();
@ -271,7 +272,7 @@ static char *StringCharAt(unsigned int i, QString &str) {
ctx->SetException("Out of range");
// Return a null pointer
return 0;
return nullptr;
}
return reinterpret_cast<char *>(str.data() + i);
@ -477,7 +478,19 @@ static CScriptArray *stringSplit(const QString &sep, bool skipEmpty,
//=================================================
static void ConstructChar(QString *thisPointer) { new (thisPointer) QString(); }
static void ConstructChar(QChar *thisPointer) { new (thisPointer) QChar(); }
static void ConstructCharInt(int v, QChar *thisPointer) {
new (thisPointer) QChar(v);
}
static void ConstructCharString(QString *v, QChar *thisPointer) {
if (v->isEmpty()) {
new (thisPointer) QChar();
} else {
new (thisPointer) QChar(v->at(0));
}
}
static void CopyConstructChar(const QChar &other, QChar *thisPointer) {
new (thisPointer) QChar(other);
@ -496,37 +509,49 @@ void RegisterQString_Native(asIScriptEngine *engine) {
asOBJ_VALUE | asOBJ_APP_CLASS_ALLINTS |
asGetTypeTraits<QChar>());
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("char", asBEHAVE_CONSTRUCT, "void f()",
asFUNCTION(ConstructChar),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour(
"char", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(ConstructCharInt),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour(
"char", asBEHAVE_CONSTRUCT, "void f(const char &in)",
asFUNCTION(CopyConstructChar), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("char", asBEHAVE_DESTRUCT, "void f()",
asFUNCTION(DestructChar),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
r = engine->RegisterObjectMethod(
"char", "int16 unicode() const",
asMETHODPR(QChar, unicode, () const, ushort), asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#else
r = engine->RegisterObjectMethod(
"char", "int16 unicode() const",
asMETHODPR(QChar, unicode, () const, char16_t), asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#endif
r = engine->RegisterObjectMethod(
"char", "char &opAssign(const char &in)",
asMETHODPR(QChar, operator=, (const QChar &), QChar &),
asCALL_THISCALL);
Q_UNUSED(r);
Q_ASSERT(r >= 0);
// Register the string type
@ -536,39 +561,53 @@ void RegisterQString_Native(asIScriptEngine *engine) {
r = engine->RegisterObjectType("string", sizeof(QString),
asOBJ_VALUE | asGetTypeTraits<QString>());
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#else
r = engine->RegisterObjectType("string", sizeof(QString),
asOBJ_VALUE | asOBJ_APP_CLASS_CDAK);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#endif
r = engine->RegisterObjectBehaviour(
"char", asBEHAVE_CONSTRUCT, "void f(const string &in)",
asFUNCTION(ConstructCharString), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterStringFactory("string", GetQStringFactorySingleton());
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// Register the object operator overloads
r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT,
"void f()", asFUNCTION(ConstructString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour(
"string", asBEHAVE_CONSTRUCT, "void f(const string &in)",
asFUNCTION(CopyConstructString), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()",
asFUNCTION(DestructString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "string &opAssign(const string &in)",
asMETHODPR(QString, operator=, (const QString &), QString &),
asCALL_THISCALL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM,
// otherwise the linker fails
r = engine->RegisterObjectMethod(
"string", "string &opAddAssign(const string &in)",
asFUNCTION(AddAssignStringToString), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// r = engine->RegisterObjectMethod("string", "string &opAddAssign(const
// string &in)", asMETHODPR(string, operator+=, (const string&), string&),
// asCALL_THISCALL); Q_ASSERT( r >= 0 );
@ -579,10 +618,12 @@ void RegisterQString_Native(asIScriptEngine *engine) {
asFUNCTIONPR(StringEquals, (const QString &, const QString &), bool),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "int opCmp(const string &in) const", asFUNCTION(StringCmp),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
r = engine->RegisterObjectMethod(
@ -590,6 +631,7 @@ void RegisterQString_Native(asIScriptEngine *engine) {
asFUNCTIONPR(operator+, (const QString &, const QString &), QString),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#else
r = engine->RegisterObjectMethod(
"string", "string opAdd(const string &in) const",
@ -597,6 +639,7 @@ void RegisterQString_Native(asIScriptEngine *engine) {
const QString),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#endif
// The string length can be accessed through methods or through virtual
@ -606,11 +649,13 @@ void RegisterQString_Native(asIScriptEngine *engine) {
asFUNCTION(StringLength),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#endif
r = engine->RegisterObjectMethod("string", "void resize(uint)",
asFUNCTION(StringResize),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#if AS_USE_ACCESSORS == 1
// Don't register these if STL names is used, as they conflict with the
// method size()
@ -618,10 +663,12 @@ void RegisterQString_Native(asIScriptEngine *engine) {
"string", "uint get_length() const property", asFUNCTION(StringLength),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "void set_length(uint) property",
asFUNCTION(StringResize),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#endif
// Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM,
// otherwise the linker fails
@ -631,6 +678,7 @@ void RegisterQString_Native(asIScriptEngine *engine) {
asFUNCTION(StringIsEmpty),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// Register the index operator, both as a mutator and as an inspector
// Note that we don't register the operator[] directly, as it doesn't do
@ -639,10 +687,12 @@ void RegisterQString_Native(asIScriptEngine *engine) {
asFUNCTION(StringCharAt),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "const char &opIndex(uint) const", asFUNCTION(StringCharAt),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#if AS_NO_IMPL_OPS_WITH_STRING_AND_PRIMITIVE == 0
// Automatic conversion from values
@ -650,86 +700,106 @@ void RegisterQString_Native(asIScriptEngine *engine) {
asFUNCTION(AssignDoubleToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)",
asFUNCTION(AddAssignDoubleToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(double) const",
asFUNCTION(AddStringDouble),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const",
asFUNCTION(AddDoubleString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAssign(float)",
asFUNCTION(AssignFloatToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)",
asFUNCTION(AddAssignFloatToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(float) const",
asFUNCTION(AddStringFloat),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const",
asFUNCTION(AddFloatString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAssign(int64)",
asFUNCTION(AssignInt64ToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)",
asFUNCTION(AddAssignInt64ToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(int64) const",
asFUNCTION(AddStringInt64),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const",
asFUNCTION(AddInt64String),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)",
asFUNCTION(AssignUInt64ToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)",
asFUNCTION(AddAssignUInt64ToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const",
asFUNCTION(AddStringUInt64),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const",
asFUNCTION(AddUInt64String),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAssign(bool)",
asFUNCTION(AssignBoolToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)",
asFUNCTION(AddAssignBoolToString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(bool) const",
asFUNCTION(AddStringBool),
asCALL_CDECL_OBJFIRST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const",
asFUNCTION(AddBoolString),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#endif
// Utilities
@ -737,46 +807,28 @@ void RegisterQString_Native(asIScriptEngine *engine) {
"string", "string substr(uint start = 0, int count = -1) const",
asFUNCTION(StringSubString), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "int findFirst(const string &in, uint start = 0) const",
asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "int findFirstOf(const string &in, uint start = 0) const",
asFUNCTION(StringFindFirstOf), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "void insert(uint pos, const string &in other)",
asFUNCTION(StringInsert), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "void erase(uint pos, int count = -1)",
asFUNCTION(StringErase), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
#if AS_USE_STLNAMES == 1
// Same as length
r = engine->RegisterObjectMethod("string", "uint size() const",
asFUNCTION(StringLength),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
// Same as isEmpty
r = engine->RegisterObjectMethod("string", "bool empty() const",
asFUNCTION(StringIsEmpty),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
// Same as findFirst
r = engine->RegisterObjectMethod(
"string", "int find(const string &in, uint start = 0) const",
asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
// Same as findLast
r = engine->RegisterObjectMethod(
"string", "int rfind(const string &in, int start = -1) const",
asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
#endif
Q_UNUSED(r);
/* These following things are not avaliable for generic call
* because it needs a lot of wrapper to do
@ -789,72 +841,87 @@ void RegisterQString_Native(asIScriptEngine *engine) {
"int compare(const string &in val, bool caseSensitive = true) const",
asFUNCTION(stringCompare), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"bool contains(const string &in val, bool caseSensitive = true) const",
asFUNCTION(stringContains), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"bool endsWith(const string &in val, bool caseSensitive = true) const",
asFUNCTION(stringEndsWith), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "string repeated(" QSIZETYPE " times)",
asFUNCTION(stringRepeated), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"string replace(const string &in before,const string &in after, "
"bool caseSensitive = true)",
asFUNCTION(stringReplace), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string simplified()",
asFUNCTION(stringSimplified),
asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"bool startsWith(const string &in, bool caseSensitive = true)",
asFUNCTION(stringStartsWith), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"array<string>@ split(const string &in, bool skipEmpty = false, "
"bool caseSensitive = true)",
asFUNCTION(stringSplit), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->SetDefaultNamespace("string");
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatInt(int64 val, const string &in options = \"\", uint "
"width = 0)",
asFUNCTION(formatInt), asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatUInt(uint64 val, const string &in options = \"\", uint "
"width = 0)",
asFUNCTION(formatUInt), asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatFloat(double val, const string &in options = \"\", uint "
"width = 0, uint precision = 0)",
asFUNCTION(formatFloat), asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint "
"base = 10, uint &out byteCount = 0)",
asFUNCTION(parseInt), asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"uint64 parseUInt(const string &in, uint base = 10, uint &out "
"byteCount = 0)",
asFUNCTION(parseUInt), asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"double parseFloat(const string &in, uint &out byteCount = 0)",
asFUNCTION(parseFloat), asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
engine->SetDefaultNamespace("");
}
@ -1179,49 +1246,58 @@ void RegisterQString_Generic(asIScriptEngine *engine) {
// QChar is wrapper of uint16 so...
r = engine->RegisterTypedef("char", "uint16");
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// Register the string type
r = engine->RegisterObjectType("string", sizeof(QString),
asOBJ_VALUE | asOBJ_APP_CLASS_CDAK);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterStringFactory("string", GetQStringFactorySingleton());
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// Register the object operator overloads
r = engine->RegisterObjectBehaviour(
"string", asBEHAVE_CONSTRUCT, "void f()",
asFUNCTION(ConstructStringGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour(
"string", asBEHAVE_CONSTRUCT, "void f(const string &in)",
asFUNCTION(CopyConstructStringGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()",
asFUNCTION(DestructStringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "string &opAssign(const string &in)",
asFUNCTION(AssignStringGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "string &opAddAssign(const string &in)",
asFUNCTION(AddAssignStringGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "bool opEquals(const string &in) const",
asFUNCTION(StringEqualsGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "int opCmp(const string &in) const",
asFUNCTION(StringCmpGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "string opAdd(const string &in) const",
asFUNCTION(StringAddGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// Register the object methods
#if AS_USE_ACCESSORS != 1
@ -1229,35 +1305,31 @@ void RegisterQString_Generic(asIScriptEngine *engine) {
asFUNCTION(StringLengthGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#endif
r = engine->RegisterObjectMethod("string", "void resize(uint)",
asFUNCTION(StringResizeGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1
r = engine->RegisterObjectMethod(
"string", "uint get_length() const property",
asFUNCTION(StringLengthGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
r = engine->RegisterObjectMethod("string", "void set_length(uint) property",
asFUNCTION(StringResizeGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
#endif
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "bool isEmpty() const",
asFUNCTION(StringIsEmptyGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
// Register the index operator, both as a mutator and as an inspector
r = engine->RegisterObjectMethod("string", "char &opIndex(uint)",
asFUNCTION(StringCharAtGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "const char &opIndex(uint) const",
asFUNCTION(StringCharAtGeneric), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#if AS_NO_IMPL_OPS_WITH_STRING_AND_PRIMITIVE == 0
// Automatic conversion from values
@ -1265,139 +1337,257 @@ void RegisterQString_Generic(asIScriptEngine *engine) {
asFUNCTION(AssignDouble2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)",
asFUNCTION(AddAssignDouble2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(double) const",
asFUNCTION(AddString2DoubleGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const",
asFUNCTION(AddDouble2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAssign(float)",
asFUNCTION(AssignFloat2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)",
asFUNCTION(AddAssignFloat2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(float) const",
asFUNCTION(AddString2FloatGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const",
asFUNCTION(AddFloat2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAssign(int64)",
asFUNCTION(AssignInt2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)",
asFUNCTION(AddAssignInt2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(int64) const",
asFUNCTION(AddString2IntGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const",
asFUNCTION(AddInt2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)",
asFUNCTION(AssignUInt2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)",
asFUNCTION(AddAssignUInt2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const",
asFUNCTION(AddString2UIntGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const",
asFUNCTION(AddUInt2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAssign(bool)",
asFUNCTION(AssignBool2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)",
asFUNCTION(AddAssignBool2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd(bool) const",
asFUNCTION(AddString2BoolGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const",
asFUNCTION(AddBool2StringGeneric),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
#endif
r = engine->RegisterObjectMethod(
"string", "string substr(uint start = 0, int count = -1) const",
asFUNCTION(StringSubString_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "int findFirst(const string &in, uint start = 0) const",
asFUNCTION(StringFindFirst_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "int findFirstOf(const string &in, uint start = 0) const",
asFUNCTION(StringFindFirstOf_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "int findLastOf(const string &in, int start = -1) const",
asFUNCTION(StringFindLastOf_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "void insert(uint pos, const string &in other)",
asFUNCTION(StringInsert_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "void erase(uint pos, int count = -1)",
asFUNCTION(StringErase_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatInt(int64 val, const string &in options = \"\")",
asFUNCTION(formatInt_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatUInt(uint64 val, const string &in options = \"\")",
asFUNCTION(formatUInt_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatFloat(double val, const string &in options = \"\")",
asFUNCTION(formatFloat_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint "
"base = 10, bool &out ok = false)",
asFUNCTION(parseInt_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, "
"uint base = 10, bool &out ok = false)",
asFUNCTION(parseUInt_Generic),
asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"double parseFloat(const string &in, bool &out ok = false)",
asFUNCTION(parseFloat_Generic), asCALL_GENERIC);
WRAP_FN(parseFloat_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"int compare(const string &in val, bool caseSensitive = true) const",
WRAP_FN(stringCompare), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"bool contains(const string &in val, bool caseSensitive = true) const",
WRAP_FN(stringContains), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"bool endsWith(const string &in val, bool caseSensitive = true) const",
WRAP_FN(stringEndsWith), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string",
"string repeated(" QSIZETYPE " times)",
WRAP_FN(stringRepeated), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"string replace(const string &in before,const string &in after, "
"bool caseSensitive = true)",
WRAP_FN(stringReplace), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod("string", "string simplified()",
WRAP_FN(stringSimplified), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"bool startsWith(const string &in, bool caseSensitive = true)",
WRAP_FN(stringStartsWith), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"array<string>@ split(const string &in, bool skipEmpty = false, "
"bool caseSensitive = true)",
WRAP_FN(stringSplit), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->SetDefaultNamespace("string");
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatInt(int64 val, const string &in options = \"\", uint "
"width = 0)",
WRAP_FN(formatInt), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatUInt(uint64 val, const string &in options = \"\", uint "
"width = 0)",
WRAP_FN(formatUInt), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"string formatFloat(double val, const string &in options = \"\", uint "
"width = 0, uint precision = 0)",
WRAP_FN(formatFloat), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint "
"base = 10, uint &out byteCount = 0)",
WRAP_FN(parseInt), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"uint64 parseUInt(const string &in, uint base = 10, uint &out "
"byteCount = 0)",
WRAP_FN(parseUInt), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"double parseFloat(const string &in, uint &out byteCount = 0)",
WRAP_FN(parseFloat), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
}
void RegisterQString(asIScriptEngine *engine) {
@ -1457,28 +1647,32 @@ static int StringCompare(const QString &s1, const QString &s2,
void RegisterQStringUtils(asIScriptEngine *engine) {
int r = engine->SetDefaultNamespace("string");
Q_ASSERT(r >= 0);
Q_UNUSED(r);
if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) {
r = engine->RegisterGlobalFunction(
"string join(const array<string> &in, const string &in)",
asFUNCTION(StringJoin_Generic), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterGlobalFunction(
"int compare(const string &in, const string &in, bool = true)",
WRAP_FN(StringCompare), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
} else {
r = engine->RegisterGlobalFunction(
"string join(const array<string> &in, const string &in)",
asFUNCTION(StringJoin), asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
/* These following things are not avaliable for generic call
* because it needs a lot of wrapper to do
* while WingHexExplorer only needs native call
* (by wingsummer)
* PULL REQUESTS ARE WELCOMED IF YOU WANT TO ADD GENERIC CALL
*/
r = engine->RegisterGlobalFunction(
"int compare(const string &in, const string &in, bool = true)",
asFUNCTION(StringCompare), asCALL_CDECL);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
}
engine->SetDefaultNamespace("");
}
@ -1540,49 +1734,77 @@ static CScriptArray *stringSplitReg(const QRegularExpression &exp,
}
void RegisterQStringRegExSupport(asIScriptEngine *engine) {
Q_ASSERT(engine->GetTypeInfoByName("regex::exp"));
int r = engine->SetDefaultNamespace("string");
Q_ASSERT(r >= 0);
Q_UNUSED(r);
if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) {
Q_UNIMPLEMENTED();
} else {
/* These following things are not avaliable for generic call
* because it needs a lot of wrapper to do
* while WingHexExplorer only needs native call
* (by wingsummer)
* PULL REQUESTS ARE WELCOMED IF YOU WANT TO ADD GENERIC CALL
*/
Q_ASSERT(engine->GetTypeInfoByName("regex::exp"));
int r = engine->SetDefaultNamespace("string");
r = engine->RegisterObjectMethod(
"string",
"int findFirst(const regex::exp &in, uint start = 0) const",
WRAP_FN(StringFindFirstReg), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"int findFirstOf(const regex::exp &in, uint start = 0) const",
WRAP_FN(StringFindFirstOfReg), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"int findLastOf(const regex::exp &in, int start = -1) const",
WRAP_FN(StringFindLastOfReg), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "bool contains(const regex::exp &in) const",
WRAP_FN(stringContainsReg), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"array<string>@ split(const regex::exp &in, "
"bool skipEmpty = false)",
WRAP_FN(stringSplitReg), asCALL_GENERIC);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
} else {
r = engine->RegisterObjectMethod(
"string",
"int findFirst(const regex::exp &in, uint start = 0) const",
asFUNCTION(StringFindFirstReg), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"int findFirstOf(const regex::exp &in, uint start = 0) const",
asFUNCTION(StringFindFirstOfReg), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"int findLastOf(const regex::exp &in, int start = -1) const",
asFUNCTION(StringFindLastOfReg), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string", "bool contains(const regex::exp &in) const",
asFUNCTION(stringContainsReg), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
Q_UNUSED(r);
r = engine->RegisterObjectMethod(
"string",
"array<string>@ split(const regex::exp &in, "
"bool skipEmpty = false)",
asFUNCTION(stringSplitReg), asCALL_CDECL_OBJLAST);
Q_ASSERT(r >= 0);
engine->SetDefaultNamespace("");
Q_UNUSED(r);
}
engine->SetDefaultNamespace("");
}
END_AS_NAMESPACE

View File

@ -48,6 +48,7 @@ void ScriptSettingDialog::loadData() {
this->blockSignals(true);
ui->cbEnable->setChecked(set.scriptEnabled());
ui->cbAllowUsrScript->setChecked(set.allowUsrScriptInRoot());
ui->sbTimeout->setValue(set.scriptTimeout());
this->blockSignals(false);
if (set.scriptEnabled()) {
@ -112,6 +113,7 @@ void ScriptSettingDialog::apply() {
auto &set = SettingManager::instance();
set.setScriptEnabled(ui->cbEnable->isChecked());
set.setAllowUsrScriptInRoot(ui->cbAllowUsrScript->isChecked());
set.setScriptTimeout(ui->sbTimeout->value());
set.setUsrHideCats(usrHideCats);
set.setSysHideCats(sysHideCats);
set.save(SettingManager::SCRIPT);

View File

@ -40,6 +40,63 @@
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>8</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="lblTimeout">
<property name="text">
<string>Timeout</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbTimeout">
<property name="suffix">
<string notr="true"> min</string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>312480</number>
</property>
<property name="value">
<number>10</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
@ -52,7 +109,7 @@
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<widget class="QListWidget" name="listWidget"/>
<widget class="QWidget" name="layoutWidget">